diff --git a/AUTHORS b/AUTHORS
index 7ad2718..a933b97 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -755,6 +755,7 @@
 Cathie Chen <cathiechen@tencent.com>
 Kyle Plumadore <kyle.plumadore@amd.com>
 Sunchang Li <johnstonli@tencent.com>
+Yeol Park <peary2@gmail.com>
 
 BlackBerry Limited <*@blackberry.com>
 Code Aurora Forum <*@codeaurora.org>
diff --git a/BUILD.gn b/BUILD.gn
index 73c12e9..87a552d 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -907,7 +907,7 @@
         "//breakpad:minidump_dump",
         "//breakpad:minidump_stackwalk",
         "//breakpad:symupload",
-        "//tools/android/forwarder",
+        "//tools/android/forwarder2",
       ]
     }
 
diff --git a/DEPS b/DEPS
index 182078d..da8c07b 100644
--- a/DEPS
+++ b/DEPS
@@ -39,7 +39,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling Skia
   # and whatever else without interference from each other.
-  'skia_revision': 'c4cbd74a38232a0e9f1cc1cc8fb826bb06c577a9',
+  'skia_revision': '47bf4c0009f1f2c86e831447e69475e50cbfc958',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
@@ -55,7 +55,7 @@
   # 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.
-  'buildtools_revision': '86f7e41d9424b9d8faf66c601b129855217f9a08',
+  'buildtools_revision': '5fd66957f08bb752dca714a591c84587c9d70762',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling SwiftShader
   # and whatever else without interference from each other.
@@ -99,7 +99,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling libFuzzer
   # and whatever else without interference from each other.
-  'libfuzzer_revision': 'eb9b8b0366f34b53cd2ffde6837f037728aa5e9c',
+  'libfuzzer_revision': 'ad607143eab09705a9e96324d040b5768f35081d',
 }
 
 # Only these hosts are allowed for dependencies in this DEPS file.
@@ -1018,6 +1018,8 @@
 ]
 
 recursedeps = [
+  # buildtools provides clang_format, libc++, and libc++abi
+  'src/buildtools',
   # android_tools manages the NDK.
   'src/third_party/android_tools',
   # ANGLE manages DEPS that it also owns the build files for, such as dEQP.
diff --git a/android_webview/BUILD.gn b/android_webview/BUILD.gn
index 3ef9827..e092d23a 100644
--- a/android_webview/BUILD.gn
+++ b/android_webview/BUILD.gn
@@ -54,61 +54,10 @@
 }
 
 locale_pak_resources("locale_paks") {
-  sources = [
-    "$root_out_dir/android_webview/locales/am.pak",
-    "$root_out_dir/android_webview/locales/ar.pak",
-    "$root_out_dir/android_webview/locales/bg.pak",
-    "$root_out_dir/android_webview/locales/bn.pak",
-    "$root_out_dir/android_webview/locales/ca.pak",
-    "$root_out_dir/android_webview/locales/cs.pak",
-    "$root_out_dir/android_webview/locales/da.pak",
-    "$root_out_dir/android_webview/locales/de.pak",
-    "$root_out_dir/android_webview/locales/el.pak",
-    "$root_out_dir/android_webview/locales/en-GB.pak",
-    "$root_out_dir/android_webview/locales/en-US.pak",
-    "$root_out_dir/android_webview/locales/es-419.pak",
-    "$root_out_dir/android_webview/locales/es.pak",
-    "$root_out_dir/android_webview/locales/et.pak",
-    "$root_out_dir/android_webview/locales/fa.pak",
-    "$root_out_dir/android_webview/locales/fi.pak",
-    "$root_out_dir/android_webview/locales/fil.pak",
-    "$root_out_dir/android_webview/locales/fr.pak",
-    "$root_out_dir/android_webview/locales/gu.pak",
-    "$root_out_dir/android_webview/locales/he.pak",
-    "$root_out_dir/android_webview/locales/hi.pak",
-    "$root_out_dir/android_webview/locales/hr.pak",
-    "$root_out_dir/android_webview/locales/hu.pak",
-    "$root_out_dir/android_webview/locales/id.pak",
-    "$root_out_dir/android_webview/locales/it.pak",
-    "$root_out_dir/android_webview/locales/ja.pak",
-    "$root_out_dir/android_webview/locales/kn.pak",
-    "$root_out_dir/android_webview/locales/ko.pak",
-    "$root_out_dir/android_webview/locales/lt.pak",
-    "$root_out_dir/android_webview/locales/lv.pak",
-    "$root_out_dir/android_webview/locales/ml.pak",
-    "$root_out_dir/android_webview/locales/mr.pak",
-    "$root_out_dir/android_webview/locales/ms.pak",
-    "$root_out_dir/android_webview/locales/nb.pak",
-    "$root_out_dir/android_webview/locales/nl.pak",
-    "$root_out_dir/android_webview/locales/pl.pak",
-    "$root_out_dir/android_webview/locales/pt-BR.pak",
-    "$root_out_dir/android_webview/locales/pt-PT.pak",
-    "$root_out_dir/android_webview/locales/ro.pak",
-    "$root_out_dir/android_webview/locales/ru.pak",
-    "$root_out_dir/android_webview/locales/sk.pak",
-    "$root_out_dir/android_webview/locales/sl.pak",
-    "$root_out_dir/android_webview/locales/sr.pak",
-    "$root_out_dir/android_webview/locales/sv.pak",
-    "$root_out_dir/android_webview/locales/sw.pak",
-    "$root_out_dir/android_webview/locales/ta.pak",
-    "$root_out_dir/android_webview/locales/te.pak",
-    "$root_out_dir/android_webview/locales/th.pak",
-    "$root_out_dir/android_webview/locales/tr.pak",
-    "$root_out_dir/android_webview/locales/uk.pak",
-    "$root_out_dir/android_webview/locales/vi.pak",
-    "$root_out_dir/android_webview/locales/zh-CN.pak",
-    "$root_out_dir/android_webview/locales/zh-TW.pak",
-  ]
+  sources = []
+  foreach(_locale, locales) {
+    sources += [ "$root_out_dir/android_webview/locales/$_locale.pak" ]
+  }
   deps = [
     ":repack_locales",
   ]
@@ -232,60 +181,10 @@
   source = "ui/aw_strings.grd"
   outputs = [
     "grit/aw_strings.h",
-    "aw_strings_am.pak",
-    "aw_strings_ar.pak",
-    "aw_strings_bg.pak",
-    "aw_strings_bn.pak",
-    "aw_strings_ca.pak",
-    "aw_strings_cs.pak",
-    "aw_strings_da.pak",
-    "aw_strings_de.pak",
-    "aw_strings_el.pak",
-    "aw_strings_en-US.pak",
-    "aw_strings_en-GB.pak",
-    "aw_strings_es.pak",
-    "aw_strings_es-419.pak",
-    "aw_strings_et.pak",
-    "aw_strings_fa.pak",
-    "aw_strings_fi.pak",
-    "aw_strings_fil.pak",
-    "aw_strings_fr.pak",
-    "aw_strings_gu.pak",
-    "aw_strings_he.pak",
-    "aw_strings_hi.pak",
-    "aw_strings_hr.pak",
-    "aw_strings_hu.pak",
-    "aw_strings_id.pak",
-    "aw_strings_it.pak",
-    "aw_strings_ja.pak",
-    "aw_strings_kn.pak",
-    "aw_strings_ko.pak",
-    "aw_strings_lt.pak",
-    "aw_strings_lv.pak",
-    "aw_strings_ml.pak",
-    "aw_strings_mr.pak",
-    "aw_strings_ms.pak",
-    "aw_strings_nl.pak",
-    "aw_strings_nb.pak",
-    "aw_strings_pl.pak",
-    "aw_strings_pt-BR.pak",
-    "aw_strings_pt-PT.pak",
-    "aw_strings_ro.pak",
-    "aw_strings_ru.pak",
-    "aw_strings_sk.pak",
-    "aw_strings_sl.pak",
-    "aw_strings_sr.pak",
-    "aw_strings_sv.pak",
-    "aw_strings_sw.pak",
-    "aw_strings_ta.pak",
-    "aw_strings_te.pak",
-    "aw_strings_th.pak",
-    "aw_strings_tr.pak",
-    "aw_strings_uk.pak",
-    "aw_strings_vi.pak",
-    "aw_strings_zh-CN.pak",
-    "aw_strings_zh-TW.pak",
   ]
+  foreach(_locale, locales) {
+    outputs += [ "aw_strings_${_locale}.pak" ]
+  }
 }
 
 grit("generate_components_strings") {
@@ -305,60 +204,6 @@
   ]
   outputs = [
     "grit/components_strings.h",
-    "components_strings_am.pak",
-    "components_strings_ar.pak",
-    "components_strings_bg.pak",
-    "components_strings_bn.pak",
-    "components_strings_ca.pak",
-    "components_strings_cs.pak",
-    "components_strings_da.pak",
-    "components_strings_de.pak",
-    "components_strings_el.pak",
-    "components_strings_en-GB.pak",
-    "components_strings_en-US.pak",
-    "components_strings_es.pak",
-    "components_strings_es-419.pak",
-    "components_strings_et.pak",
-    "components_strings_fa.pak",
-    "components_strings_fake-bidi.pak",
-    "components_strings_fi.pak",
-    "components_strings_fil.pak",
-    "components_strings_fr.pak",
-    "components_strings_gu.pak",
-    "components_strings_he.pak",
-    "components_strings_hi.pak",
-    "components_strings_hr.pak",
-    "components_strings_hu.pak",
-    "components_strings_id.pak",
-    "components_strings_it.pak",
-    "components_strings_ja.pak",
-    "components_strings_kn.pak",
-    "components_strings_ko.pak",
-    "components_strings_lt.pak",
-    "components_strings_lv.pak",
-    "components_strings_ml.pak",
-    "components_strings_mr.pak",
-    "components_strings_ms.pak",
-    "components_strings_nl.pak",
-    "components_strings_nb.pak",
-    "components_strings_pl.pak",
-    "components_strings_pt-BR.pak",
-    "components_strings_pt-PT.pak",
-    "components_strings_ro.pak",
-    "components_strings_ru.pak",
-    "components_strings_sk.pak",
-    "components_strings_sl.pak",
-    "components_strings_sr.pak",
-    "components_strings_sv.pak",
-    "components_strings_sw.pak",
-    "components_strings_ta.pak",
-    "components_strings_te.pak",
-    "components_strings_th.pak",
-    "components_strings_tr.pak",
-    "components_strings_uk.pak",
-    "components_strings_vi.pak",
-    "components_strings_zh-CN.pak",
-    "components_strings_zh-TW.pak",
     "java/res/values-am/components_strings.xml",
     "java/res/values-ar/components_strings.xml",
     "java/res/values-bg/components_strings.xml",
@@ -404,6 +249,9 @@
     "java/res/values-zh-rTW/components_strings.xml",
     "java/res/values/components_strings.xml",
   ]
+  foreach(_locale, locales) {
+    outputs += [ "components_strings_${_locale}.pak" ]
+  }
 }
 
 source_set("webview_entry_point") {
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
index 55a309a..fa0dc88 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.cc
@@ -269,6 +269,7 @@
     content::ResourceContext* resource_context,
     bool is_content_initiated,
     bool must_download,
+    bool is_new_request,
     ScopedVector<content::ResourceThrottle>* throttles) {
   GURL url(request->url());
   std::string user_agent;
diff --git a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
index 7bfc6ef..4731573 100644
--- a/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
+++ b/android_webview/browser/renderer_host/aw_resource_dispatcher_host_delegate.h
@@ -39,6 +39,7 @@
       content::ResourceContext* resource_context,
       bool is_content_initiated,
       bool must_download,
+      bool is_new_request,
       ScopedVector<content::ResourceThrottle>* throttles) override;
   content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
       net::AuthChallengeInfo* auth_info,
diff --git a/ash/common/wm/system_modal_container_layout_manager.cc b/ash/common/wm/system_modal_container_layout_manager.cc
index 4185abf..1a895ab 100644
--- a/ash/common/wm/system_modal_container_layout_manager.cc
+++ b/ash/common/wm/system_modal_container_layout_manager.cc
@@ -52,6 +52,21 @@
 ////////////////////////////////////////////////////////////////////////////////
 // SystemModalContainerLayoutManager, WmLayoutManager implementation:
 
+void SystemModalContainerLayoutManager::OnChildWindowVisibilityChanged(
+    WmWindow* window,
+    bool visible) {
+  if (GetModalType(window) != ui::MODAL_TYPE_SYSTEM)
+    return;
+
+  if (window->IsVisible()) {
+    DCHECK(!base::ContainsValue(modal_windows_, window));
+    AddModalWindow(window);
+  } else {
+    if (RemoveModalWindow(window))
+      WmShell::Get()->OnModalWindowRemoved(window);
+  }
+}
+
 void SystemModalContainerLayoutManager::OnWindowResized() {
   PositionDialogsAfterWorkAreaResize();
 }
@@ -110,20 +125,6 @@
   }
 }
 
-void SystemModalContainerLayoutManager::OnWindowVisibilityChanged(
-    WmWindow* window,
-    bool visible) {
-  if (GetModalType(window) != ui::MODAL_TYPE_SYSTEM)
-    return;
-
-  if (window->IsVisible()) {
-    AddModalWindow(window);
-  } else {
-    RemoveModalWindow(window);
-    WmShell::Get()->OnModalWindowRemoved(window);
-  }
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // SystemModalContainerLayoutManager, Keyboard::KeybaordControllerObserver
 // implementation:
diff --git a/ash/common/wm/system_modal_container_layout_manager.h b/ash/common/wm/system_modal_container_layout_manager.h
index 18fe75d..7bf81c8 100644
--- a/ash/common/wm/system_modal_container_layout_manager.h
+++ b/ash/common/wm/system_modal_container_layout_manager.h
@@ -36,6 +36,7 @@
   bool has_window_dimmer() const { return window_dimmer_ != nullptr; }
 
   // Overridden from WmSnapToPixelLayoutManager:
+  void OnChildWindowVisibilityChanged(WmWindow* child, bool visible) override;
   void OnWindowResized() override;
   void OnWindowAddedToLayout(WmWindow* child) override;
   void OnWillRemoveWindowFromLayout(WmWindow* child) override;
@@ -45,7 +46,6 @@
   // Overridden from WmWindowObserver:
   void OnWindowPropertyChanged(WmWindow* window,
                                WmWindowProperty property) override;
-  void OnWindowVisibilityChanged(WmWindow* window, bool visible) override;
 
   // Overridden from keyboard::KeyboardControllerObserver:
   void OnKeyboardBoundsChanging(const gfx::Rect& new_bounds) override;
diff --git a/ash/wm/system_modal_container_layout_manager_unittest.cc b/ash/wm/system_modal_container_layout_manager_unittest.cc
index 9ba6dfa..dc95fbd 100644
--- a/ash/wm/system_modal_container_layout_manager_unittest.cc
+++ b/ash/wm/system_modal_container_layout_manager_unittest.cc
@@ -784,6 +784,16 @@
   EXPECT_TRUE(WmShell::Get()->IsSystemModalWindowOpen());
   EXPECT_TRUE(layout_manager->has_window_dimmer());
 
+  // Make sure that a child visibility change should not cause
+  // inconsistent state.
+  std::unique_ptr<aura::Window> child = base::MakeUnique<aura::Window>(nullptr);
+  child->SetType(ui::wm::WINDOW_TYPE_CONTROL);
+  child->Init(ui::LAYER_TEXTURED);
+  modal_window->AddChild(child.get());
+  child->Show();
+  EXPECT_TRUE(WmShell::Get()->IsSystemModalWindowOpen());
+  EXPECT_TRUE(layout_manager->has_window_dimmer());
+
   modal_window->Hide();
   EXPECT_FALSE(WmShell::Get()->IsSystemModalWindowOpen());
   EXPECT_FALSE(layout_manager->has_window_dimmer());
diff --git a/base/files/file_path_watcher.cc b/base/files/file_path_watcher.cc
index a4624ab..e370fcb1 100644
--- a/base/files/file_path_watcher.cc
+++ b/base/files/file_path_watcher.cc
@@ -18,12 +18,6 @@
 }
 
 // static
-void FilePathWatcher::CancelWatch(
-    const scoped_refptr<PlatformDelegate>& delegate) {
-  delegate->CancelOnMessageLoopThread();
-}
-
-// static
 bool FilePathWatcher::RecursiveWatchAvailable() {
 #if (defined(OS_MACOSX) && !defined(OS_IOS)) || defined(OS_WIN) || \
     defined(OS_LINUX) || defined(OS_ANDROID)
diff --git a/base/files/file_path_watcher.h b/base/files/file_path_watcher.h
index d5c6db1ac..7b1483a 100644
--- a/base/files/file_path_watcher.h
+++ b/base/files/file_path_watcher.h
@@ -53,11 +53,6 @@
 
     virtual ~PlatformDelegate();
 
-    // Stop watching. This is only called on the thread of the appropriate
-    // message loop. Since it can also be called more than once, it should
-    // check |is_cancelled()| to avoid duplicate work.
-    virtual void CancelOnMessageLoopThread() = 0;
-
     scoped_refptr<base::SingleThreadTaskRunner> task_runner() const {
       return task_runner_;
     }
diff --git a/base/files/file_path_watcher_fsevents.h b/base/files/file_path_watcher_fsevents.h
index cfbe020b..fbcca1f8 100644
--- a/base/files/file_path_watcher_fsevents.h
+++ b/base/files/file_path_watcher_fsevents.h
@@ -54,7 +54,7 @@
                       const FilePath& resolved_target);
 
   // Cleans up and stops the event stream.
-  void CancelOnMessageLoopThread() override;
+  void CancelOnMessageLoopThread();
 
   // (Re-)Initialize the event stream to start reporting events from
   // |start_event|.
diff --git a/base/files/file_path_watcher_kqueue.h b/base/files/file_path_watcher_kqueue.h
index d9db8c2..365cac53 100644
--- a/base/files/file_path_watcher_kqueue.h
+++ b/base/files/file_path_watcher_kqueue.h
@@ -61,7 +61,7 @@
   typedef std::vector<struct kevent> EventVector;
 
   // Can only be called on |io_task_runner_|'s thread.
-  void CancelOnMessageLoopThread() override;
+  void CancelOnMessageLoopThread();
 
   // Returns true if the kevent values are error free.
   bool AreKeventValuesValid(struct kevent* kevents, int count);
diff --git a/base/files/file_path_watcher_linux.cc b/base/files/file_path_watcher_linux.cc
index 9d50169..958e60c 100644
--- a/base/files/file_path_watcher_linux.cc
+++ b/base/files/file_path_watcher_linux.cc
@@ -120,7 +120,6 @@
 
   // Cancel the watch. This unregisters the instance with InotifyReader.
   void Cancel() override;
-  void CancelOnMessageLoopThread() override;
   void CancelOnMessageLoopThreadOrInDestructor();
 
   // Inotify watches are installed for all directory components of |target_|.
@@ -329,8 +328,8 @@
     return;
   }
 
-  // Check to see if CancelOnMessageLoopThread() has already been called.
-  // May happen when code flow reaches here from the PostTask() above.
+  // Check to see if CancelOnMessageLoopThreadOrInDestructor() has already been
+  // called. May happen when code flow reaches here from the PostTask() above.
   if (watches_.empty()) {
     DCHECK(target_.empty());
     return;
@@ -445,19 +444,17 @@
     return;
   }
 
-  // Switch to the message_loop() if necessary so we can access |watches_|.
+  // Switch to the task_runner() if necessary so we can access |watches_|.
   if (!task_runner()->BelongsToCurrentThread()) {
-    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
-                                            make_scoped_refptr(this)));
+    task_runner()->PostTask(
+        FROM_HERE,
+        Bind(&FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor,
+             this));
   } else {
-    CancelOnMessageLoopThread();
+    CancelOnMessageLoopThreadOrInDestructor();
   }
 }
 
-void FilePathWatcherImpl::CancelOnMessageLoopThread() {
-  CancelOnMessageLoopThreadOrInDestructor();
-}
-
 void FilePathWatcherImpl::CancelOnMessageLoopThreadOrInDestructor() {
   DCHECK(in_destructor_ || task_runner()->BelongsToCurrentThread());
 
@@ -479,7 +476,7 @@
 }
 
 void FilePathWatcherImpl::UpdateWatches() {
-  // Ensure this runs on the message_loop() exclusively in order to avoid
+  // Ensure this runs on the task_runner() exclusively in order to avoid
   // concurrency issues.
   DCHECK(task_runner()->BelongsToCurrentThread());
   DCHECK(HasValidWatchVector());
diff --git a/base/files/file_path_watcher_mac.cc b/base/files/file_path_watcher_mac.cc
index 7338eaf..b65591a2 100644
--- a/base/files/file_path_watcher_mac.cc
+++ b/base/files/file_path_watcher_mac.cc
@@ -40,12 +40,6 @@
     set_cancelled();
   }
 
-  void CancelOnMessageLoopThread() override {
-    if (impl_.get())
-      impl_->Cancel();
-    set_cancelled();
-  }
-
  protected:
   ~FilePathWatcherImpl() override {}
 
diff --git a/base/files/file_path_watcher_stub.cc b/base/files/file_path_watcher_stub.cc
index 8138692e..c637e3c 100644
--- a/base/files/file_path_watcher_stub.cc
+++ b/base/files/file_path_watcher_stub.cc
@@ -21,8 +21,6 @@
 
   void Cancel() override {}
 
-  void CancelOnMessageLoopThread() override {}
-
  protected:
   ~FilePathWatcherImpl() override {}
 };
diff --git a/base/files/file_path_watcher_win.cc b/base/files/file_path_watcher_win.cc
index 9121fa9..3bbf2fb 100644
--- a/base/files/file_path_watcher_win.cc
+++ b/base/files/file_path_watcher_win.cc
@@ -60,7 +60,7 @@
   void DestroyWatch();
 
   // Cleans up and stops observing the |task_runner_| thread.
-  void CancelOnMessageLoopThread() override;
+  void CancelOnMessageLoopThread();
 
   // Callback to notify upon changes.
   FilePathWatcher::Callback callback_;
@@ -122,8 +122,8 @@
 
   // Switch to the file thread if necessary so we can stop |watcher_|.
   if (!task_runner()->BelongsToCurrentThread()) {
-    task_runner()->PostTask(FROM_HERE, Bind(&FilePathWatcher::CancelWatch,
-                                            make_scoped_refptr(this)));
+    task_runner()->PostTask(
+        FROM_HERE, Bind(&FilePathWatcherImpl::CancelOnMessageLoopThread, this));
   } else {
     CancelOnMessageLoopThread();
   }
diff --git a/blimp/net/BUILD.gn b/blimp/net/BUILD.gn
index 9c348825..2c6ab3a9 100644
--- a/blimp/net/BUILD.gn
+++ b/blimp/net/BUILD.gn
@@ -77,6 +77,7 @@
   defines = [ "BLIMP_NET_IMPLEMENTATION=1" ]
 
   deps = [
+    ":helium",
     "//base",
     "//blimp/common",
     "//net",
@@ -90,6 +91,21 @@
   ]
 }
 
+source_set("helium") {
+  sources = [
+    "helium/vector_clock.cc",
+    "helium/vector_clock.h",
+  ]
+  deps = [
+    "//base",
+    "//blimp/common",
+  ]
+
+  public_deps = [
+    "//blimp/common/proto",
+  ]
+}
+
 source_set("test_support") {
   testonly = true
 
@@ -134,6 +150,7 @@
     "compressed_packet_unittest.cc",
     "engine_authentication_handler_unittest.cc",
     "engine_connection_manager_unittest.cc",
+    "helium/vector_clock_unittest.cc",
     "input_message_unittest.cc",
     "ssl_client_transport_unittest.cc",
     "stream_packet_reader_unittest.cc",
@@ -143,6 +160,7 @@
   ]
 
   deps = [
+    ":helium",
     ":net",
     ":test_support",
     "//base",
diff --git a/blimp/net/helium/vector_clock.cc b/blimp/net/helium/vector_clock.cc
new file mode 100644
index 0000000..6b13d28
--- /dev/null
+++ b/blimp/net/helium/vector_clock.cc
@@ -0,0 +1,57 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "blimp/net/helium/vector_clock.h"
+
+#include <algorithm>
+
+#include "base/logging.h"
+
+namespace blimp {
+
+VectorClock::VectorClock() {}
+
+VectorClock::VectorClock(Revision local_revision, Revision remote_revision)
+    : local_revision_(local_revision), remote_revision_(remote_revision) {}
+
+VectorClock::Comparison VectorClock::CompareTo(const VectorClock& other) const {
+  DCHECK(local_revision_ >= other.local_revision());
+
+  if (local_revision_ == other.local_revision()) {
+    if (remote_revision_ == other.remote_revision()) {
+      return VectorClock::Comparison::EqualTo;
+    } else if (remote_revision_ < other.remote_revision()) {
+      return VectorClock::Comparison::LessThan;
+    } else {
+      return VectorClock::Comparison::GreaterThan;
+    }
+  } else {
+    if (local_revision_ > other.local_revision()) {
+      if (remote_revision_ == other.remote_revision()) {
+        return VectorClock::Comparison::GreaterThan;
+      } else {
+        return VectorClock::Comparison::Conflict;
+      }
+    } else {  // We know its not equal or greater, so its smaller
+      if (remote_revision_ == other.remote_revision()) {
+        return VectorClock::Comparison::LessThan;
+      } else {
+        LOG(FATAL) << "Local revision should always be greater or equal.";
+        return VectorClock::Comparison::Conflict;
+      }
+    }
+  }
+}
+
+VectorClock VectorClock::MergeWith(const VectorClock& other) const {
+  VectorClock result(std::max(local_revision_, other.local_revision()),
+                     std::max(remote_revision_, other.remote_revision()));
+  return result;
+}
+
+void VectorClock::IncrementLocal() {
+  local_revision_++;
+}
+
+}  // namespace blimp
diff --git a/blimp/net/helium/vector_clock.h b/blimp/net/helium/vector_clock.h
new file mode 100644
index 0000000..c375aac
--- /dev/null
+++ b/blimp/net/helium/vector_clock.h
@@ -0,0 +1,66 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef BLIMP_NET_HELIUM_VECTOR_CLOCK_H_
+#define BLIMP_NET_HELIUM_VECTOR_CLOCK_H_
+
+#include <stdint.h>
+
+namespace blimp {
+
+// From wikipedia:
+// A vector clock is an algorithm for generating a partial ordering of events
+// in a distributed system and detecting causality violations. This is used
+// in Blimp to allow client and server modify a local copy of an object and
+// later be able to detect ordering or conflicts if any.
+//
+// For more info see:
+// https://en.wikipedia.org/wiki/Vector_clock
+
+typedef uint32_t Revision;
+
+class VectorClock {
+ public:
+  enum class Comparison { LessThan, EqualTo, GreaterThan, Conflict };
+
+  VectorClock(Revision local_revision, Revision remote_revision);
+  VectorClock();
+
+  // Compares two vector clocks. There are 4 possibilities for the result:
+  // * LessThan: One revision is equal and for the other is smaller.
+  // (1,0).CompareTo((2, 0));
+  // * EqualTo: Both revisions are the same.
+  // * GreaterThan: One revision is equal and for the other is greater.
+  // (2,0).CompareTo((1, 0));
+  // * Conflict: Both revisions are different. (1,0).CompareTo(0,1)
+  Comparison CompareTo(const VectorClock& other) const;
+
+  // Merges two vector clocks. This function should be used at synchronization
+  // points. i.e. when client receives data from the server or vice versa.
+  VectorClock MergeWith(const VectorClock& other) const;
+
+  // Increments local_revision_ by one. This is used when something changes
+  // in the local state like setting a property or applying a change set.
+  void IncrementLocal();
+
+  Revision local_revision() const { return local_revision_; }
+
+  void set_local_revision(Revision local_revision) {
+    local_revision_ = local_revision;
+  }
+
+  Revision remote_revision() const { return remote_revision_; }
+
+  void set_remote_revision(Revision remote_revision) {
+    remote_revision_ = remote_revision;
+  }
+
+ private:
+  Revision local_revision_ = 0;
+  Revision remote_revision_ = 0;
+};
+
+}  // namespace blimp
+
+#endif  // BLIMP_NET_HELIUM_VECTOR_CLOCK_H_
diff --git a/blimp/net/helium/vector_clock_unittest.cc b/blimp/net/helium/vector_clock_unittest.cc
new file mode 100644
index 0000000..2bd258e
--- /dev/null
+++ b/blimp/net/helium/vector_clock_unittest.cc
@@ -0,0 +1,140 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "blimp/net/helium/vector_clock.h"
+
+#include "base/macros.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blimp {
+namespace {
+
+class VectorClockComparisonTest
+    : public ::testing::TestWithParam<
+          std::tuple<VectorClock, VectorClock, VectorClock::Comparison>> {
+ public:
+  VectorClockComparisonTest() {}
+  ~VectorClockComparisonTest() override {}
+};
+
+TEST_P(VectorClockComparisonTest, CompareTo) {
+  auto param = GetParam();
+  VectorClock v1 = std::get<0>(param);
+  VectorClock v2 = std::get<1>(param);
+  VectorClock::Comparison expected = std::get<2>(param);
+  EXPECT_EQ(expected, v1.CompareTo(v2));
+}
+
+INSTANTIATE_TEST_CASE_P(
+    LessThan,
+    VectorClockComparisonTest,
+    ::testing::Values(std::make_tuple(VectorClock(1, 2),
+                                      VectorClock(1, 3),
+                                      VectorClock::Comparison::LessThan)));
+
+INSTANTIATE_TEST_CASE_P(
+    GreaterThan,
+    VectorClockComparisonTest,
+    ::testing::Values(std::make_tuple(VectorClock(1, 3),
+                                      VectorClock(1, 2),
+                                      VectorClock::Comparison::GreaterThan),
+                      std::make_tuple(VectorClock(2, 2),
+                                      VectorClock(1, 2),
+                                      VectorClock::Comparison::GreaterThan)));
+
+INSTANTIATE_TEST_CASE_P(
+    Conflict,
+    VectorClockComparisonTest,
+    ::testing::Values(std::make_tuple(VectorClock(1, 2),
+                                      VectorClock(0, 1),
+                                      VectorClock::Comparison::Conflict),
+                      std::make_tuple(VectorClock(1, 2),
+                                      VectorClock(0, 3),
+                                      VectorClock::Comparison::Conflict)));
+
+INSTANTIATE_TEST_CASE_P(
+    EqualTo,
+    VectorClockComparisonTest,
+    ::testing::Values(std::make_tuple(VectorClock(1, 1),
+                                      VectorClock(1, 1),
+                                      VectorClock::Comparison::EqualTo),
+                      std::make_tuple(VectorClock(2, 3),
+                                      VectorClock(2, 3),
+                                      VectorClock::Comparison::EqualTo),
+                      std::make_tuple(VectorClock(3, 2),
+                                      VectorClock(3, 2),
+                                      VectorClock::Comparison::EqualTo)));
+
+class VectorClockTest : public testing::Test {
+ public:
+  VectorClockTest() {}
+  ~VectorClockTest() override {}
+
+ protected:
+  void CheckCumulativeMerge(const VectorClock& v1,
+                            const VectorClock& v2,
+                            const VectorClock& expected) {
+    // Compute the merge of v1 and v2
+    VectorClock r1 = v1.MergeWith(v2);
+    EXPECT_EQ(expected.local_revision(), r1.local_revision());
+    EXPECT_EQ(expected.remote_revision(), r1.remote_revision());
+
+    // Compute the merge of v2 and v1
+    VectorClock r2 = v2.MergeWith(v1);
+    EXPECT_EQ(expected.local_revision(), r2.local_revision());
+    EXPECT_EQ(expected.remote_revision(), r2.remote_revision());
+  }
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(VectorClockTest);
+};
+
+TEST_F(VectorClockTest, IncrementLocal1) {
+  VectorClock v(0, 0);
+  v.IncrementLocal();
+  EXPECT_EQ(1U, v.local_revision());
+  EXPECT_EQ(0U, v.remote_revision());
+}
+
+TEST_F(VectorClockTest, IncrementLocal2) {
+  VectorClock v(4, 5);
+  v.IncrementLocal();
+  EXPECT_EQ(5U, v.local_revision());
+  EXPECT_EQ(5U, v.remote_revision());
+}
+
+TEST_F(VectorClockTest, MergeLocalEqualRemoteSmaller) {
+  VectorClock v1(1, 2);
+  VectorClock v2(1, 4);
+
+  VectorClock expected(1, 4);
+  CheckCumulativeMerge(v1, v2, expected);
+}
+
+TEST_F(VectorClockTest, MergeLocalSmallerRemoteEqual) {
+  VectorClock v1(1, 4);
+  VectorClock v2(2, 4);
+
+  VectorClock expected(2, 4);
+  CheckCumulativeMerge(v1, v2, expected);
+}
+
+TEST_F(VectorClockTest, MergeLocalSmallerRemoteSmaller) {
+  VectorClock v1(1, 2);
+  VectorClock v2(3, 4);
+
+  VectorClock expected(3, 4);
+  CheckCumulativeMerge(v1, v2, expected);
+}
+
+TEST_F(VectorClockTest, MergeLocalSmallerRemoteGreater) {
+  VectorClock v1(1, 4);
+  VectorClock v2(3, 2);
+
+  VectorClock expected(3, 4);
+  CheckCumulativeMerge(v1, v2, expected);
+}
+
+}  // namespace
+}  // namespace blimp
diff --git a/build/config/compiler/BUILD.gn b/build/config/compiler/BUILD.gn
index 4bbc34f4..5fcc050 100644
--- a/build/config/compiler/BUILD.gn
+++ b/build/config/compiler/BUILD.gn
@@ -1084,9 +1084,7 @@
       defines += [ "_FORTIFY_SOURCE=2" ]
     }
 
-    if (is_mac) {
-      # Warn if automatic synthesis is triggered. This triggers numerous
-      # warnings for internal iOS directories.
+    if (is_mac || is_ios) {
       cflags_objc = [ "-Wobjc-missing-property-synthesis" ]
       cflags_objcc = [ "-Wobjc-missing-property-synthesis" ]
     }
diff --git a/build/config/ios/codesign.py b/build/config/ios/codesign.py
index 3d66b24..5b55318 100644
--- a/build/config/ios/codesign.py
+++ b/build/config/ios/codesign.py
@@ -232,7 +232,6 @@
 
 
 class Action(object):
-
   """Class implementing one action supported by the script."""
 
   @classmethod
@@ -243,7 +242,6 @@
 
 
 class CodeSignBundleAction(Action):
-
   """Class implementing the code-sign-bundle action."""
 
   name = 'code-sign-bundle'
@@ -321,8 +319,49 @@
     CodeSignBundle(bundle.path, args.identity, codesign_extra_args)
 
 
-class GenerateEntitlementsAction(Action):
+class CodeSignFileAction(Action):
+  """Class implementing code signature for a single file."""
 
+  name = 'code-sign-file'
+  help = 'code-sign a single file'
+
+  @staticmethod
+  def _Register(parser):
+    parser.add_argument(
+        'path', help='path to the file to codesign')
+    parser.add_argument(
+        '--identity', '-i', required=True,
+        help='identity to use to codesign')
+    parser.add_argument(
+        '--output', '-o',
+        help='if specified copy the file to that location before signing it')
+    parser.set_defaults(sign=True)
+
+  @staticmethod
+  def _Execute(args):
+    if not args.identity:
+      args.identity = '-'
+
+    install_path = args.path
+    if args.output:
+
+      if os.path.isfile(args.output):
+        os.unlink(args.output)
+      elif os.path.isdir(args.output):
+        shutil.rmtree(args.output)
+
+      if os.path.isfile(args.path):
+        shutil.copy(args.path, args.output)
+      elif os.path.isdir(args.path):
+        shutil.copytree(args.path, args.output)
+
+      install_path = args.output
+
+    CodeSignBundle(install_path, args.identity,
+      ['--deep', '--preserve-metadata=identifier,entitlements'])
+
+
+class GenerateEntitlementsAction(Action):
   """Class implementing the generate-entitlements action."""
 
   name = 'generate-entitlements'
@@ -353,7 +392,13 @@
   parser = argparse.ArgumentParser('codesign iOS bundles')
   subparsers = parser.add_subparsers()
 
-  for action in [ CodeSignBundleAction, GenerateEntitlementsAction ]:
+  actions = [
+      CodeSignBundleAction,
+      CodeSignFileAction,
+      GenerateEntitlementsAction,
+  ]
+
+  for action in actions:
     action.Register(subparsers)
 
   args = parser.parse_args()
diff --git a/build/config/ios/rules.gni b/build/config/ios/rules.gni
index 8d1c162..93565f0 100644
--- a/build/config/ios/rules.gni
+++ b/build/config/ios/rules.gni
@@ -223,7 +223,7 @@
       code_signing_outputs +=
           [ "$_bundle_root_dir/_CodeSignature/CodeResources" ]
     }
-    if (ios_code_signing_identity != "" && ios_sdk_name != "iphonesimulator") {
+    if (ios_code_signing_identity != "" && !use_ios_simulator) {
       code_signing_outputs += [ "$_bundle_root_dir/embedded.mobileprovision" ]
     }
 
diff --git a/build/config/locales.gni b/build/config/locales.gni
index 5886132..2b608b7 100644
--- a/build/config/locales.gni
+++ b/build/config/locales.gni
@@ -2,6 +2,22 @@
 # Use of this source code is governed by a BSD-style license that can be
 # found in the LICENSE file.
 
+# Android doesn't ship all locales in order to save space (but webview does).
+# http://crbug.com/369218
+if (is_android) {
+  android_chrome_omitted_locales = [
+    "bn",
+    "et",
+    "gu",
+    "kn",
+    "ml",
+    "mr",
+    "ms",
+    "ta",
+    "te",
+  ]
+}
+
 # Chrome on iOS only ships with a subset of the locales supported by other
 # version of Chrome as the corresponding locales are not supported by the
 # operating system (but for simplicity, the corresponding .pak files are
diff --git a/build/config/sanitizers/BUILD.gn b/build/config/sanitizers/BUILD.gn
index 9dc878e..5040189e 100644
--- a/build/config/sanitizers/BUILD.gn
+++ b/build/config/sanitizers/BUILD.gn
@@ -9,6 +9,10 @@
 import("//build/config/sanitizers/sanitizers.gni")
 import("//build/toolchain/toolchain.gni")
 
+if (is_ios) {
+  import("//build/config/ios/ios_sdk.gni")
+}
+
 # Contains the dependencies needed for sanitizers to link into executables and
 # shared_libraries. Unconditionally depend upon this target as it is empty if
 # |is_asan|, |is_lsan|, |is_tsan|, |is_msan| and |use_custom_libcxx| are false.
@@ -67,35 +71,65 @@
       public_deps += [ "//buildtools/third_party/libc++:libcxx_proxy" ]
       data += [ "$root_out_dir/libc++.so" ]
     }
-    if (is_mac || is_win) {
+
+    # ASAN is supported on iOS but the runtime library depends on the compiler
+    # used (Chromium version of clang versus Xcode version of clang). Only copy
+    # the ASAN runtime on iOS if building with Chromium clang.
+    if (is_win || is_mac || (is_ios && !use_xcode_clang)) {
       data_deps = [
         ":copy_asan_runtime",
       ]
     }
-    if (is_mac) {
+    if (is_mac || (is_ios && !use_xcode_clang)) {
       public_deps += [ ":asan_runtime_bundle_data" ]
     }
   }
 }
 
-if ((is_mac || is_win) && using_sanitizer) {
-  copy("copy_asan_runtime") {
-    if (is_mac) {
-      clang_rt_dso_path = "darwin/libclang_rt.asan_osx_dynamic.dylib"
-    } else if (is_win && target_cpu == "x86") {
-      clang_rt_dso_path = "windows/clang_rt.asan_dynamic-i386.dll"
-    } else if (is_win && target_cpu == "x64") {
-      clang_rt_dso_path = "windows/clang_rt.asan_dynamic-x86_64.dll"
-    }
-    sources = [
-      "$clang_base_path/lib/clang/$clang_version/lib/$clang_rt_dso_path",
-    ]
-    outputs = [
-      "$root_out_dir/{{source_file_part}}",
-    ]
+if ((is_mac || is_win || (is_ios && !use_xcode_clang)) && using_sanitizer) {
+  if (is_mac) {
+    _clang_rt_dso_path = "darwin/libclang_rt.asan_osx_dynamic.dylib"
+  } else if (is_ios) {
+    _clang_rt_dso_path = "darwin/libclang_rt.asan_iossim_dynamic.dylib"
+  } else if (is_win && target_cpu == "x86") {
+    _clang_rt_dso_path = "windows/clang_rt.asan_dynamic-i386.dll"
+  } else if (is_win && target_cpu == "x64") {
+    _clang_rt_dso_path = "windows/clang_rt.asan_dynamic-x86_64.dll"
   }
 
-  if (is_mac) {
+  _clang_rt_dso_full_path =
+      "$clang_base_path/lib/clang/$clang_version/lib/$_clang_rt_dso_path"
+
+  if (!is_ios) {
+    copy("copy_asan_runtime") {
+      sources = [
+        _clang_rt_dso_full_path,
+      ]
+      outputs = [
+        "$root_out_dir/{{source_file_part}}",
+      ]
+    }
+  } else {
+    # On iOS, the runtime library need to be code signed (adhoc signature)
+    # starting with Xcode 8, so use an action instead of a copy on iOS.
+    action("copy_asan_runtime") {
+      script = "//build/config/ios/codesign.py"
+      sources = [
+        _clang_rt_dso_full_path,
+      ]
+      outputs = [
+        "$root_out_dir/" + get_path_info(sources[0], "file"),
+      ]
+      args = [
+        "code-sign-file",
+        "--identity=" + ios_code_signing_identity,
+        "--output=" + rebase_path(outputs[0], root_build_dir),
+        rebase_path(sources[0], root_build_dir),
+      ]
+    }
+  }
+
+  if (is_mac || is_ios) {
     bundle_data("asan_runtime_bundle_data") {
       sources = get_target_outputs(":copy_asan_runtime")
       outputs = [
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 8a22ed7..4f242d1 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -67,52 +67,10 @@
 }
 
 locale_pak_resources("chrome_locale_paks") {
-  sources = [
-    "$root_out_dir/locales/am.pak",
-    "$root_out_dir/locales/ar.pak",
-    "$root_out_dir/locales/bg.pak",
-    "$root_out_dir/locales/ca.pak",
-    "$root_out_dir/locales/cs.pak",
-    "$root_out_dir/locales/da.pak",
-    "$root_out_dir/locales/de.pak",
-    "$root_out_dir/locales/el.pak",
-    "$root_out_dir/locales/en-GB.pak",
-    "$root_out_dir/locales/en-US.pak",
-    "$root_out_dir/locales/es-419.pak",
-    "$root_out_dir/locales/es.pak",
-    "$root_out_dir/locales/fa.pak",
-    "$root_out_dir/locales/fi.pak",
-    "$root_out_dir/locales/fil.pak",
-    "$root_out_dir/locales/fr.pak",
-    "$root_out_dir/locales/he.pak",
-    "$root_out_dir/locales/hi.pak",
-    "$root_out_dir/locales/hr.pak",
-    "$root_out_dir/locales/hu.pak",
-    "$root_out_dir/locales/id.pak",
-    "$root_out_dir/locales/it.pak",
-    "$root_out_dir/locales/ja.pak",
-    "$root_out_dir/locales/ko.pak",
-    "$root_out_dir/locales/lt.pak",
-    "$root_out_dir/locales/lv.pak",
-    "$root_out_dir/locales/nb.pak",
-    "$root_out_dir/locales/nl.pak",
-    "$root_out_dir/locales/pl.pak",
-    "$root_out_dir/locales/pt-BR.pak",
-    "$root_out_dir/locales/pt-PT.pak",
-    "$root_out_dir/locales/ro.pak",
-    "$root_out_dir/locales/ru.pak",
-    "$root_out_dir/locales/sk.pak",
-    "$root_out_dir/locales/sl.pak",
-    "$root_out_dir/locales/sr.pak",
-    "$root_out_dir/locales/sv.pak",
-    "$root_out_dir/locales/sw.pak",
-    "$root_out_dir/locales/th.pak",
-    "$root_out_dir/locales/tr.pak",
-    "$root_out_dir/locales/uk.pak",
-    "$root_out_dir/locales/vi.pak",
-    "$root_out_dir/locales/zh-CN.pak",
-    "$root_out_dir/locales/zh-TW.pak",
-  ]
+  sources = []
+  foreach(_locale, locales - android_chrome_omitted_locales) {
+    sources += [ "$root_out_dir/locales/$_locale.pak" ]
+  }
 
   deps = [
     "//chrome:packed_resources",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
index d93e107..ec0bfdf 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ItemChooserDialog.java
@@ -202,6 +202,17 @@
         public void remove(ItemChooserRow item) {
             ItemChooserRow oldItem = mKeyToItemMap.remove(item.mKey);
             if (oldItem == null) return;
+            int oldItemPosition = getPosition(oldItem);
+            // If the removed item is the item that is currently selected, deselect it
+            // and disable the confirm button. Otherwise if the removed item is before
+            // the currently selected item, the currently selected item's index needs
+            // to be adjusted by one.
+            if (oldItemPosition == mSelectedItem) {
+                mSelectedItem = ListView.INVALID_POSITION;
+                mConfirmButton.setEnabled(false);
+            } else if (oldItemPosition < mSelectedItem) {
+                --mSelectedItem;
+            }
             removeFromDescriptionsMap(oldItem.mDescription);
             super.remove(oldItem);
         }
@@ -221,6 +232,7 @@
          * selected.
          */
         public String getSelectedItemKey() {
+            if (mSelectedItem == ListView.INVALID_POSITION) return "";
             ItemChooserRow row = getItem(mSelectedItem);
             if (row == null) return "";
             return row.mKey;
@@ -241,7 +253,7 @@
         }
 
         /**
-         * Sets whether the itam is enabled. Disabled items are grayed out.
+         * Sets whether the item is enabled. Disabled items are grayed out.
          * @param id The id of the item to affect.
          * @param enabled Whether the item should be enabled or not.
          */
@@ -251,6 +263,14 @@
             } else {
                 mDisabledEntries.add(id);
             }
+
+            if (mSelectedItem != ListView.INVALID_POSITION) {
+                ItemChooserRow selectedRow = getItem(mSelectedItem);
+                if (id.equals(selectedRow.mKey)) {
+                    mConfirmButton.setEnabled(enabled);
+                }
+            }
+
             notifyDataSetChanged();
         }
 
@@ -399,6 +419,7 @@
         });
 
         mItemAdapter = new ItemAdapter(mActivity, R.layout.item_chooser_dialog_row);
+        mItemAdapter.setNotifyOnChange(true);
         mListView.setAdapter(mItemAdapter);
         mListView.setEmptyView(mEmptyMessage);
         mListView.setOnItemClickListener(mItemAdapter);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemViewHolder.java
index 0352799..4be5689 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadHistoryItemViewHolder.java
@@ -66,8 +66,9 @@
 
         // Asynchronously grab a thumbnail for the file if it might have one.
         int fileType = item.getFilterType();
+        Bitmap thumbnail = null;
         if (fileType == DownloadFilter.FILTER_IMAGE) {
-            thumbnailProvider.getThumbnail(this);
+            thumbnail = thumbnailProvider.getThumbnail(this);
         } else {
             // TODO(dfalcantara): Get thumbnails for audio and video files when possible.
         }
@@ -94,7 +95,7 @@
         }
 
         // Initialize the DownloadItemView.
-        mItemView.initialize(item, iconResource);
+        mItemView.initialize(item, iconResource, thumbnail);
     }
 
     @VisibleForTesting
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
index e2b1766..337a7e1 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/DownloadItemView.java
@@ -14,6 +14,8 @@
 import org.chromium.chrome.browser.widget.TintedImageView;
 import org.chromium.chrome.browser.widget.selection.SelectableItemView;
 
+import javax.annotation.Nullable;
+
 /**
  * The view for a downloaded item displayed in the Downloads list.
  */
@@ -50,13 +52,15 @@
      *
      * @param item      The item represented by this DownloadItemView.
      * @param iconResId The drawable resource ID to use for the icon ImageView.
+     * @param thumbnail The Bitmap to use for the thumbnail or null.
      */
-    public void initialize(DownloadHistoryItemWrapper item, int iconResId) {
+    public void initialize(DownloadHistoryItemWrapper item, int iconResId,
+            @Nullable Bitmap thumbnail) {
         mItem = item;
         setItem(item);
 
         mIconResId = iconResId;
-        mThumbnailBitmap = null;
+        mThumbnailBitmap = thumbnail;
         updateIconView();
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProvider.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProvider.java
index 3ef3b466..032215e5 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProvider.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProvider.java
@@ -21,10 +21,11 @@
     void destroy();
 
     /**
-     * Asynchronously returns a thumbnail via {@link ThumbnailRequest#onThumbnailRetrieved}.
+     * Synchronously returns a thumbnail if it is cached. Otherwise, asynchronously returns a
+     * thumbnail via {@link ThumbnailRequest#onThumbnailRetrieved}.
      * @param request Parameters that describe the thumbnail being retrieved.
      */
-    void getThumbnail(ThumbnailRequest request);
+    Bitmap getThumbnail(ThumbnailRequest request);
 
     /** Removes a particular request from the pending queue. */
     void cancelRetrieval(ThumbnailRequest request);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java
index c32b4c02..73366c0 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/ui/ThumbnailProviderImpl.java
@@ -67,12 +67,16 @@
     }
 
     @Override
-    public void getThumbnail(ThumbnailRequest request) {
+    public Bitmap getThumbnail(ThumbnailRequest request) {
         String filePath = request.getFilePath();
-        if (TextUtils.isEmpty(filePath)) return;
+        if (TextUtils.isEmpty(filePath)) return null;
+
+        Bitmap cachedBitmap = getBitmapCache().get(filePath);
+        if (cachedBitmap != null) return cachedBitmap;
 
         mRequestQueue.offer(request);
         processQueue();
+        return null;
     }
 
     /** Removes a particular file from the pending queue. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
index 1a1ac8f7e..de27aef 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -48,7 +48,6 @@
 import org.chromium.chrome.browser.ntp.MostVisitedItem.MostVisitedItemManager;
 import org.chromium.chrome.browser.ntp.NewTabPage.OnSearchBoxScrollListener;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageAdapter;
-import org.chromium.chrome.browser.ntp.cards.NewTabPageItem;
 import org.chromium.chrome.browser.ntp.cards.NewTabPageRecyclerView;
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.ntp.snippets.SnippetsConfig;
@@ -513,21 +512,6 @@
     }
 
     /**
-     * Get the number of listed items (visible or not) for the given type.
-     * @param newTabPageItemViewType the item type to count.
-     */
-    public int getViewCountMatchingViewType(@NewTabPageItem.ViewType int newTabPageItemViewType) {
-        int viewCount = 0;
-        int adapterSize = mNewTabPageAdapter.getItemCount();
-        for (int i = 0; i < adapterSize; i++) {
-            if (mNewTabPageAdapter.getItemViewType(i) == newTabPageItemViewType) {
-                viewCount++;
-            }
-        }
-        return viewCount;
-    }
-
-    /**
      * Sets up scrolling when snippets are enabled. It adds scroll listeners and touch listeners to
      * the RecyclerView.
      */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
index 3701ed4..99dd3ba 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapter.java
@@ -230,9 +230,9 @@
     }
 
     @Override
-    public void onSuggestionInvalidated(@CategoryInt int category, String suggestionId) {
+    public void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {
         if (!mSections.containsKey(category)) return;
-        mSections.get(category).removeSuggestionById(suggestionId);
+        mSections.get(category).removeSuggestionById(idWithinCategory);
         updateGroups();
     }
 
@@ -318,14 +318,11 @@
         return getGroupPositionOffset(mBottomSpacer);
     }
 
-    public int getSuggestionPosition(String suggestionId) {
+    public int getSuggestionPosition(SnippetArticle article) {
         List<NewTabPageItem> items = getItems();
         for (int i = 0; i < items.size(); i++) {
             NewTabPageItem item = items.get(i);
-            if (item instanceof SnippetArticle
-                    && ((SnippetArticle) item).mId.equals(suggestionId)) {
-                return i;
-            }
+            if (article.equals(item)) return i;
         }
         return RecyclerView.NO_POSITION;
     }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
index 351e0d4..dcd072f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/NewTabPageRecyclerView.java
@@ -429,7 +429,7 @@
      */
     public void dismissItemWithAnimation(SnippetArticle suggestion) {
         // We need to recompute the position, as it might have changed.
-        final int position = getNewTabPageAdapter().getSuggestionPosition(suggestion.mId);
+        final int position = getNewTabPageAdapter().getSuggestionPosition(suggestion);
         if (position == RecyclerView.NO_POSITION) {
             // The item does not exist anymore, so ignore.
             return;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
index 6348250..2b29f57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/cards/SuggestionsSection.java
@@ -67,9 +67,9 @@
         if (mMoreButton != null) mMoreButton.setDismissable(!hasSuggestions());
     }
 
-    public void removeSuggestionById(String suggestionId) {
+    public void removeSuggestionById(String idWithinCategory) {
         for (SnippetArticle suggestion : mSuggestions) {
-            if (suggestion.mId.equals(suggestionId)) {
+            if (suggestion.mIdWithinCategory.equals(idWithinCategory)) {
                 removeSuggestion(suggestion);
                 return;
             }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java
index bec2652..325e618c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/FakeSuggestionsSource.java
@@ -70,14 +70,14 @@
      * Removes the given suggestion from the source and notifies any observer that it has been
      * invalidated.
      */
-    public void fireSuggestionInvalidated(@CategoryInt int category, String suggestionId) {
+    public void fireSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {
         for (SnippetArticle suggestion : mSuggestions.get(category)) {
-            if (suggestion.mId.equals(suggestionId)) {
+            if (suggestion.mIdWithinCategory.equals(idWithinCategory)) {
                 mSuggestions.get(category).remove(suggestion);
                 break;
             }
         }
-        mObserver.onSuggestionInvalidated(category, suggestionId);
+        mObserver.onSuggestionInvalidated(category, idWithinCategory);
     }
 
     /**
@@ -102,8 +102,8 @@
 
     @Override
     public void fetchSuggestionImage(SnippetArticle suggestion, Callback<Bitmap> callback) {
-        if (mThumbnails.containsKey(suggestion.mId)) {
-            callback.onResult(mThumbnails.get(suggestion.mId));
+        if (mThumbnails.containsKey(suggestion.mIdWithinCategory)) {
+            callback.onResult(mThumbnails.get(suggestion.mIdWithinCategory));
         }
     }
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
index 7fb0372..2387d61 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetArticle.java
@@ -18,8 +18,8 @@
     /** The category of this article. */
     public final int mCategory;
 
-    /** The unique identifier for this article. */
-    public final String mId;
+    /** The identifier for this article within the category - not necessarily unique globally. */
+    public final String mIdWithinCategory;
 
     /** The title of this article. */
     public final String mTitle;
@@ -64,11 +64,11 @@
     /**
      * Creates a SnippetArticleListItem object that will hold the data.
      */
-    public SnippetArticle(int category, String id, String title, String publisher,
+    public SnippetArticle(int category, String idWithinCategory, String title, String publisher,
             String previewText, String url, String ampUrl, long timestamp, float score,
             int position, @ContentSuggestionsCardLayoutEnum int cardLayout) {
         mCategory = category;
-        mId = id;
+        mIdWithinCategory = idWithinCategory;
         mTitle = title;
         mPublisher = publisher;
         mPreviewText = previewText;
@@ -83,12 +83,13 @@
     @Override
     public boolean equals(Object other) {
         if (!(other instanceof SnippetArticle)) return false;
-        return mId.equals(((SnippetArticle) other).mId);
+        SnippetArticle rhs = (SnippetArticle) other;
+        return mCategory == rhs.mCategory && mIdWithinCategory.equals(rhs.mIdWithinCategory);
     }
 
     @Override
     public int hashCode() {
-        return mId.hashCode();
+        return mCategory ^ mIdWithinCategory.hashCode();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
index e3850d1..e3cdbd3 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SnippetsBridge.java
@@ -107,13 +107,15 @@
     @Override
     public void fetchSuggestionImage(SnippetArticle suggestion, Callback<Bitmap> callback) {
         assert mNativeSnippetsBridge != 0;
-        nativeFetchSuggestionImage(mNativeSnippetsBridge, suggestion.mId, callback);
+        nativeFetchSuggestionImage(mNativeSnippetsBridge, suggestion.mCategory,
+                suggestion.mIdWithinCategory, callback);
     }
 
     @Override
     public void dismissSuggestion(SnippetArticle suggestion) {
         assert mNativeSnippetsBridge != 0;
-        nativeDismissSuggestion(mNativeSnippetsBridge, suggestion.mId);
+        nativeDismissSuggestion(
+                mNativeSnippetsBridge, suggestion.mCategory, suggestion.mIdWithinCategory);
     }
 
     @Override
@@ -219,8 +221,8 @@
     }
 
     @CalledByNative
-    private void onSuggestionInvalidated(@CategoryInt int category, String suggestionId) {
-        if (mObserver != null) mObserver.onSuggestionInvalidated(category, suggestionId);
+    private void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory) {
+        if (mObserver != null) mObserver.onSuggestionInvalidated(category, idWithinCategory);
     }
 
     private native long nativeInit(Profile profile);
@@ -233,9 +235,10 @@
             long nativeNTPSnippetsBridge, int category);
     private native List<SnippetArticle> nativeGetSuggestionsForCategory(
             long nativeNTPSnippetsBridge, int category);
-    private native void nativeFetchSuggestionImage(
-            long nativeNTPSnippetsBridge, String suggestionId, Callback<Bitmap> callback);
-    private native void nativeDismissSuggestion(long nativeNTPSnippetsBridge, String suggestionId);
+    private native void nativeFetchSuggestionImage(long nativeNTPSnippetsBridge, int category,
+            String idWithinCategory, Callback<Bitmap> callback);
+    private native void nativeDismissSuggestion(
+            long nativeNTPSnippetsBridge, int category, String idWithinCategory);
     private native void nativeDismissCategory(long nativeNTPSnippetsBridge, int category);
     private native void nativeGetURLVisited(
             long nativeNTPSnippetsBridge, Callback<Boolean> callback, String url);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
index 9bd37a8d..1f631587a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/snippets/SuggestionsSource.java
@@ -31,7 +31,7 @@
          * immediately. This event may be fired for a category or suggestion that does not
          * currently exist or has never existed and should be ignored in that case.
          */
-        void onSuggestionInvalidated(@CategoryInt int category, String suggestionId);
+        void onSuggestionInvalidated(@CategoryInt int category, String idWithinCategory);
     }
 
     /**
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
index cdbc4f35..3f1abe26 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ItemChooserDialogTest.java
@@ -203,6 +203,117 @@
     }
 
     @LargeTest
+    public void testPairButtonDisabledOrEnabledAfterSelectedItemDisabledOrEnabled()
+            throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+
+        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key1", "desc1"));
+        mChooserDialog.addOrUpdateItem(new ItemChooserDialog.ItemChooserRow("key2", "desc2"));
+
+        selectItem(dialog, 1, "key1", true);
+        assertTrue(button.isEnabled());
+
+        mChooserDialog.setEnabled("key1", false);
+        assertFalse(button.isEnabled());
+
+        mChooserDialog.setEnabled("key1", true);
+        assertTrue(button.isEnabled());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
+    public void testPairButtonDisabledAfterSelectedItemRemoved() throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+
+        ItemChooserDialog.ItemChooserRow item1 =
+                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
+        ItemChooserDialog.ItemChooserRow item2 =
+                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
+        mChooserDialog.addOrUpdateItem(item1);
+        mChooserDialog.addOrUpdateItem(item2);
+
+        selectItem(dialog, 1, "key1", true);
+        assertTrue(button.isEnabled());
+
+        mChooserDialog.removeItemFromList(item1);
+        assertFalse(button.isEnabled());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
+    public void testSelectAnItemAndRemoveAnotherItem() throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+        ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
+
+        ItemChooserDialog.ItemChooserRow item1 =
+                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
+        ItemChooserDialog.ItemChooserRow item2 =
+                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
+        ItemChooserDialog.ItemChooserRow item3 =
+                new ItemChooserDialog.ItemChooserRow("key3", "desc3");
+
+        mChooserDialog.addOrUpdateItem(item1);
+        mChooserDialog.addOrUpdateItem(item2);
+        mChooserDialog.addOrUpdateItem(item3);
+
+        selectItem(dialog, 2, "key2", true);
+        assertTrue(button.isEnabled());
+
+        // Remove the item before the currently selected item.
+        mChooserDialog.removeItemFromList(item1);
+        assertTrue(button.isEnabled());
+        assertEquals("key2", itemAdapter.getSelectedItemKey());
+
+        // Remove the item after the currently selected item.
+        mChooserDialog.removeItemFromList(item3);
+        assertTrue(button.isEnabled());
+        assertEquals("key2", itemAdapter.getSelectedItemKey());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
+    public void testSelectAnItemAndRemoveTheSelectedItem() throws InterruptedException {
+        Dialog dialog = mChooserDialog.getDialogForTesting();
+        assertTrue(dialog.isShowing());
+
+        final Button button = (Button) dialog.findViewById(R.id.positive);
+        ItemChooserDialog.ItemAdapter itemAdapter = mChooserDialog.getItemAdapterForTesting();
+
+        ItemChooserDialog.ItemChooserRow item1 =
+                new ItemChooserDialog.ItemChooserRow("key1", "desc1");
+        ItemChooserDialog.ItemChooserRow item2 =
+                new ItemChooserDialog.ItemChooserRow("key2", "desc2");
+        ItemChooserDialog.ItemChooserRow item3 =
+                new ItemChooserDialog.ItemChooserRow("key3", "desc3");
+
+        mChooserDialog.addOrUpdateItem(item1);
+        mChooserDialog.addOrUpdateItem(item2);
+        mChooserDialog.addOrUpdateItem(item3);
+
+        selectItem(dialog, 2, "key2", true);
+        assertTrue(button.isEnabled());
+
+        // Remove the selected item.
+        mChooserDialog.removeItemFromList(item2);
+        assertFalse(button.isEnabled());
+        assertEquals("", itemAdapter.getSelectedItemKey());
+
+        mChooserDialog.dismiss();
+    }
+
+    @LargeTest
     public void testAddOrUpdateItemAndRemoveItemFromList() throws InterruptedException {
         Dialog dialog = mChooserDialog.getDialogForTesting();
         assertTrue(dialog.isShowing());
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
index 81c0f67..66b52405 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/download/ui/StubbedProvider.java
@@ -8,6 +8,7 @@
 import static junit.framework.Assert.assertNull;
 
 import android.content.ComponentName;
+import android.graphics.Bitmap;
 import android.os.Handler;
 import android.os.Looper;
 import android.text.TextUtils;
@@ -145,8 +146,12 @@
     public static class StubbedThumbnailProvider implements ThumbnailProvider {
         @Override
         public void destroy() {}
+
         @Override
-        public void getThumbnail(ThumbnailRequest request) {}
+        public Bitmap getThumbnail(ThumbnailRequest request) {
+            return null;
+        }
+
         @Override
         public void cancelRetrieval(ThumbnailRequest request) {}
     }
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
index 956e6f0..67911e4 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/ntp/cards/NewTabPageAdapterTest.java
@@ -580,7 +580,7 @@
         assertArticlesEqual(articles, 2, 5);
 
         SnippetArticle removed = articles.remove(1);
-        mSource.fireSuggestionInvalidated(KnownCategories.ARTICLES, removed.mId);
+        mSource.fireSuggestionInvalidated(KnownCategories.ARTICLES, removed.mIdWithinCategory);
         assertArticlesEqual(articles, 2, 4);
     }
 
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp
index 299b886..e8e2180 100644
--- a/chrome/app/chromeos_strings.grdp
+++ b/chrome/app/chromeos_strings.grdp
@@ -4660,6 +4660,9 @@
   <message name="IDS_KEYBOARD_OVERLAY_TOGGLE_CHROMEVOX_SPOKEN_FEEDBACK" desc="The text in the keyboard overlay to explain the shortcut (enable or disable spoken feedback).">
     ChromeVox (spoken feedback)
   </message>
+  <message name="IDS_KEYBOARD_OVERLAY_TOGGLE_HIGH_CONTRAST_MODE" desc="The text in the keyboard overlay to explain the shortcut (Toggle high contrast mode).">
+    Toggle High Contrast Mode
+  </message>
   <message name="IDS_KEYBOARD_OVERLAY_TOGGLE_PROJECTION_TOUCH_HUD" desc="The text in the keyboard overlay to explain the shortcut.">
     Projection touch HUD
   </message>
diff --git a/chrome/browser/android/download/download_controller.cc b/chrome/browser/android/download/download_controller.cc
index 337b8ab62..024bef0 100644
--- a/chrome/browser/android/download/download_controller.cc
+++ b/chrome/browser/android/download/download_controller.cc
@@ -217,11 +217,6 @@
       RequestFileAccess(callback_id);
 }
 
-void DownloadController::SetDefaultDownloadFileName(
-    const std::string& file_name) {
-  default_file_name_ = file_name;
-}
-
 bool DownloadController::HasFileAccessPermission(
     ui::WindowAndroid* window_android) {
   ScopedJavaLocalRef<jobject> jwindow_android = window_android->GetJavaObject();
diff --git a/chrome/browser/android/download/download_controller.h b/chrome/browser/android/download/download_controller.h
index 163e815..737e380 100644
--- a/chrome/browser/android/download/download_controller.h
+++ b/chrome/browser/android/download/download_controller.h
@@ -48,7 +48,6 @@
   void AcquireFileAccessPermission(
       content::WebContents* web_contents,
       const AcquireFileAccessPermissionCallback& callback) override;
-  void SetDefaultDownloadFileName(const std::string& file_name) override;
 
   // UMA histogram enum for download cancellation reasons. Keep this
   // in sync with MobileDownloadCancelReason in histograms.xml. This should be
diff --git a/chrome/browser/android/download/download_controller_base.h b/chrome/browser/android/download/download_controller_base.h
index c317ed4..ec85098 100644
--- a/chrome/browser/android/download/download_controller_base.h
+++ b/chrome/browser/android/download/download_controller_base.h
@@ -88,10 +88,6 @@
   // Called by unit test to approve or disapprove file access request.
   virtual void SetApproveFileAccessRequestForTesting(bool approve) {}
 
-  // Called to set the default download file name if it cannot be resolved
-  // from url and content disposition
-  virtual void SetDefaultDownloadFileName(const std::string& file_name) {}
-
  protected:
   ~DownloadControllerBase() override {}
   static DownloadControllerBase* download_controller_;
diff --git a/chrome/browser/android/download/download_manager_service.cc b/chrome/browser/android/download/download_manager_service.cc
index 5630e66..9b4fa66b 100644
--- a/chrome/browser/android/download/download_manager_service.cc
+++ b/chrome/browser/android/download/download_manager_service.cc
@@ -111,8 +111,6 @@
     JNIEnv* env,
     jobject obj) {
   java_ref_.Reset(env, obj);
-  DownloadControllerBase::Get()->SetDefaultDownloadFileName(
-      l10n_util::GetStringUTF8(IDS_DEFAULT_DOWNLOAD_FILENAME));
 }
 
 void DownloadManagerService::ResumeDownload(
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.cc b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
index 6b0c9fe..1e4f9805 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.cc
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.cc
@@ -201,7 +201,8 @@
       Java_SnippetsBridge_createSuggestionList(env);
   for (const ContentSuggestion& suggestion : suggestions) {
     Java_SnippetsBridge_addSuggestion(
-        env, result, category, ConvertUTF8ToJavaString(env, suggestion.id()),
+        env, result, category,
+        ConvertUTF8ToJavaString(env, suggestion.id().id_within_category()),
         ConvertUTF16ToJavaString(env, suggestion.title()),
         ConvertUTF16ToJavaString(env, suggestion.publisher_name()),
         ConvertUTF16ToJavaString(env, suggestion.snippet_text()),
@@ -216,11 +217,13 @@
 void NTPSnippetsBridge::FetchSuggestionImage(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& suggestion_id,
+    jint category,
+    const JavaParamRef<jstring>& id_within_category,
     const JavaParamRef<jobject>& j_callback) {
   base::android::ScopedJavaGlobalRef<jobject> callback(j_callback);
   content_suggestions_service_->FetchSuggestionImage(
-      ConvertJavaStringToUTF8(env, suggestion_id),
+      ContentSuggestion::ID(CategoryFromIDValue(category),
+                            ConvertJavaStringToUTF8(env, id_within_category)),
       base::Bind(&NTPSnippetsBridge::OnImageFetched,
                  weak_ptr_factory_.GetWeakPtr(), callback));
 }
@@ -228,9 +231,11 @@
 void NTPSnippetsBridge::DismissSuggestion(
     JNIEnv* env,
     const JavaParamRef<jobject>& obj,
-    const JavaParamRef<jstring>& suggestion_id) {
+    jint category,
+    const JavaParamRef<jstring>& id_within_category) {
   content_suggestions_service_->DismissSuggestion(
-      ConvertJavaStringToUTF8(env, suggestion_id));
+      ContentSuggestion::ID(CategoryFromIDValue(category),
+                            ConvertJavaStringToUTF8(env, id_within_category)));
 }
 
 void NTPSnippetsBridge::DismissCategory(JNIEnv* env,
@@ -357,15 +362,14 @@
 }
 
 void NTPSnippetsBridge::OnSuggestionInvalidated(
-    Category category,
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   if (observer_.is_null())
     return;
 
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_SnippetsBridge_onSuggestionInvalidated(
-      env, observer_.obj(), static_cast<int>(category.id()),
-      ConvertUTF8ToJavaString(env, suggestion_id).obj());
+      env, observer_.obj(), static_cast<int>(suggestion_id.category().id()),
+      ConvertUTF8ToJavaString(env, suggestion_id.id_within_category()).obj());
 }
 
 void NTPSnippetsBridge::ContentSuggestionsServiceShutdown() {
diff --git a/chrome/browser/android/ntp/ntp_snippets_bridge.h b/chrome/browser/android/ntp/ntp_snippets_bridge.h
index e5332b8..3f94cb4 100644
--- a/chrome/browser/android/ntp/ntp_snippets_bridge.h
+++ b/chrome/browser/android/ntp/ntp_snippets_bridge.h
@@ -54,13 +54,15 @@
   void FetchSuggestionImage(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& suggestion_id,
+      jint category,
+      const base::android::JavaParamRef<jstring>& id_within_category,
       const base::android::JavaParamRef<jobject>& j_callback);
 
   void DismissSuggestion(
       JNIEnv* env,
       const base::android::JavaParamRef<jobject>& obj,
-      const base::android::JavaParamRef<jstring>& suggestion_id);
+      jint category,
+      const base::android::JavaParamRef<jstring>& id_within_category);
 
   void DismissCategory(JNIEnv* env,
                        const base::android::JavaParamRef<jobject>& obj,
@@ -124,8 +126,8 @@
   void OnCategoryStatusChanged(
       ntp_snippets::Category category,
       ntp_snippets::CategoryStatus new_status) override;
-  void OnSuggestionInvalidated(ntp_snippets::Category category,
-                               const std::string& suggestion_id) override;
+  void OnSuggestionInvalidated(
+      const ntp_snippets::ContentSuggestion::ID& suggestion_id) override;
   void ContentSuggestionsServiceShutdown() override;
 
   void OnImageFetched(base::android::ScopedJavaGlobalRef<jobject> callback,
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
index 5f447423..3685359 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher.cc
@@ -114,8 +114,6 @@
   WebApplicationInfo web_app_info = received_web_app_info;
   web_app_info.title =
       web_app_info.title.substr(0, chrome::kMaxMetaTagAttributeLength);
-  web_app_info.description =
-      web_app_info.description.substr(0, chrome::kMaxMetaTagAttributeLength);
 
   // Simply set the user-editable title to be the page's title
   shortcut_info_.user_title = web_app_info.title.empty()
@@ -211,6 +209,11 @@
         (data.error_code == NO_ERROR_DETECTED &&
          AreWebManifestUrlsWebApkCompatible(data.manifest));
     weak_observer_->OnDidDetermineWebApkCompatibility(webapk_compatible);
+
+    // WebAPKs are wholly defined by the Web Manifest. Ignore the <meta> tag
+    // data received in OnDidGetWebApplicationInfo().
+    if (webapk_compatible)
+      shortcut_info_ = ShortcutInfo(GURL());
   }
 
   if (!data.manifest.IsEmpty()) {
diff --git a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
index 4bde273..b9180b2 100644
--- a/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
+++ b/chrome/browser/android/webapps/add_to_homescreen_data_fetcher_unittest.cc
@@ -14,6 +14,7 @@
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "base/strings/nullable_string16.h"
+#include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/time/time.h"
 #include "chrome/common/web_application_info.h"
@@ -96,7 +97,11 @@
 // called.
 class ObserverWaiter : public AddToHomescreenDataFetcher::Observer {
  public:
-  ObserverWaiter() {}
+  ObserverWaiter()
+      : is_webapk_compatible_(false),
+        determined_webapk_compatibility_(false),
+        title_available_(false),
+        data_available_(false) {}
   ~ObserverWaiter() override {}
 
   // Waits till the OnDataAvailable() callback is called.
@@ -275,6 +280,59 @@
   DISALLOW_COPY_AND_ASSIGN(AddToHomescreenDataFetcherTestCommon);
 };
 
+// Test that when the manifest provides Manifest::short_name but not
+// Manifest::name that Manifest::short_name is used as the name instead of
+// WebApplicationInfo::title.
+TEST_P(AddToHomescreenDataFetcherTestCommon,
+       ManifestShortNameClobbersWebApplicationName) {
+  WebApplicationInfo web_application_info;
+  web_application_info.title = base::UTF8ToUTF16("Meta Title");
+
+  content::Manifest manifest(BuildDefaultManifest());
+  manifest.name = base::NullableString16();
+
+  RegisterServiceWorker(GURL(kDefaultStartUrl));
+  SetManifest(GURL(kDefaultManifestUrl), manifest, 0);
+
+  ObserverWaiter waiter;
+  scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
+  fetcher->OnDidGetWebApplicationInfo(web_application_info);
+  waiter.WaitForDataAvailable();
+
+  EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
+                                kDefaultManifestShortName));
+
+  fetcher->set_weak_observer(nullptr);
+}
+
+// Test that when the manifest does not provide either Manifest::short_name nor
+// Manifest::name that:
+// - The page is not WebAPK compatible.
+// - WebApplicationInfo::title is used as the "name".
+TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestNoNameNoShortName) {
+    const char* kWebApplicationInfoTitle = "Meta Title";
+    WebApplicationInfo web_application_info;
+    web_application_info.title = base::UTF8ToUTF16(kWebApplicationInfoTitle);
+
+    content::Manifest manifest(BuildDefaultManifest());
+    manifest.name = base::NullableString16();
+    manifest.short_name = base::NullableString16();
+
+    RegisterServiceWorker(GURL(kDefaultStartUrl));
+    SetManifest(GURL(kDefaultManifestUrl), manifest, 0);
+
+    ObserverWaiter waiter;
+    scoped_refptr<AddToHomescreenDataFetcher> fetcher(BuildFetcher(&waiter));
+    fetcher->OnDidGetWebApplicationInfo(web_application_info);
+    waiter.WaitForDataAvailable();
+
+    EXPECT_FALSE(waiter.is_webapk_compatible());
+    EXPECT_TRUE(base::EqualsASCII(fetcher->shortcut_info().name,
+                                  kWebApplicationInfoTitle));
+
+    fetcher->set_weak_observer(nullptr);
+}
+
 // Checks that the AddToHomescreenDataFetcher::Observer callbacks are called
 // when a service worker is registered and the manifest fetch times out.
 TEST_P(AddToHomescreenDataFetcherTestCommon, ManifestFetchTimesOut) {
diff --git a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
index b43173d..f930fe5 100644
--- a/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
+++ b/chrome/browser/chromeos/extensions/device_local_account_management_policy_provider.cc
@@ -370,45 +370,31 @@
 // [1] https://developer.chrome.com/apps/declare_permissions
 // [2] https://developer.chrome.com/apps/api_other
 const char* const kSafePermissionStrings[] = {
-    // Risky: Reading accessibility settings could allow to infer health
-    // information.
-    // "accessibilityFeatures.read",
-
     // Modifying accessibility settings seems safe (at most a user could be
     // confused by it).
     "accessibilityFeatures.modify",
 
+    // Originally blocked due to concerns about leaking user health information,
+    // but it seems this does more harm than good as it would likely prevent the
+    // extension from enabling assistive features. If the concerns prevail, we
+    // should probably not block, but adjust the API to pretend accessibility is
+    // off, so we don't punish apps that try to be helpful.
+    "accessibilityFeatures.read",
+
+    // Allows access to web contents in response to user gesture. Note that this
+    // doesn't trigger a permission warning on install though, so blocking is
+    // somewhat at odds with the spirit of the API - however I presume the API
+    // design assumes user-installed extensions, which we don't have here.
+    // "activeTab",
+
     // Schedule code to run at future times.
     "alarms",
 
-    // Risk of listening attack.
-    // "audio",
+    // Allow, but keep PS UX on top regardless.
+    // "app.window.alwaysOnTop",
 
-    // Risk of listening attack.
-    // "audioCapture",
-
-    // Just resource management, probably doesn't even apply to Chrome OS.
-    "background",
-
-    // Open a new tab with a given URL.
-    "browser",
-
-    // Risky: Reading from clipboard could expose private information.
-    // "clipboardRead",
-
-    // Writing to clipboard is safe.
-    "clipboardWrite",
-
-    // Potentially risky: Could be used to spoof system UI.
-    // "contextMenus",
-
-    // Placing a document on the scanner implies user consent.
-    "documentScan",
-
-    // Possibly risky due to its experimental nature: not vetted for security,
-    // potentially buggy, subject to change without notice.
-    // "experimental",
-
+    // TODO(isandrk): The following permissions need to be adjusted
+    // (crbug/651071).
     // Fullscreen is a no-op for Public Session.  Whitelisting nevertheless to
     // broaden the range of supported apps.  (The recommended permission names
     // are "app.window.*" but their unprefixed counterparts are still
@@ -418,88 +404,284 @@
     "fullscreen",
     "overrideEscFullscreen",
 
-    // TBD
-    // "fileSystemProvider",
+    "app.window.shape",
+
+    // The embedded app is subject to the restrictions as well obviously.
+    "appview",
+
+    // Risk of listening attack.
+    // "audio",
+
+    // Need to surface notification to the user. Check what existing UI we have
+    // and whether that's sufficient for PS.
+    // "audioCapture",
+
+    // Just resource management, probably doesn't even apply to Chrome OS.
+    "background",
+
+    // Access to URLs only, no content.
+    "bookmarks",
+
+    // Open a new tab with a given URL.
+    "browser",
+
+    // This allows to read the current browsing data removal dialog settings,
+    // but I don't see why this would be problematic.
+    "browsingData",
+
+    "certificateProvider",
+
+    // This is risky, but blocking extensions just because they declare
+    // clipboardRead is unfortunate. Options: (1) Make clipboardRead return
+    // empty string (2) confirmation dialog.
+    // "clipboardRead",
+
+    // Writing to clipboard is safe.
+    "clipboardWrite",
+
+    "contentSettings",
+
+    // Provides access to URLs.
+    "contextMenus",
+
+    // This would provie access to auth cookies, so needs to be blocked.
+    // "cookies",
+
+    // Provides access to the DOM, so block.
+    // "debugger",
+
+    // This is mostly fine, but has a RequestContentScript action that'd allow
+    // access to page content, which we can't allow.
+    // "declarativeContent",
+
+    // Allow, but either (1) ask user for confirmation or (2) return blank
+    // capture.
+    // "desktopCapture",
+
+    // Haven't checked in detail what this does, but messing with devtools
+    // usually comes with the ability to access page content.
+    // "devtools",
+
+    // I think it's fine to allow this as it should be obvious to users that
+    // scanning a document on the scanner will make it available to the
+    // organization (placing a document in the scanner implies user consent).
+    "documentScan",
+
+    // Doesn't allow access to file contents AFAICT, so should be fine.
+    "downloads",
+
+    // Triggers a file open for the download.
+    "downloads.open",
+
+    // Controls shelf visibility.
+    "downloads.shelf",
+
+    "enterprise.deviceAttributes",
+
+    "enterprise.platformKeys",
+
+    // Possibly risky due to its experimental nature: not vetted for security,
+    // potentially buggy, subject to change without notice (shouldn't
+    // blanket-allow experimental stuff).
+    // "experimental",
+
+    "fileBrowserHandler",
+
+    // Allow: (1) session state is ephemeral anyways, so no leaks across users.
+    // (2) a user that stores data on an org-owned machine won't be surprised if
+    // the org can see it.
+    "fileSystem",
+
+    "fileSystem.directory",
+
+    "fileSystem.requestFileSystem",
+
+    "fileSystem.retainEntries",
+
+    "fileSystem.write",
+
+    "fileSystemProvider",
+
+    "fontSettings",
 
     // Just another type of connectivity.  On the system side, no user data is
     // involved, implicitly or explicity.
     "gcm",
 
-    // Risky: Accessing location without explicit user consent.
-    // "geolocation",
+    // It's fair game for a kiosk device owner to locate their device. Could
+    // just as well do this via IP-geolocation mechanism, so little difference.
+    "geolocation",
 
-    // Risky: Potentially allows keylogging.
-    // "hid",
+    // Somewhat risky as this opens up the ability to intercept user input.
+    // However, keyboards and mice are apparently not surfaced via this API.
+    "hid",
+
+    // Just URLs and meta data.
+    "history",
+
+    // Not really useful as there's no signed-in user, so OK to allow.
+    "identity",
+
+    "identity.email",
 
     // Detection of idle state.
     "idle",
 
-    // Dev channel only.  Not evaluated.
-    // "location",
+    // IME extensions see keystrokes. This might be useful though, might rely on
+    // manual whitelisting (assuming the number of useful IME extensions is
+    // relatively limited).
+    // "input",
+
+    // Fair game - admin can manipulate extensions via policy anyways.
+    "management",
 
     // Just another type of connectivity.
     "mdns",
 
-    // Risky: The "allAutoDectected" option could allow access to user data
-    // without their consent.
-    // "mediaGalleries",
+    // Storage is ephemeral, so user needs to get their content onto the Kiosk
+    // device (download or plug in media), both of which seem sufficient consent
+    // actions.
+    "mediaGalleries",
 
-    // Potentially risky: Could be used to spoof system UI.
-    // "notifications",
+    "mediaGalleries.allAutoDetected",
 
-    // TBD.  Could allow UX spoofing.
-    // "pointerLock",
+    "mediaGalleries.copyTo",
+
+    "mediaGalleries.delete",
+
+    "mediaGalleries.read",
+
+    // Probably doesn't work on Chrome OS anyways.
+    "nativeMessaging",
+
+    // Admin controls network connectivity anyways.
+    "networking.config",
+
+    // Status quo considers this risky due to the ability to fake system UI -
+    // low risk IMHO however since notifications are already badged with app
+    // icon and won't extract any data.
+    "notifications",
+
+    // Captures page content, so block. Alternatively: Allow, but either (1)
+    // prompt user or (2) return blank content.
+    // "pageCapture",
+
+    // Allows to use machine crypto keys - these would be provisioned by the
+    // admin anyways.
+    "platformKeys",
+
+    // No plugins on Chrome OS anyways.
+    "plugin",
+
+    // Status quo notes concern about UX spoofing - not an issue IMHO.
+    "pointerLock",
 
     // Potentiall risky: chrome.power.requestKeepAwake can inhibit idle time
     // detection and prevent idle time logout and that way reduce isolation
     // between subsequent Public Session users.
+    // OK to allow as long as it doesn't affect PS idle time detection.
     // "power",
 
-    // Risky: Could be used to siphon printed documents.
-    // "printerProvider",
+    // Printing initiated by user anyways, which provides consent gesture.
+    "printerProvider",
+
+    // The settings exposed via the API are under admin policy control anyways.
+    "privacy",
+
+    // Admin controls network anyways.
+    "proxy",
+
+    "runtime",
+
+    // Looking at the code, this feature is declared but used nowhere.
+    // "screensaver",
 
     // Access serial port.  It's hard to conceive a case in which private data
     // is stored on a serial device and being read without the user's consent.
+    // Minor risk of intercepting input events from serial input devices - given
+    // that serial input devices are exceedingly rare, OK to allow.
     "serial",
 
+    // Access to URLs.
+    "sessions",
+
+    "socket",
+
     // Per-app sandbox.  User cannot log into Public Session, thus storage
     // cannot be sync'ed to the cloud.
     "storage",
 
-    // Access system parameters.
+    // Not very useful since no signed-in user.
+    "syncFileSystem",
+
+    // Returns CPU parameters.
     "system.cpu",
 
-    // Access system parameters.
+    // Display parameters query/manipulation.
     "system.display",
 
-    // Access system parameters.
+    // Memory parameters access.
     "system.memory",
 
-    // Access system parameters.
+    // Enumerates network interfaces.
     "system.network",
 
-    // Risky: Could leak the name of a user-supplied storage medium.
-    // "system.storage",
+    // Enumerates removable storage.
+    "system.storage",
 
-    // Just UX.
+    // Provides access to screen contents, so block. Alternatively, (1) prompt
+    // for user consent or (2) return blank capture.
+    // "tabCapture",
+
+    // URLs and page titles.
+    "tabs",
+
+    // URLs and page titles.
+    "topSites",
+
+    // Allows to generate TTS, but no content access. Just UX.
     "tts",
 
+    // Might need this, but has content access. Manual whitelisting?
+    // "ttsEngine",
+
     // Excessive resource usage is not a risk.
     "unlimitedStorage",
 
-    // Risky: Raw peripheral access could allow an app to read user data from
-    // USB storage devices that have been plugged in by the user.  Not sure if
-    // that can happen though, because the system might claim storage devices
-    // for itself.  Still, leaving disallowed for now to be on the safe side.
-    // "usb",
+    // Plugging the USB device is sufficient as consent gesture.
+    "usb",
 
-    // TBD: What if one user connects and the next one is unaware of that?
-    // "vpnProvider",
+    // Belongs to the USB API.
+    "usbDevices",
+
+    // Need to surface notification to the user. Check what existing UI we have
+    // and whether that's sufficient for PS.
+    // "videoCapture",
+
+    // Admin controls network config anyways.
+    "vpnProvider",
 
     // Just UX.
     "wallpaper",
 
-    // Web capabilities are safe.
+    // Access to URLs.
+    "webNavigation",
+
+    // Provides access to cookies and form upload data. Options: (1) block,
+    // (2) strip all content in events.
+    // "webRequest",
+
+    // Fine once webRequest is adjusted.
+    // "webRequestBlocking",
+
+    // This allows content scripts and capturing. However, the webview runs
+    // within a separate storage partition, i.e. doesn't share cookies and other
+    // storage with the browsing session. Furthermore, the embedding app could
+    // just as well proxy 3rd-party origin content through its own web origin
+    // server-side or via chrome.socket. Finally, web security doesn't make a
+    // lot of sense when there's no URL bar or HTTPS padlock providing trusted
+    // UI. Bottom line: Risks are mitigated, further restrictions don't make
+    // sense, so OK to allow.
     "webview",
 };
 
@@ -717,6 +899,7 @@
       return true;
     }
 
+    // TODO(isandrk): Remove when whitelisting work is done (crbug/651027).
     // Allow extension if its type is whitelisted for use in public sessions.
     if (extension->GetType() == extensions::Manifest::TYPE_HOSTED_APP) {
       return true;
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
index da28470..97cb50e 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.cc
@@ -501,6 +501,7 @@
     content::ResourceContext* resource_context,
     bool is_content_initiated,
     bool must_download,
+    bool is_new_request,
     ScopedVector<content::ResourceThrottle>* throttles) {
   const content::ResourceRequestInfo* info =
         content::ResourceRequestInfo::ForRequest(request);
@@ -516,9 +517,9 @@
         request->url(), request->method()));
   }
 
-  // If this isn't a new request, we've seen this before and added the standard
-  //  resource throttles already so no need to add it again.
-  if (!request->is_pending()) {
+  // If this isn't a new request, the standard resource throttles have already
+  // been added, so no need to add them again.
+  if (is_new_request) {
     AppendStandardResourceThrottles(request,
                                     resource_context,
                                     content::RESOURCE_TYPE_MAIN_FRAME,
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h
index 001be0ea..b730ddbb 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate.h
@@ -58,6 +58,7 @@
       content::ResourceContext* resource_context,
       bool is_content_initiated,
       bool must_download,
+      bool is_new_request,
       ScopedVector<content::ResourceThrottle>* throttles) override;
   content::ResourceDispatcherHostLoginDelegate* CreateLoginDelegate(
       net::AuthChallengeInfo* auth_info,
@@ -103,6 +104,14 @@
   static void SetExternalProtocolHandlerDelegateForTesting(
       ExternalProtocolHandler::Delegate* delegate);
 
+ protected:
+  // Virtual for testing.
+  virtual void AppendStandardResourceThrottles(
+      net::URLRequest* request,
+      content::ResourceContext* resource_context,
+      content::ResourceType resource_type,
+      ScopedVector<content::ResourceThrottle>* throttles);
+
  private:
 #if defined(ENABLE_EXTENSIONS)
   struct StreamTargetInfo {
@@ -111,12 +120,6 @@
   };
 #endif
 
-  void AppendStandardResourceThrottles(
-      net::URLRequest* request,
-      content::ResourceContext* resource_context,
-      content::ResourceType resource_type,
-      ScopedVector<content::ResourceThrottle>* throttles);
-
   scoped_refptr<DownloadRequestLimiter> download_request_limiter_;
   scoped_refptr<safe_browsing::SafeBrowsingService> safe_browsing_;
 #if defined(ENABLE_EXTENSIONS)
diff --git a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
index cda953f8..ebf2a250 100644
--- a/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
+++ b/chrome/browser/loader/chrome_resource_dispatcher_host_delegate_browsertest.cc
@@ -11,20 +11,25 @@
 #include <utility>
 #include <vector>
 
+#include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/command_line.h"
+#include "base/files/scoped_temp_dir.h"
 #include "base/macros.h"
 #include "base/path_service.h"
+#include "base/run_loop.h"
 #include "base/stl_util.h"
 #include "base/strings/string_util.h"
 #include "base/test/scoped_command_line.h"
 #include "chrome/browser/browser_process.h"
+#include "chrome/browser/download/download_browsertest.h"
 #include "chrome/browser/loader/chrome_navigation_data.h"
 #include "chrome/browser/policy/cloud/policy_header_service_factory.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_paths.h"
+#include "chrome/common/pref_names.h"
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/ui_test_utils.h"
 #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h"
@@ -36,6 +41,8 @@
 #include "components/signin/core/browser/signin_header_helper.h"
 #include "components/signin/core/common/signin_pref_names.h"
 #include "components/signin/core/common/signin_switches.h"
+#include "content/public/browser/browser_context.h"
+#include "content/public/browser/browser_thread.h"
 #include "content/public/browser/navigation_data.h"
 #include "content/public/browser/navigation_handle.h"
 #include "content/public/browser/resource_dispatcher_host.h"
@@ -56,6 +63,7 @@
 using testing::Not;
 
 namespace {
+
 static const char kTestPolicyHeader[] = "test_header";
 static const char kServerRedirectUrl[] = "/server-redirect";
 
@@ -87,6 +95,7 @@
   TestDispatcherHostDelegate() : should_add_data_reduction_proxy_data_(false) {}
   ~TestDispatcherHostDelegate() override {}
 
+  // ResourceDispatcherHostDelegate implementation:
   void RequestBeginning(
       net::URLRequest* request,
       content::ResourceContext* resource_context,
@@ -125,10 +134,40 @@
     return ChromeResourceDispatcherHostDelegate::GetNavigationData(request);
   }
 
+  // ChromeResourceDispatcherHost implementation:
+  void AppendStandardResourceThrottles(
+      net::URLRequest* request,
+      content::ResourceContext* resource_context,
+      content::ResourceType resource_type,
+      ScopedVector<content::ResourceThrottle>* throttles) override {
+    ++times_stardard_throttles_added_for_url_[request->url()];
+    ChromeResourceDispatcherHostDelegate::AppendStandardResourceThrottles(
+        request, resource_context, resource_type, throttles);
+  }
+
+  void set_should_add_data_reduction_proxy_data(
+      bool should_add_data_reduction_proxy_data) {
+    should_add_data_reduction_proxy_data_ =
+        should_add_data_reduction_proxy_data;
+  }
+
+  const net::HttpRequestHeaders& request_headers() const {
+    return request_headers_;
+  }
+
+  // Writes the number of times the standard set of throttles have been added
+  // for requests for the speficied URL to |count|.
+  void GetTimesStandardThrottlesAddedForURL(const GURL& url, int* count) {
+    DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
+    *count = times_stardard_throttles_added_for_url_[url];
+  }
+
+ private:
   bool should_add_data_reduction_proxy_data_;
   net::HttpRequestHeaders request_headers_;
 
- private:
+  std::map<GURL, int> times_stardard_throttles_added_for_url_;
+
   DISALLOW_COPY_AND_ASSIGN(TestDispatcherHostDelegate);
 };
 
@@ -194,6 +233,11 @@
       (*it)->SetServerURLForTest(dm_url_.spec());
       (*it)->UpdateHeader(kTestPolicyHeader);
     }
+
+    // Set up temp directory for downloads.
+    ASSERT_TRUE(downloads_directory_.CreateUniqueTempDir());
+    browser()->profile()->GetPrefs()->SetFilePath(
+        prefs::kDownloadDefaultDirectory, downloads_directory_.GetPath());
   }
 
   void TearDownOnMainThread() override {
@@ -202,14 +246,32 @@
   }
 
   void SetShouldAddDataReductionProxyData(bool add_data) {
-    dispatcher_host_delegate_->should_add_data_reduction_proxy_data_ = add_data;
+    dispatcher_host_delegate_->set_should_add_data_reduction_proxy_data(
+        add_data);
+  }
+
+  int GetTimesStandardThrottlesAddedForURL(const GURL& url) {
+    int count;
+    base::RunLoop run_loop;
+    content::BrowserThread::PostTaskAndReply(
+        content::BrowserThread::IO, FROM_HERE,
+        base::Bind(
+            &TestDispatcherHostDelegate::GetTimesStandardThrottlesAddedForURL,
+            base::Unretained(dispatcher_host_delegate_.get()), url, &count),
+        run_loop.QuitClosure());
+    run_loop.Run();
+    return count;
   }
 
  protected:
   // The fake URL for DMServer we are using.
   GURL dm_url_;
   std::unique_ptr<TestDispatcherHostDelegate> dispatcher_host_delegate_;
+
  private:
+  // Location of the downloads directory for tests that use one.
+  base::ScopedTempDir downloads_directory_;
+
   DISALLOW_COPY_AND_ASSIGN(ChromeResourceDispatcherHostDelegateBrowserTest);
 };
 
@@ -220,7 +282,7 @@
   // request.
   DCHECK(!embedded_test_server()->base_url().spec().empty());
   ui_test_utils::NavigateToURL(browser(), embedded_test_server()->base_url());
-  ASSERT_FALSE(dispatcher_host_delegate_->request_headers_.HasHeader(
+  ASSERT_FALSE(dispatcher_host_delegate_->request_headers().HasHeader(
       policy::kChromePolicyHeader));
 }
 
@@ -230,7 +292,7 @@
   // request.
   ui_test_utils::NavigateToURL(browser(), dm_url_);
   std::string value;
-  ASSERT_TRUE(dispatcher_host_delegate_->request_headers_.GetHeader(
+  ASSERT_TRUE(dispatcher_host_delegate_->request_headers().GetHeader(
       policy::kChromePolicyHeader, &value));
   ASSERT_EQ(kTestPolicyHeader, value);
 }
@@ -247,7 +309,7 @@
   ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(
       redirect_url));
   std::string value;
-  ASSERT_TRUE(dispatcher_host_delegate_->request_headers_.GetHeader(
+  ASSERT_TRUE(dispatcher_host_delegate_->request_headers().GetHeader(
       policy::kChromePolicyHeader, &value));
   ASSERT_EQ(kTestPolicyHeader, value);
 }
@@ -531,3 +593,46 @@
     }
   }
 }
+
+// Check that exactly one set of throttles is added to smaller downloads, which
+// have their mime type determined only after the response is completely
+// received.
+// See https://crbug.com/640545
+IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
+                       ThrottlesAddedExactlyOnceToTinySniffedDownloads) {
+  GURL url = embedded_test_server()->GetURL("/downloads/tiny_binary.bin");
+  DownloadTestObserverNotInProgress download_observer(
+      content::BrowserContext::GetDownloadManager(browser()->profile()), 1);
+  download_observer.StartObserving();
+  ui_test_utils::NavigateToURL(browser(), url);
+  download_observer.WaitForFinished();
+  EXPECT_EQ(1, GetTimesStandardThrottlesAddedForURL(url));
+}
+
+// Check that exactly one set of throttles is added to larger downloads, which
+// have their mime type determined before the end of the response is reported.
+IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
+                       ThrottlesAddedExactlyOnceToLargeSniffedDownloads) {
+  GURL url = embedded_test_server()->GetURL("/downloads/thisdayinhistory.xls");
+  DownloadTestObserverNotInProgress download_observer(
+      content::BrowserContext::GetDownloadManager(browser()->profile()), 1);
+  download_observer.StartObserving();
+  ui_test_utils::NavigateToURL(browser(), url);
+  download_observer.WaitForFinished();
+  EXPECT_EQ(1, GetTimesStandardThrottlesAddedForURL(url));
+}
+
+// Check that exactly one set of throttles is added to downloads started by an
+// <a download> click.
+IN_PROC_BROWSER_TEST_F(ChromeResourceDispatcherHostDelegateBrowserTest,
+                       ThrottlesAddedExactlyOnceToADownloads) {
+  DownloadTestObserverNotInProgress download_observer(
+      content::BrowserContext::GetDownloadManager(browser()->profile()), 1);
+  download_observer.StartObserving();
+  ui_test_utils::NavigateToURL(browser(), embedded_test_server()->GetURL(
+                                              "/download-anchor-attrib.html"));
+  download_observer.WaitForFinished();
+  EXPECT_EQ(1,
+            GetTimesStandardThrottlesAddedForURL(
+                embedded_test_server()->GetURL("/anchor_download_test.png")));
+}
diff --git a/chrome/browser/plugins/plugin_info_message_filter.cc b/chrome/browser/plugins/plugin_info_message_filter.cc
index b1ea5b4..b8cc37a 100644
--- a/chrome/browser/plugins/plugin_info_message_filter.cc
+++ b/chrome/browser/plugins/plugin_info_message_filter.cc
@@ -365,7 +365,9 @@
   }
 #endif  // defined(ENABLE_EXTENSIONS)
 
-  if (plugin_setting == CONTENT_SETTING_DETECT_IMPORTANT_CONTENT) {
+  if (plugin_setting == CONTENT_SETTING_DETECT_IMPORTANT_CONTENT ||
+      (plugin_setting == CONTENT_SETTING_ALLOW &&
+       base::FeatureList::IsEnabled(features::kPreferHtmlOverPlugins))) {
     *status = ChromeViewHostMsg_GetPluginInfo_Status::kPlayImportantContent;
   } else if (plugin_setting == CONTENT_SETTING_BLOCK) {
     // For managed users with the ASK policy, we allow manually running plugins
diff --git a/chrome/browser/plugins/plugin_power_saver_browsertest.cc b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
index 6cb3bd6..63136c54 100644
--- a/chrome/browser/plugins/plugin_power_saver_browsertest.cc
+++ b/chrome/browser/plugins/plugin_power_saver_browsertest.cc
@@ -12,6 +12,7 @@
 #include "base/strings/stringprintf.h"
 #include "base/test/scoped_feature_list.h"
 #include "build/build_config.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/ui/browser.h"
 #include "chrome/browser/ui/browser_window.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
@@ -20,6 +21,7 @@
 #include "chrome/test/base/in_process_browser_test.h"
 #include "chrome/test/base/test_switches.h"
 #include "chrome/test/base/ui_test_utils.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/zoom/zoom_controller.h"
 #include "content/public/browser/readback_types.h"
 #include "content/public/browser/render_frame_host.h"
@@ -312,6 +314,14 @@
         GetActiveWebContents()->GetMainFrame()));
   }
 
+  // Loads a peripheral plugin (small cross origin) named 'plugin'.
+  void LoadPeripheralPlugin() {
+    LoadHTML(
+        "<object id='plugin' data='http://otherorigin.com/fake.swf' "
+        "    type='application/x-shockwave-flash' width='400' height='100'>"
+        "</object>");
+  }
+
   // Returns the background WebContents.
   content::WebContents* LoadHTMLInBackgroundTab(const std::string& html) {
     embedded_test_server()->RegisterRequestHandler(
@@ -457,6 +467,23 @@
   SimulateClickAndAwaitMarkedEssential("plugin_poster", gfx::Point(50, 150));
 }
 
+IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, ContentSettings) {
+  HostContentSettingsMap* content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+
+  // Throttle on DETECT.
+  content_settings_map->SetDefaultContentSetting(
+      CONTENT_SETTINGS_TYPE_PLUGINS, CONTENT_SETTING_DETECT_IMPORTANT_CONTENT);
+  LoadPeripheralPlugin();
+  VerifyPluginIsThrottled(GetActiveWebContents(), "plugin");
+
+  // Don't throttle on ALLOW.
+  content_settings_map->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
+                                                 CONTENT_SETTING_ALLOW);
+  LoadPeripheralPlugin();
+  VerifyPluginMarkedEssential(GetActiveWebContents(), "plugin");
+}
+
 IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, SmallerThanPlayIcon) {
   LoadHTML(
       "<object id='plugin_16' type='application/x-shockwave-flash' "
@@ -622,10 +649,7 @@
 }
 
 IN_PROC_BROWSER_TEST_F(PluginPowerSaverBrowserTest, ExpandingSmallPlugin) {
-  LoadHTML(
-      "<object id='plugin' data='http://otherorigin.com/fake.swf' "
-      "    type='application/x-shockwave-flash' width='400' height='80'>"
-      "</object>");
+  LoadPeripheralPlugin();
   VerifyPluginIsThrottled(GetActiveWebContents(), "plugin");
 
   std::string script = "window.document.getElementById('plugin').height = 400;";
@@ -738,3 +762,27 @@
   VerifyPluginMarkedEssential(GetActiveWebContents(), "tiny_cross_origin_1");
   VerifyPluginMarkedEssential(GetActiveWebContents(), "tiny_cross_origin_2");
 }
+
+// Separate test case with HTML By Default feature flag on.
+class PluginPowerSaverPreferHtmlBrowserTest
+    : public PluginPowerSaverBrowserTest {
+ public:
+  void SetUpInProcessBrowserTestFixture() override {
+    PluginPowerSaverBrowserTest::SetUpInProcessBrowserTestFixture();
+    feature_list.InitAndEnableFeature(features::kPreferHtmlOverPlugins);
+  }
+
+ private:
+  base::test::ScopedFeatureList feature_list;
+};
+
+IN_PROC_BROWSER_TEST_F(PluginPowerSaverPreferHtmlBrowserTest,
+                       ThrottlePluginsOnAllowContentSetting) {
+  HostContentSettingsMap* content_settings_map =
+      HostContentSettingsMapFactory::GetForProfile(browser()->profile());
+
+  content_settings_map->SetDefaultContentSetting(CONTENT_SETTINGS_TYPE_PLUGINS,
+                                                 CONTENT_SETTING_ALLOW);
+  LoadPeripheralPlugin();
+  VerifyPluginIsThrottled(GetActiveWebContents(), "plugin");
+}
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.cc b/chrome/browser/predictors/resource_prefetch_predictor.cc
index b34cd78..bc80138 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor.cc
@@ -10,6 +10,7 @@
 
 #include "base/command_line.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/strings/string_number_conversions.h"
@@ -23,7 +24,6 @@
 #include "chrome/common/chrome_switches.h"
 #include "chrome/common/url_constants.h"
 #include "components/history/core/browser/history_database.h"
-#include "components/history/core/browser/history_db_task.h"
 #include "components/history/core/browser/history_service.h"
 #include "components/mime_util/mime_util.h"
 #include "content/public/browser/browser_thread.h"
@@ -66,52 +66,6 @@
 namespace predictors {
 
 ////////////////////////////////////////////////////////////////////////////////
-// History lookup task.
-
-// Used to fetch the visit count for a URL from the History database.
-class GetUrlVisitCountTask : public history::HistoryDBTask {
- public:
-  typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
-  typedef base::Callback<void(
-      size_t,   // Visit count.
-      const NavigationID&,
-      const std::vector<URLRequestSummary>&)> VisitInfoCallback;
-
-  GetUrlVisitCountTask(
-      const NavigationID& navigation_id,
-      std::vector<URLRequestSummary>* requests,
-      VisitInfoCallback callback)
-      : visit_count_(0),
-        navigation_id_(navigation_id),
-        requests_(requests),
-        callback_(callback) {
-    DCHECK(requests_.get());
-  }
-
-  bool RunOnDBThread(history::HistoryBackend* backend,
-                     history::HistoryDatabase* db) override {
-    history::URLRow url_row;
-    if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row))
-      visit_count_ = url_row.visit_count();
-    return true;
-  }
-
-  void DoneRunOnMainThread() override {
-    callback_.Run(visit_count_, navigation_id_, *requests_);
-  }
-
- private:
-  ~GetUrlVisitCountTask() override {}
-
-  int visit_count_;
-  NavigationID navigation_id_;
-  std::unique_ptr<std::vector<URLRequestSummary>> requests_;
-  VisitInfoCallback callback_;
-
-  DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask);
-};
-
-////////////////////////////////////////////////////////////////////////////////
 // ResourcePrefetchPredictor static functions.
 
 // static
@@ -257,7 +211,7 @@
 }
 
 ////////////////////////////////////////////////////////////////////////////////
-// ResourcePrefetchPredictor structs.
+// ResourcePrefetchPredictor nested types.
 
 ResourcePrefetchPredictor::URLRequestSummary::URLRequestSummary()
     : resource_type(content::RESOURCE_TYPE_LAST_TYPE),
@@ -318,6 +272,38 @@
   return true;
 }
 
+ResourcePrefetchPredictor::GetUrlVisitCountTask::GetUrlVisitCountTask(
+    const NavigationID& navigation_id,
+    std::unique_ptr<PageRequestSummary> summary,
+    VisitInfoCallback callback)
+    : visit_count_(0),
+      navigation_id_(navigation_id),
+      summary_(std::move(summary)),
+      callback_(callback) {
+  DCHECK(summary_.get());
+}
+
+bool ResourcePrefetchPredictor::GetUrlVisitCountTask::RunOnDBThread(
+    history::HistoryBackend* backend,
+    history::HistoryDatabase* db) {
+  history::URLRow url_row;
+  if (db->GetRowForURL(navigation_id_.main_frame_url, &url_row))
+    visit_count_ = url_row.visit_count();
+  return true;
+}
+
+void ResourcePrefetchPredictor::GetUrlVisitCountTask::DoneRunOnMainThread() {
+  callback_.Run(visit_count_, navigation_id_, *summary_);
+}
+
+ResourcePrefetchPredictor::GetUrlVisitCountTask::~GetUrlVisitCountTask() {}
+
+ResourcePrefetchPredictor::PageRequestSummary::PageRequestSummary(
+    const GURL& i_initial_url)
+    : initial_url(i_initial_url) {}
+
+ResourcePrefetchPredictor::PageRequestSummary::~PageRequestSummary() {}
+
 ////////////////////////////////////////////////////////////////////////////////
 // ResourcePrefetchPredictor.
 
@@ -414,9 +400,10 @@
   CleanupAbandonedNavigations(request.navigation_id);
 
   // New empty navigation entry.
-  inflight_navigations_.insert(std::make_pair(
-      request.navigation_id,
-      make_linked_ptr(new std::vector<URLRequestSummary>())));
+  const GURL& initial_url = request.navigation_id.main_frame_url;
+  inflight_navigations_.insert(
+      std::make_pair(request.navigation_id,
+                     base::MakeUnique<PageRequestSummary>(initial_url)));
 }
 
 void ResourcePrefetchPredictor::OnMainFrameResponse(
@@ -432,27 +419,33 @@
     const URLRequestSummary& response) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
-  // TODO(shishir): There are significant gains to be had here if we can use the
-  // start URL in a redirect chain as the key to start prefetching. We can save
-  // of redirect times considerably assuming that the redirect chains do not
-  // change.
-
   // Stop any inflight prefetching. Remove the older navigation.
   StopPrefetching(response.navigation_id);
-  inflight_navigations_.erase(response.navigation_id);
 
-  // A redirect will not lead to another OnMainFrameRequest call, so record the
-  // redirect url as a new navigation.
+  std::unique_ptr<PageRequestSummary> summary;
+  NavigationMap::iterator nav_it =
+      inflight_navigations_.find(response.navigation_id);
+  if (nav_it != inflight_navigations_.end()) {
+    summary.reset(nav_it->second.release());
+    inflight_navigations_.erase(nav_it);
+  }
 
   // The redirect url may be empty if the URL was invalid.
   if (response.redirect_url.is_empty())
     return;
 
+  // If we lost the information about the first hop for some reason.
+  if (!summary) {
+    const GURL& initial_url = response.navigation_id.main_frame_url;
+    summary = base::MakeUnique<PageRequestSummary>(initial_url);
+  }
+
+  // A redirect will not lead to another OnMainFrameRequest call, so record the
+  // redirect url as a new navigation id and save the initial url.
   NavigationID navigation_id(response.navigation_id);
   navigation_id.main_frame_url = response.redirect_url;
-  inflight_navigations_.insert(std::make_pair(
-      navigation_id,
-      make_linked_ptr(new std::vector<URLRequestSummary>())));
+  inflight_navigations_.insert(
+      std::make_pair(navigation_id, std::move(summary)));
 }
 
 void ResourcePrefetchPredictor::OnSubresourceResponse(
@@ -465,7 +458,7 @@
     return;
   }
 
-  nav_it->second->push_back(response);
+  nav_it->second->subresource_requests.push_back(response);
 }
 
 void ResourcePrefetchPredictor::OnNavigationComplete(
@@ -480,7 +473,7 @@
   const NavigationID navigation_id(nav_it->first);
 
   // Remove the navigation from the inflight navigations.
-  std::vector<URLRequestSummary>* requests = (nav_it->second).release();
+  std::unique_ptr<PageRequestSummary> summary = std::move(nav_it->second);
   inflight_navigations_.erase(nav_it);
 
   // Kick off history lookup to determine if we should record the URL.
@@ -490,7 +483,7 @@
   DCHECK(history_service);
   history_service->ScheduleDBTask(
       std::unique_ptr<history::HistoryDBTask>(new GetUrlVisitCountTask(
-          navigation_id, requests,
+          navigation_id, std::move(summary),
           base::Bind(&ResourcePrefetchPredictor::OnVisitCountLookup,
                      AsWeakPtr()))),
       &history_lookup_consumer_);
@@ -586,31 +579,40 @@
   initialization_state_ = INITIALIZING;
 
   // Create local caches using the database as loaded.
-  std::unique_ptr<PrefetchDataMap> url_data_map(new PrefetchDataMap());
-  std::unique_ptr<PrefetchDataMap> host_data_map(new PrefetchDataMap());
-  PrefetchDataMap* url_data_ptr = url_data_map.get();
-  PrefetchDataMap* host_data_ptr = host_data_map.get();
+  auto url_data_map = base::MakeUnique<PrefetchDataMap>();
+  auto host_data_map = base::MakeUnique<PrefetchDataMap>();
+  auto url_redirect_data_map = base::MakeUnique<RedirectDataMap>();
+  auto host_redirect_data_map = base::MakeUnique<RedirectDataMap>();
 
   BrowserThread::PostTaskAndReply(
       BrowserThread::DB, FROM_HERE,
-      base::Bind(&ResourcePrefetchPredictorTables::GetAllData,
-                 tables_, url_data_ptr, host_data_ptr),
+      base::Bind(&ResourcePrefetchPredictorTables::GetAllData, tables_,
+                 url_data_map.get(), host_data_map.get(),
+                 url_redirect_data_map.get(), host_redirect_data_map.get()),
       base::Bind(&ResourcePrefetchPredictor::CreateCaches, AsWeakPtr(),
-                 base::Passed(&url_data_map), base::Passed(&host_data_map)));
+                 base::Passed(&url_data_map), base::Passed(&host_data_map),
+                 base::Passed(&url_redirect_data_map),
+                 base::Passed(&host_redirect_data_map)));
 }
 
 void ResourcePrefetchPredictor::CreateCaches(
     std::unique_ptr<PrefetchDataMap> url_data_map,
-    std::unique_ptr<PrefetchDataMap> host_data_map) {
+    std::unique_ptr<PrefetchDataMap> host_data_map,
+    std::unique_ptr<RedirectDataMap> url_redirect_data_map,
+    std::unique_ptr<RedirectDataMap> host_redirect_data_map) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   DCHECK_EQ(INITIALIZING, initialization_state_);
   DCHECK(!url_table_cache_);
   DCHECK(!host_table_cache_);
+  DCHECK(!url_redirect_table_cache_);
+  DCHECK(!host_redirect_table_cache_);
   DCHECK(inflight_navigations_.empty());
 
   url_table_cache_ = std::move(url_data_map);
   host_table_cache_ = std::move(host_data_map);
+  url_redirect_table_cache_ = std::move(url_redirect_data_map);
+  host_redirect_table_cache_ = std::move(host_redirect_data_map);
 
   UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.UrlTableMainFrameUrlCount",
                        url_table_cache_->size());
@@ -653,6 +655,8 @@
   inflight_navigations_.clear();
   url_table_cache_->clear();
   host_table_cache_->clear();
+  url_redirect_table_cache_->clear();
+  host_redirect_table_cache_->clear();
 
   BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
       base::Bind(&ResourcePrefetchPredictorTables::DeleteAllData, tables_));
@@ -662,6 +666,7 @@
   // Check all the urls in the database and pick out the ones that are present
   // in the cache.
   std::vector<std::string> urls_to_delete, hosts_to_delete;
+  std::vector<std::string> url_redirects_to_delete, host_redirects_to_delete;
 
   for (const auto& it : urls) {
     const std::string& url_spec = it.url().spec();
@@ -670,19 +675,37 @@
       url_table_cache_->erase(url_spec);
     }
 
+    if (url_redirect_table_cache_->find(url_spec) !=
+        url_redirect_table_cache_->end()) {
+      url_redirects_to_delete.push_back(url_spec);
+      url_redirect_table_cache_->erase(url_spec);
+    }
+
     const std::string& host = it.url().host();
     if (host_table_cache_->find(host) != host_table_cache_->end()) {
       hosts_to_delete.push_back(host);
       host_table_cache_->erase(host);
     }
+
+    if (host_redirect_table_cache_->find(host) !=
+        host_redirect_table_cache_->end()) {
+      host_redirects_to_delete.push_back(host);
+      host_redirect_table_cache_->erase(host);
+    }
   }
 
   if (!urls_to_delete.empty() || !hosts_to_delete.empty()) {
-    BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
-        base::Bind(&ResourcePrefetchPredictorTables::DeleteData,
-                   tables_,
-                   urls_to_delete,
-                   hosts_to_delete));
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
+        base::Bind(&ResourcePrefetchPredictorTables::DeleteResourceData,
+                   tables_, urls_to_delete, hosts_to_delete));
+  }
+
+  if (!url_redirects_to_delete.empty() || !host_redirects_to_delete.empty()) {
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
+        base::Bind(&ResourcePrefetchPredictorTables::DeleteRedirectData,
+                   tables_, url_redirects_to_delete, host_redirects_to_delete));
   }
 }
 
@@ -703,23 +726,49 @@
   }
 
   data_map->erase(key_to_delete);
-    BrowserThread::PostTask(BrowserThread::DB, FROM_HERE,
-        base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint,
-                   tables_,
-                   key_to_delete,
-                   key_type));
+  BrowserThread::PostTask(
+      BrowserThread::DB, FROM_HERE,
+      base::Bind(
+          &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint,
+          tables_, key_to_delete, key_type));
+}
+
+void ResourcePrefetchPredictor::RemoveOldestEntryInRedirectDataMap(
+    PrefetchKeyType key_type,
+    RedirectDataMap* data_map) {
+  if (data_map->empty())
+    return;
+
+  uint64_t oldest_time = UINT64_MAX;
+  std::string key_to_delete;
+  for (const auto& kv : *data_map) {
+    const RedirectData& data = kv.second;
+    if (key_to_delete.empty() || data.last_visit_time() < oldest_time) {
+      key_to_delete = data.primary_key();
+      oldest_time = data.last_visit_time();
+    }
+  }
+
+  data_map->erase(key_to_delete);
+  BrowserThread::PostTask(
+      BrowserThread::DB, FROM_HERE,
+      base::Bind(
+          &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint,
+          tables_, key_to_delete, key_type));
 }
 
 void ResourcePrefetchPredictor::OnVisitCountLookup(
     size_t visit_count,
     const NavigationID& navigation_id,
-    const std::vector<URLRequestSummary>& requests) {
+    const PageRequestSummary& summary) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   UMA_HISTOGRAM_COUNTS("ResourcePrefetchPredictor.HistoryVisitCountForUrl",
                        visit_count);
 
-  // URL level data - merge only if we are already saving the data, or we it
+  // TODO(alexilin): make only one request to DB thread.
+
+  // URL level data - merge only if we already saved the data, or it
   // meets the cutoff requirement.
   const std::string url_spec = navigation_id.main_frame_url.spec();
   bool already_tracking = url_table_cache_->find(url_spec) !=
@@ -728,17 +777,19 @@
       (visit_count >= config_.min_url_visit_count);
 
   if (should_track_url && config_.IsURLLearningEnabled()) {
-    LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL, requests,
-                    config_.max_urls_to_track, url_table_cache_.get());
+    LearnNavigation(url_spec, PREFETCH_KEY_TYPE_URL,
+                    summary.subresource_requests, config_.max_urls_to_track,
+                    url_table_cache_.get(), summary.initial_url.spec(),
+                    url_redirect_table_cache_.get());
   }
 
   // Host level data - no cutoff, always learn the navigation if enabled.
   if (config_.IsHostLearningEnabled()) {
-    LearnNavigation(navigation_id.main_frame_url.host(),
-                    PREFETCH_KEY_TYPE_HOST,
-                    requests,
-                    config_.max_hosts_to_track,
-                    host_table_cache_.get());
+    const std::string host = navigation_id.main_frame_url.host();
+    LearnNavigation(host, PREFETCH_KEY_TYPE_HOST, summary.subresource_requests,
+                    config_.max_hosts_to_track, host_table_cache_.get(),
+                    summary.initial_url.host(),
+                    host_redirect_table_cache_.get());
   }
 }
 
@@ -747,7 +798,9 @@
     PrefetchKeyType key_type,
     const std::vector<URLRequestSummary>& new_resources,
     size_t max_data_map_size,
-    PrefetchDataMap* data_map) {
+    PrefetchDataMap* data_map,
+    const std::string& key_before_redirects,
+    RedirectDataMap* redirect_map) {
   DCHECK_CURRENTLY_ON(BrowserThread::UI);
 
   // If the primary key is too long reject it.
@@ -756,10 +809,9 @@
 
   PrefetchDataMap::iterator cache_entry = data_map->find(key);
   if (cache_entry == data_map->end()) {
-    if (data_map->size() >= max_data_map_size) {
-      // The table is full, delete an entry.
+    // If the table is full, delete an entry.
+    if (data_map->size() >= max_data_map_size)
       RemoveOldestEntryInPrefetchDataMap(key_type, data_map);
-    }
 
     cache_entry = data_map->insert(std::make_pair(
         key, PrefetchData(key_type, key))).first;
@@ -879,23 +931,111 @@
     data_map->erase(key);
     BrowserThread::PostTask(
         BrowserThread::DB, FROM_HERE,
-        base::Bind(&ResourcePrefetchPredictorTables::DeleteSingleDataPoint,
-                   tables_,
-                   key,
-                   key_type));
+        base::Bind(
+            &ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint,
+            tables_, key, key_type));
   } else {
     bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
     PrefetchData empty_data(
         !is_host ? PREFETCH_KEY_TYPE_HOST : PREFETCH_KEY_TYPE_URL,
         std::string());
+    RedirectData empty_redirect_data;
     const PrefetchData& host_data = is_host ? cache_entry->second : empty_data;
     const PrefetchData& url_data = is_host ? empty_data : cache_entry->second;
     BrowserThread::PostTask(
         BrowserThread::DB, FROM_HERE,
-        base::Bind(&ResourcePrefetchPredictorTables::UpdateData,
-                   tables_,
-                   url_data,
-                   host_data));
+        base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_,
+                   url_data, host_data, empty_redirect_data,
+                   empty_redirect_data));
+  }
+
+  if (key != key_before_redirects) {
+    LearnRedirect(key_before_redirects, key_type, key, max_data_map_size,
+                  redirect_map);
+  }
+}
+
+void ResourcePrefetchPredictor::LearnRedirect(const std::string& key,
+                                              PrefetchKeyType key_type,
+                                              const std::string& final_redirect,
+                                              size_t max_redirect_map_size,
+                                              RedirectDataMap* redirect_map) {
+  DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+  RedirectDataMap::iterator cache_entry = redirect_map->find(key);
+  if (cache_entry == redirect_map->end()) {
+    if (redirect_map->size() >= max_redirect_map_size)
+      RemoveOldestEntryInRedirectDataMap(key_type, redirect_map);
+
+    RedirectData new_data;
+    new_data.set_primary_key(key);
+    cache_entry = redirect_map->insert(std::make_pair(key, new_data)).first;
+    cache_entry->second.set_last_visit_time(
+        base::Time::Now().ToInternalValue());
+    RedirectStat* redirect_to_add =
+        cache_entry->second.add_redirect_endpoints();
+    redirect_to_add->set_url(final_redirect);
+    redirect_to_add->set_number_of_hits(1);
+  } else {
+    bool need_to_add = true;
+    cache_entry->second.set_last_visit_time(
+        base::Time::Now().ToInternalValue());
+
+    for (RedirectStat& redirect :
+         *(cache_entry->second.mutable_redirect_endpoints())) {
+      if (redirect.url() == final_redirect) {
+        need_to_add = false;
+        redirect.set_number_of_hits(redirect.number_of_hits() + 1);
+        redirect.set_consecutive_misses(0);
+      } else {
+        redirect.set_number_of_misses(redirect.number_of_misses() + 1);
+        redirect.set_consecutive_misses(redirect.consecutive_misses() + 1);
+      }
+    }
+
+    if (need_to_add) {
+      RedirectStat* redirect_to_add =
+          cache_entry->second.add_redirect_endpoints();
+      redirect_to_add->set_url(final_redirect);
+      redirect_to_add->set_number_of_hits(1);
+    }
+  }
+
+  // Trim and sort redirects after update.
+  std::vector<RedirectStat> redirects;
+  redirects.reserve(cache_entry->second.redirect_endpoints_size());
+  for (const RedirectStat& redirect :
+       cache_entry->second.redirect_endpoints()) {
+    if (redirect.consecutive_misses() < config_.max_consecutive_misses)
+      redirects.push_back(redirect);
+  }
+  ResourcePrefetchPredictorTables::SortRedirects(&redirects);
+
+  cache_entry->second.clear_redirect_endpoints();
+  for (const RedirectStat& redirect : redirects)
+    cache_entry->second.add_redirect_endpoints()->CopyFrom(redirect);
+
+  if (redirects.empty()) {
+    redirect_map->erase(cache_entry);
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
+        base::Bind(
+            &ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint,
+            tables_, key, key_type));
+  } else {
+    bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+    RedirectData empty_redirect_data;
+    PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string());
+    PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string());
+    const RedirectData& host_redirect_data =
+        is_host ? cache_entry->second : empty_redirect_data;
+    const RedirectData& url_redirect_data =
+        is_host ? empty_redirect_data : cache_entry->second;
+    BrowserThread::PostTask(
+        BrowserThread::DB, FROM_HERE,
+        base::Bind(&ResourcePrefetchPredictorTables::UpdateData, tables_,
+                   empty_url_data, empty_host_data, url_redirect_data,
+                   host_redirect_data));
   }
 }
 
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.h b/chrome/browser/predictors/resource_prefetch_predictor.h
index c3177cd..969cfb8 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor.h
@@ -9,12 +9,12 @@
 
 #include <map>
 #include <memory>
+#include <set>
 #include <string>
 #include <vector>
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
-#include "base/memory/linked_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "base/task/cancelable_task_tracker.h"
@@ -22,6 +22,7 @@
 #include "chrome/browser/predictors/resource_prefetch_common.h"
 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
 #include "chrome/browser/predictors/resource_prefetcher.h"
+#include "components/history/core/browser/history_db_task.h"
 #include "components/history/core/browser/history_service_observer.h"
 #include "components/history/core/browser/history_types.h"
 #include "components/keyed_service/core/keyed_service.h"
@@ -146,6 +147,8 @@
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, NavigationUrlNotInDB);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest,
                            NavigationUrlNotInDBAndDBFull);
+  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, RedirectUrlNotInDB);
+  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, RedirectUrlInDB);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, OnMainFrameRequest);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest, OnMainFrameRedirect);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTest,
@@ -159,9 +162,53 @@
     INITIALIZED = 2
   };
 
+  // Stores information about inflight navigations.
+  struct PageRequestSummary {
+    explicit PageRequestSummary(const GURL& initial_url);
+    ~PageRequestSummary();
+
+    GURL initial_url;
+
+    // Stores all subresources requests within a single navigation, from initial
+    // main frame request to navigation completion.
+    std::vector<URLRequestSummary> subresource_requests;
+  };
+
+  // Used to fetch the visit count for a URL from the History database.
+  class GetUrlVisitCountTask : public history::HistoryDBTask {
+   public:
+    typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
+    typedef ResourcePrefetchPredictor::PageRequestSummary PageRequestSummary;
+    typedef base::Callback<void(size_t,  // Visit count.
+                                const NavigationID&,
+                                const PageRequestSummary&)>
+        VisitInfoCallback;
+
+    GetUrlVisitCountTask(const NavigationID& navigation_id,
+                         std::unique_ptr<PageRequestSummary> summary,
+                         VisitInfoCallback callback);
+
+    bool RunOnDBThread(history::HistoryBackend* backend,
+                       history::HistoryDatabase* db) override;
+
+    void DoneRunOnMainThread() override;
+
+   private:
+    ~GetUrlVisitCountTask() override;
+
+    int visit_count_;
+    NavigationID navigation_id_;
+    std::unique_ptr<PageRequestSummary> summary_;
+    VisitInfoCallback callback_;
+
+    DISALLOW_COPY_AND_ASSIGN(GetUrlVisitCountTask);
+  };
+
   typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData;
   typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap;
-  typedef std::map<NavigationID, linked_ptr<std::vector<URLRequestSummary> > >
+  typedef ResourcePrefetchPredictorTables::RedirectDataMap RedirectDataMap;
+
+  typedef std::map<NavigationID, std::unique_ptr<PageRequestSummary>>
       NavigationMap;
 
   // Returns true if the main page request is supported for prediction.
@@ -216,9 +263,11 @@
   void StartInitialization();
 
   // Callback for task to read predictor database. Takes ownership of
-  // |url_data_map| and |host_data_map|.
+  // all arguments.
   void CreateCaches(std::unique_ptr<PrefetchDataMap> url_data_map,
-                    std::unique_ptr<PrefetchDataMap> host_data_map);
+                    std::unique_ptr<PrefetchDataMap> host_data_map,
+                    std::unique_ptr<RedirectDataMap> url_redirect_data_map,
+                    std::unique_ptr<RedirectDataMap> host_redirect_data_map);
 
   // Called during initialization when history is read and the predictor
   // database has been read.
@@ -239,25 +288,38 @@
   // Callback for GetUrlVisitCountTask.
   void OnVisitCountLookup(size_t visit_count,
                           const NavigationID& navigation_id,
-                          const std::vector<URLRequestSummary>& requests);
+                          const PageRequestSummary& summary);
 
   // Removes the oldest entry in the input |data_map|, also deleting it from the
   // predictor database.
   void RemoveOldestEntryInPrefetchDataMap(PrefetchKeyType key_type,
                                           PrefetchDataMap* data_map);
 
+  void RemoveOldestEntryInRedirectDataMap(PrefetchKeyType key_type,
+                                          RedirectDataMap* data_map);
+
   // Merges resources in |new_resources| into the |data_map| and correspondingly
-  // updates the predictor database.
+  // updates the predictor database. Also calls LearnRedirect if relevant.
   void LearnNavigation(const std::string& key,
                        PrefetchKeyType key_type,
                        const std::vector<URLRequestSummary>& new_resources,
                        size_t max_data_map_size,
-                       PrefetchDataMap* data_map);
+                       PrefetchDataMap* data_map,
+                       const std::string& key_before_redirects,
+                       RedirectDataMap* redirect_map);
+
+  // Updates information about final redirect destination for |key| in
+  // |redirect_map| and correspondingly updates the predictor database.
+  void LearnRedirect(const std::string& key,
+                     PrefetchKeyType key_type,
+                     const std::string& final_redirect,
+                     size_t max_redirect_map_size,
+                     RedirectDataMap* redirect_map);
 
   // Reports overall page load time.
   void ReportPageLoadTimeStats(base::TimeDelta plt) const;
 
-  // Reports page load time for prefetched and not prefetched pages
+  // Reports page load time for prefetched and not prefetched pages.
   void ReportPageLoadTimePrefetchStats(
       base::TimeDelta plt,
       bool prefetched,
@@ -289,12 +351,13 @@
   scoped_refptr<ResourcePrefetcherManager> prefetch_manager_;
   base::CancelableTaskTracker history_lookup_consumer_;
 
-  // Map of all the navigations in flight to their resource requests.
-  NavigationMap inflight_navigations_;
-
   // Copy of the data in the predictor tables.
   std::unique_ptr<PrefetchDataMap> url_table_cache_;
   std::unique_ptr<PrefetchDataMap> host_table_cache_;
+  std::unique_ptr<RedirectDataMap> url_redirect_table_cache_;
+  std::unique_ptr<RedirectDataMap> host_redirect_table_cache_;
+
+  NavigationMap inflight_navigations_;
 
   ScopedObserver<history::HistoryService, history::HistoryServiceObserver>
       history_service_observer_;
diff --git a/chrome/browser/predictors/resource_prefetch_predictor.proto b/chrome/browser/predictors/resource_prefetch_predictor.proto
index 8616d5c..6d2a59b 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor.proto
+++ b/chrome/browser/predictors/resource_prefetch_predictor.proto
@@ -4,11 +4,11 @@
 
 // Protocol buffers used for storing in SQLite.
 // CAUTION: When any change is done here, bump kDatabaseVersion in
-//          resource_prefetch_predictor.h.
+//          resource_prefetch_predictor_tables.h.
 
 syntax = "proto2";
 
-package chrome_browser_predictors;
+package predictors;
 
 // Required in Chrome.
 option optimize_for = LITE_RUNTIME;
@@ -61,3 +61,20 @@
   optional bool has_validators = 8;
   optional bool always_revalidate = 9;
 }
+
+// Represents a mapping from URL or host to a list of redirect endpoints.
+message RedirectData {
+  // Represents a single redirect chain endpoint.
+  message RedirectStat {
+    // Represents the host for RedirectData in a host-based table.
+    optional string url = 1;
+    optional uint32 number_of_hits = 2;
+    optional uint32 number_of_misses = 3;
+    optional uint32 consecutive_misses = 4;
+  }
+
+  // Represents main frame URL or host.
+  optional string primary_key = 1;
+  optional uint64 last_visit_time = 2;
+  repeated RedirectStat redirect_endpoints = 3;
+}
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
index 982e197..a300d5b0 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.cc
@@ -24,13 +24,17 @@
 namespace {
 
 using ResourceData = predictors::ResourceData;
+using RedirectData = predictors::RedirectData;
 
 const char kMetadataTableName[] = "resource_prefetch_predictor_metadata";
 const char kUrlResourceTableName[] = "resource_prefetch_predictor_url";
 const char kUrlMetadataTableName[] = "resource_prefetch_predictor_url_metadata";
+const char kUrlRedirectTableName[] = "resource_prefetch_predictor_url_redirect";
 const char kHostResourceTableName[] = "resource_prefetch_predictor_host";
 const char kHostMetadataTableName[] =
     "resource_prefetch_predictor_host_metadata";
+const char kHostRedirectTableName[] =
+    "resource_prefetch_predictor_host_redirect";
 
 const char kCreateGlobalMetadataStatementTemplate[] =
     "CREATE TABLE %s ( "
@@ -47,9 +51,16 @@
     "main_page_url TEXT, "
     "last_visit_time INTEGER, "
     "PRIMARY KEY(main_page_url))";
+const char kCreateRedirectTableStatementTemplate[] =
+    "CREATE TABLE %s ( "
+    "main_page_url TEXT, "
+    "proto BLOB, "
+    "PRIMARY KEY(main_page_url))";
 
 const char kInsertResourceTableStatementTemplate[] =
     "INSERT INTO %s (main_page_url, resource_url, proto) VALUES (?,?,?)";
+const char kInsertRedirectTableStatementTemplate[] =
+    "INSERT INTO %s (main_page_url, proto) VALUES (?,?)";
 const char kInsertMetadataTableStatementTemplate[] =
     "INSERT INTO %s (main_page_url, last_visit_time) VALUES (?,?)";
 const char kDeleteStatementTemplate[] = "DELETE FROM %s WHERE main_page_url=?";
@@ -58,7 +69,7 @@
                                  const std::string& primary_key,
                                  Statement* statement) {
   int size = data.ByteSize();
-  DCHECK(size > 0);
+  DCHECK_GT(size, 0);
   std::vector<char> proto_buffer(size);
   data.SerializeToArray(&proto_buffer[0], size);
 
@@ -67,6 +78,17 @@
   statement->BindBlob(2, &proto_buffer[0], size);
 }
 
+void BindRedirectDataToStatement(const RedirectData& data,
+                                 Statement* statement) {
+  int size = data.ByteSize();
+  DCHECK_GT(size, 0);
+  std::vector<char> proto_buffer(size);
+  data.SerializeToArray(&proto_buffer[0], size);
+
+  statement->BindString(0, data.primary_key());
+  statement->BindBlob(1, &proto_buffer[0], size);
+}
+
 bool StepAndInitializeResourceData(Statement* statement,
                                    ResourceData* data,
                                    std::string* primary_key) {
@@ -74,7 +96,6 @@
     return false;
 
   *primary_key = statement->ColumnString(0);
-
   int size = statement->ColumnByteLength(2);
   const void* blob = statement->ColumnBlob(2);
   DCHECK(blob);
@@ -86,6 +107,24 @@
   return true;
 }
 
+bool StepAndInitializeRedirectData(Statement* statement,
+                                   RedirectData* data,
+                                   std::string* primary_key) {
+  if (!statement->Step())
+    return false;
+
+  *primary_key = statement->ColumnString(0);
+
+  int size = statement->ColumnByteLength(1);
+  const void* blob = statement->ColumnBlob(1);
+  DCHECK(blob);
+  data->ParseFromArray(blob, size);
+
+  DCHECK(data->primary_key() == *primary_key);
+
+  return true;
+}
+
 }  // namespace
 
 namespace predictors {
@@ -93,11 +132,18 @@
 // static
 void ResourcePrefetchPredictorTables::SortResources(
     std::vector<ResourceData>* resources) {
-  // Sort indices instead of ResourceData objects and then apply resulting
-  // permutation to the resources.
   std::sort(resources->begin(), resources->end(),
             [](const ResourceData& x, const ResourceData& y) {
-              return ComputeScore(x) > ComputeScore(y);
+              return ComputeResourceScore(x) > ComputeResourceScore(y);
+            });
+}
+
+// static
+void ResourcePrefetchPredictorTables::SortRedirects(
+    std::vector<RedirectStat>* redirects) {
+  std::sort(redirects->begin(), redirects->end(),
+            [](const RedirectStat& x, const RedirectStat& y) {
+              return ComputeRedirectScore(x) > ComputeRedirectScore(y);
             });
 }
 
@@ -121,45 +167,66 @@
 
 void ResourcePrefetchPredictorTables::GetAllData(
     PrefetchDataMap* url_data_map,
-    PrefetchDataMap* host_data_map) {
+    PrefetchDataMap* host_data_map,
+    RedirectDataMap* url_redirect_data_map,
+    RedirectDataMap* host_redirect_data_map) {
   DCHECK_CURRENTLY_ON(BrowserThread::DB);
   if (CantAccessDatabase())
     return;
 
   DCHECK(url_data_map);
   DCHECK(host_data_map);
+  DCHECK(url_redirect_data_map);
+  DCHECK(host_redirect_data_map);
   url_data_map->clear();
   host_data_map->clear();
+  url_redirect_data_map->clear();
+  host_redirect_data_map->clear();
 
   std::vector<std::string> urls_to_delete, hosts_to_delete;
-  GetAllDataHelper(PREFETCH_KEY_TYPE_URL, url_data_map, &urls_to_delete);
-  GetAllDataHelper(PREFETCH_KEY_TYPE_HOST, host_data_map, &hosts_to_delete);
+  GetAllResourceDataHelper(PREFETCH_KEY_TYPE_URL, url_data_map,
+                           &urls_to_delete);
+  GetAllResourceDataHelper(PREFETCH_KEY_TYPE_HOST, host_data_map,
+                           &hosts_to_delete);
+  GetAllRedirectDataHelper(PREFETCH_KEY_TYPE_URL, url_redirect_data_map);
+  GetAllRedirectDataHelper(PREFETCH_KEY_TYPE_HOST, host_redirect_data_map);
 
   if (!urls_to_delete.empty() || !hosts_to_delete.empty())
-    DeleteData(urls_to_delete, hosts_to_delete);
+    DeleteResourceData(urls_to_delete, hosts_to_delete);
 }
 
 void ResourcePrefetchPredictorTables::UpdateData(
     const PrefetchData& url_data,
-    const PrefetchData& host_data) {
+    const PrefetchData& host_data,
+    const RedirectData& url_redirect_data,
+    const RedirectData& host_redirect_data) {
   DCHECK_CURRENTLY_ON(BrowserThread::DB);
   if (CantAccessDatabase())
     return;
 
   DCHECK(!url_data.is_host() && host_data.is_host());
-  DCHECK(!url_data.primary_key.empty() || !host_data.primary_key.empty());
+  DCHECK(!url_data.primary_key.empty() || !host_data.primary_key.empty() ||
+         url_redirect_data.has_primary_key() ||
+         host_redirect_data.has_primary_key());
 
   DB()->BeginTransaction();
 
-  bool success = (url_data.primary_key.empty() || UpdateDataHelper(url_data)) &&
-      (host_data.primary_key.empty() || UpdateDataHelper(host_data));
+  bool success =
+      (url_data.primary_key.empty() ||
+       UpdateResourceDataHelper(PREFETCH_KEY_TYPE_URL, url_data)) &&
+      (host_data.primary_key.empty() ||
+       UpdateResourceDataHelper(PREFETCH_KEY_TYPE_HOST, host_data)) &&
+      (!url_redirect_data.has_primary_key() ||
+       UpdateRedirectDataHelper(PREFETCH_KEY_TYPE_URL, url_redirect_data)) &&
+      (!host_redirect_data.has_primary_key() ||
+       UpdateRedirectDataHelper(PREFETCH_KEY_TYPE_HOST, host_redirect_data));
   if (!success)
     DB()->RollbackTransaction();
-
-  DB()->CommitTransaction();
+  else
+    DB()->CommitTransaction();
 }
 
-void ResourcePrefetchPredictorTables::DeleteData(
+void ResourcePrefetchPredictorTables::DeleteResourceData(
     const std::vector<std::string>& urls,
     const std::vector<std::string>& hosts) {
   DCHECK_CURRENTLY_ON(BrowserThread::DB);
@@ -169,19 +236,44 @@
   DCHECK(!urls.empty() || !hosts.empty());
 
   if (!urls.empty())
-    DeleteDataHelper(PREFETCH_KEY_TYPE_URL, urls);
+    DeleteDataHelper(PREFETCH_KEY_TYPE_URL, PrefetchDataType::RESOURCE, urls);
   if (!hosts.empty())
-    DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, hosts);
+    DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::RESOURCE, hosts);
 }
 
-void ResourcePrefetchPredictorTables::DeleteSingleDataPoint(
+void ResourcePrefetchPredictorTables::DeleteSingleResourceDataPoint(
     const std::string& key,
     PrefetchKeyType key_type) {
   DCHECK_CURRENTLY_ON(BrowserThread::DB);
   if (CantAccessDatabase())
     return;
 
-  DeleteDataHelper(key_type, std::vector<std::string>(1, key));
+  DeleteDataHelper(key_type, PrefetchDataType::RESOURCE, {key});
+}
+
+void ResourcePrefetchPredictorTables::DeleteRedirectData(
+    const std::vector<std::string>& urls,
+    const std::vector<std::string>& hosts) {
+  DCHECK_CURRENTLY_ON(BrowserThread::DB);
+  if (CantAccessDatabase())
+    return;
+
+  DCHECK(!urls.empty() || !hosts.empty());
+
+  if (!urls.empty())
+    DeleteDataHelper(PREFETCH_KEY_TYPE_URL, PrefetchDataType::REDIRECT, urls);
+  if (!hosts.empty())
+    DeleteDataHelper(PREFETCH_KEY_TYPE_HOST, PrefetchDataType::REDIRECT, hosts);
+}
+
+void ResourcePrefetchPredictorTables::DeleteSingleRedirectDataPoint(
+    const std::string& key,
+    PrefetchKeyType key_type) {
+  DCHECK_CURRENTLY_ON(BrowserThread::DB);
+  if (CantAccessDatabase())
+    return;
+
+  DeleteDataHelper(key_type, PrefetchDataType::REDIRECT, {key});
 }
 
 void ResourcePrefetchPredictorTables::DeleteAllData() {
@@ -190,8 +282,9 @@
 
   Statement deleter;
   for (const char* table_name :
-       {kUrlResourceTableName, kUrlMetadataTableName, kHostResourceTableName,
-        kHostMetadataTableName}) {
+       {kUrlResourceTableName, kUrlMetadataTableName, kUrlRedirectTableName,
+        kHostResourceTableName, kHostMetadataTableName,
+        kHostRedirectTableName}) {
     deleter.Assign(DB()->GetUniqueStatement(
         base::StringPrintf("DELETE FROM %s", table_name).c_str()));
     deleter.Run();
@@ -205,7 +298,7 @@
 ResourcePrefetchPredictorTables::~ResourcePrefetchPredictorTables() {
 }
 
-void ResourcePrefetchPredictorTables::GetAllDataHelper(
+void ResourcePrefetchPredictorTables::GetAllResourceDataHelper(
     PrefetchKeyType key_type,
     PrefetchDataMap* data_map,
     std::vector<std::string>* to_delete) {
@@ -235,8 +328,8 @@
 
   // Read the metadata and keep track of entries that have metadata, but no
   // resource entries, so they can be deleted.
-  const char* metadata_table_name = is_host ? kHostMetadataTableName :
-      kUrlMetadataTableName;
+  const char* metadata_table_name =
+      is_host ? kHostMetadataTableName : kUrlMetadataTableName;
   Statement metadata_reader(DB()->GetUniqueStatement(
       base::StringPrintf("SELECT * FROM %s", metadata_table_name).c_str()));
 
@@ -253,7 +346,26 @@
   }
 }
 
-bool ResourcePrefetchPredictorTables::UpdateDataHelper(
+void ResourcePrefetchPredictorTables::GetAllRedirectDataHelper(
+    PrefetchKeyType key_type,
+    RedirectDataMap* redirect_map) {
+  bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+
+  const char* redirect_table_name =
+      is_host ? kHostRedirectTableName : kUrlRedirectTableName;
+  Statement redirect_reader(DB()->GetUniqueStatement(
+      base::StringPrintf("SELECT * FROM %s", redirect_table_name).c_str()));
+
+  RedirectData data;
+  std::string primary_key;
+  while (StepAndInitializeRedirectData(&redirect_reader, &data, &primary_key)) {
+    auto result = redirect_map->insert(std::make_pair(primary_key, data));
+    DCHECK(result.second);
+  }
+}
+
+bool ResourcePrefetchPredictorTables::UpdateResourceDataHelper(
+    PrefetchKeyType key_type,
     const PrefetchData& data) {
   DCHECK(!data.primary_key.empty());
 
@@ -263,57 +375,78 @@
   }
 
   // Delete the older data from both the tables.
-  std::unique_ptr<Statement> deleter(data.is_host()
-                                         ? GetHostResourceDeleteStatement()
-                                         : GetUrlResourceDeleteStatement());
+  std::unique_ptr<Statement> deleter(GetTableUpdateStatement(
+      key_type, PrefetchDataType::RESOURCE, TableOperationType::REMOVE));
   deleter->BindString(0, data.primary_key);
   if (!deleter->Run())
     return false;
 
-  deleter.reset(data.is_host() ? GetHostMetadataDeleteStatement() :
-      GetUrlMetadataDeleteStatement());
+  deleter = GetTableUpdateStatement(key_type, PrefetchDataType::METADATA,
+                                    TableOperationType::REMOVE);
   deleter->BindString(0, data.primary_key);
   if (!deleter->Run())
     return false;
 
   // Add the new data to the tables.
   for (const ResourceData& resource : data.resources) {
-    std::unique_ptr<Statement> resource_inserter(
-        data.is_host() ? GetHostResourceUpdateStatement()
-                       : GetUrlResourceUpdateStatement());
+    std::unique_ptr<Statement> resource_inserter(GetTableUpdateStatement(
+        key_type, PrefetchDataType::RESOURCE, TableOperationType::INSERT));
     BindResourceDataToStatement(resource, data.primary_key,
                                 resource_inserter.get());
     if (!resource_inserter->Run())
       return false;
   }
 
-  std::unique_ptr<Statement> metadata_inserter(
-      data.is_host() ? GetHostMetadataUpdateStatement()
-                     : GetUrlMetadataUpdateStatement());
+  std::unique_ptr<Statement> metadata_inserter(GetTableUpdateStatement(
+      key_type, PrefetchDataType::METADATA, TableOperationType::INSERT));
   metadata_inserter->BindString(0, data.primary_key);
   metadata_inserter->BindInt64(1, data.last_visit.ToInternalValue());
-  if (!metadata_inserter->Run())
+  return metadata_inserter->Run();
+}
+
+bool ResourcePrefetchPredictorTables::UpdateRedirectDataHelper(
+    PrefetchKeyType key_type,
+    const RedirectData& data) {
+  DCHECK(data.has_primary_key());
+
+  if (!StringsAreSmallerThanDBLimit(data)) {
+    UMA_HISTOGRAM_BOOLEAN("ResourcePrefetchPredictor.DbStringTooLong", true);
+    return false;
+  }
+
+  // Delete the older data from the table.
+  std::unique_ptr<Statement> deleter(GetTableUpdateStatement(
+      key_type, PrefetchDataType::REDIRECT, TableOperationType::REMOVE));
+  deleter->BindString(0, data.primary_key());
+  if (!deleter->Run())
     return false;
 
-  return true;
+  // Add the new data to the table.
+  std::unique_ptr<Statement> inserter(GetTableUpdateStatement(
+      key_type, PrefetchDataType::REDIRECT, TableOperationType::INSERT));
+  BindRedirectDataToStatement(data, inserter.get());
+  return inserter->Run();
 }
 
 void ResourcePrefetchPredictorTables::DeleteDataHelper(
     PrefetchKeyType key_type,
+    PrefetchDataType data_type,
     const std::vector<std::string>& keys) {
-  bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+  bool is_resource = data_type == PrefetchDataType::RESOURCE;
 
   for (const std::string& key : keys) {
-    std::unique_ptr<Statement> deleter(is_host
-                                           ? GetHostResourceDeleteStatement()
-                                           : GetUrlResourceDeleteStatement());
+    std::unique_ptr<Statement> deleter(GetTableUpdateStatement(
+        key_type, data_type, TableOperationType::REMOVE));
     deleter->BindString(0, key);
     deleter->Run();
 
-    deleter.reset(is_host ? GetHostMetadataDeleteStatement() :
-        GetUrlMetadataDeleteStatement());
-    deleter->BindString(0, key);
-    deleter->Run();
+    if (is_resource) {
+      // Delete corresponding resource metadata as well.
+      deleter = GetTableUpdateStatement(key_type, PrefetchDataType::METADATA,
+                                        TableOperationType::REMOVE);
+      deleter->BindString(0, key);
+      deleter->Run();
+    }
   }
 }
 
@@ -330,8 +463,21 @@
   return true;
 }
 
+bool ResourcePrefetchPredictorTables::StringsAreSmallerThanDBLimit(
+    const RedirectData& data) {
+  if (data.primary_key().length() > kMaxStringLength)
+    return false;
+
+  for (const RedirectStat& redirect : data.redirect_endpoints()) {
+    if (redirect.url().length() > kMaxStringLength)
+      return false;
+  }
+  return true;
+}
+
 // static
-float ResourcePrefetchPredictorTables::ComputeScore(const ResourceData& data) {
+float ResourcePrefetchPredictorTables::ComputeResourceScore(
+    const ResourceData& data) {
   // The score is calculated so that when the rows are sorted, stylesheets,
   // scripts and fonts appear first, sorted by position(ascending) and then the
   // rest of the resources sorted by position (ascending).
@@ -350,6 +496,13 @@
 }
 
 // static
+float ResourcePrefetchPredictorTables::ComputeRedirectScore(
+    const RedirectStat& data) {
+  // TODO(alexilin): Invent some scoring.
+  return 0.0;
+}
+
+// static
 bool ResourcePrefetchPredictorTables::DropTablesIfOutdated(
     sql::Connection* db) {
   int version = GetDatabaseVersion(db);
@@ -360,7 +513,8 @@
   if (incompatible_version) {
     for (const char* table_name :
          {kMetadataTableName, kUrlResourceTableName, kHostResourceTableName,
-          kUrlMetadataTableName, kHostMetadataTableName}) {
+          kUrlRedirectTableName, kHostRedirectTableName, kUrlMetadataTableName,
+          kHostMetadataTableName}) {
       success =
           success &&
           db->Execute(base::StringPrintf("DROP TABLE IF EXISTS %s", table_name)
@@ -427,6 +581,10 @@
        db->Execute(base::StringPrintf(kCreateMetadataTableStatementTemplate,
                                       kUrlMetadataTableName)
                        .c_str())) &&
+      (db->DoesTableExist(kUrlRedirectTableName) ||
+       db->Execute(base::StringPrintf(kCreateRedirectTableStatementTemplate,
+                                      kUrlRedirectTableName)
+                       .c_str())) &&
       (db->DoesTableExist(kHostResourceTableName) ||
        db->Execute(base::StringPrintf(kCreateResourceTableStatementTemplate,
                                       kHostResourceTableName)
@@ -434,6 +592,10 @@
       (db->DoesTableExist(kHostMetadataTableName) ||
        db->Execute(base::StringPrintf(kCreateMetadataTableStatementTemplate,
                                       kHostMetadataTableName)
+                       .c_str())) &&
+      (db->DoesTableExist(kHostRedirectTableName) ||
+       db->Execute(base::StringPrintf(kCreateRedirectTableStatementTemplate,
+                                      kHostRedirectTableName)
                        .c_str()));
 
   if (success)
@@ -465,67 +627,61 @@
                          statement.ColumnInt(0));
 }
 
-Statement*
-    ResourcePrefetchPredictorTables::GetUrlResourceDeleteStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      base::StringPrintf(kDeleteStatementTemplate, kUrlResourceTableName)
-          .c_str()));
+std::unique_ptr<Statement>
+ResourcePrefetchPredictorTables::GetTableUpdateStatement(
+    PrefetchKeyType key_type,
+    PrefetchDataType data_type,
+    TableOperationType op_type) {
+  sql::StatementID id(__FILE__, key_type | (static_cast<int>(data_type) << 1) |
+                                    (static_cast<int>(op_type) << 3));
+  const char* statement_template =
+      GetTableUpdateStatementTemplate(op_type, data_type);
+  const char* table_name =
+      GetTableUpdateStatementTableName(key_type, data_type);
+  return base::MakeUnique<Statement>(DB()->GetCachedStatement(
+      id, base::StringPrintf(statement_template, table_name).c_str()));
 }
 
-Statement*
-    ResourcePrefetchPredictorTables::GetUrlResourceUpdateStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE, base::StringPrintf(kInsertResourceTableStatementTemplate,
-                                        kUrlResourceTableName)
-                         .c_str()));
+// static
+const char* ResourcePrefetchPredictorTables::GetTableUpdateStatementTemplate(
+    TableOperationType op_type,
+    PrefetchDataType data_type) {
+  switch (op_type) {
+    case TableOperationType::REMOVE:
+      return kDeleteStatementTemplate;
+    case TableOperationType::INSERT:
+      switch (data_type) {
+        case PrefetchDataType::RESOURCE:
+          return kInsertResourceTableStatementTemplate;
+        case PrefetchDataType::REDIRECT:
+          return kInsertRedirectTableStatementTemplate;
+        case PrefetchDataType::METADATA:
+          return kInsertMetadataTableStatementTemplate;
+      }
+  }
+
+  NOTREACHED();
+  return nullptr;
 }
 
-Statement*
-    ResourcePrefetchPredictorTables::GetUrlMetadataDeleteStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      base::StringPrintf(kDeleteStatementTemplate, kUrlMetadataTableName)
-          .c_str()));
-}
+// static
+const char* ResourcePrefetchPredictorTables::GetTableUpdateStatementTableName(
+    PrefetchKeyType key_type,
+    PrefetchDataType data_type) {
+  DCHECK(key_type == PREFETCH_KEY_TYPE_URL ||
+         key_type == PREFETCH_KEY_TYPE_HOST);
+  bool is_host = key_type == PREFETCH_KEY_TYPE_HOST;
+  switch (data_type) {
+    case PrefetchDataType::RESOURCE:
+      return is_host ? kHostResourceTableName : kUrlResourceTableName;
+    case PrefetchDataType::REDIRECT:
+      return is_host ? kHostRedirectTableName : kUrlRedirectTableName;
+    case PrefetchDataType::METADATA:
+      return is_host ? kHostMetadataTableName : kUrlMetadataTableName;
+  }
 
-Statement*
-    ResourcePrefetchPredictorTables::GetUrlMetadataUpdateStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE, base::StringPrintf(kInsertMetadataTableStatementTemplate,
-                                        kUrlMetadataTableName)
-                         .c_str()));
-}
-
-Statement*
-    ResourcePrefetchPredictorTables::GetHostResourceDeleteStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      base::StringPrintf(kDeleteStatementTemplate, kHostResourceTableName)
-          .c_str()));
-}
-
-Statement*
-    ResourcePrefetchPredictorTables::GetHostResourceUpdateStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE, base::StringPrintf(kInsertResourceTableStatementTemplate,
-                                        kHostResourceTableName)
-                         .c_str()));
-}
-
-Statement*
-    ResourcePrefetchPredictorTables::GetHostMetadataDeleteStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE,
-      base::StringPrintf(kDeleteStatementTemplate, kHostMetadataTableName)
-          .c_str()));
-}
-
-Statement* ResourcePrefetchPredictorTables::GetHostMetadataUpdateStatement() {
-  return new Statement(DB()->GetCachedStatement(
-      SQL_FROM_HERE, base::StringPrintf(kInsertMetadataTableStatementTemplate,
-                                        kHostMetadataTableName)
-                         .c_str()));
+  NOTREACHED();
+  return nullptr;
 }
 
 }  // namespace predictors
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables.h b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
index b56ed4c..6588b546 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables.h
@@ -13,6 +13,7 @@
 
 #include "base/gtest_prod_util.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/time/time.h"
 #include "chrome/browser/predictors/predictor_table_base.h"
 #include "chrome/browser/predictors/resource_prefetch_common.h"
@@ -27,7 +28,8 @@
 
 namespace predictors {
 
-using chrome_browser_predictors::ResourceData;
+// From resource_prefetch_predictor.proto.
+using RedirectStat = RedirectData_RedirectStat;
 
 // Interface for database tables used by the ResourcePrefetchPredictor.
 // All methods except the constructor and destructor need to be called on the DB
@@ -36,13 +38,12 @@
 // Currently manages:
 //  - UrlResourceTable - resources per Urls.
 //  - UrlMetadataTable - misc data for Urls (like last visit time).
+//  - UrlRedirectTable - redirects per Urls.
 //  - HostResourceTable - resources per host.
 //  - HostMetadataTable - misc data for hosts.
+//  - HostRedirectTable - redirects per host.
 class ResourcePrefetchPredictorTables : public PredictorTableBase {
  public:
-  // Sorts the resources by score, decreasing.
-  static void SortResources(std::vector<ResourceData>* resources);
-
   // Aggregated data for a Url or Host. Although the data differs slightly, we
   // store them in the same structure, because most of the fields are common and
   // it allows us to use the same functions.
@@ -63,58 +64,95 @@
   // Map from primary key to PrefetchData for the key.
   typedef std::map<std::string, PrefetchData> PrefetchDataMap;
 
+  // Map from primary key to RedirectData for the key.
+  typedef std::map<std::string, RedirectData> RedirectDataMap;
+
   // Returns data for all Urls and Hosts.
   virtual void GetAllData(PrefetchDataMap* url_data_map,
-                          PrefetchDataMap* host_data_map);
+                          PrefetchDataMap* host_data_map,
+                          RedirectDataMap* url_redirect_data_map,
+                          RedirectDataMap* host_redirect_data_map);
 
   // Updates data for a Url and a host. If either of the |url_data| or
-  // |host_data| has an empty primary key, it will be ignored.
-  // Note that the Urls and primary key in |url_data| and |host_data| should be
-  // less than |kMaxStringLength| in length.
+  // |host_data| or |url_redirect_data| or |host_redirect_data| has an empty
+  // primary key, it will be ignored.
+  // Note that the Urls and primary key in |url_data|, |host_data|,
+  // |url_redirect_data| and |host_redirect_data| should be less than
+  // |kMaxStringLength| in length.
   virtual void UpdateData(const PrefetchData& url_data,
-                          const PrefetchData& host_data);
+                          const PrefetchData& host_data,
+                          const RedirectData& url_redirect_data,
+                          const RedirectData& host_redirect_data);
 
   // Delete data for the input |urls| and |hosts|.
-  virtual void DeleteData(const std::vector<std::string>& urls,
-                  const std::vector<std::string>& hosts);
+  virtual void DeleteResourceData(const std::vector<std::string>& urls,
+                                  const std::vector<std::string>& hosts);
 
-  // Wrapper over DeleteData for convenience.
-  virtual void DeleteSingleDataPoint(const std::string& key,
-                                     PrefetchKeyType key_type);
+  // Wrapper over DeleteResourceData for convenience.
+  virtual void DeleteSingleResourceDataPoint(const std::string& key,
+                                             PrefetchKeyType key_type);
+
+  // Delete data for the input |urls| and |hosts|.
+  virtual void DeleteRedirectData(const std::vector<std::string>& urls,
+                                  const std::vector<std::string>& hosts);
+
+  // Wrapper over DeleteRedirectData for convenience.
+  virtual void DeleteSingleRedirectDataPoint(const std::string& key,
+                                             PrefetchKeyType key_type);
 
   // Deletes all data in all the tables.
   virtual void DeleteAllData();
 
+  // Sorts the resources by score, decreasing.
+  static void SortResources(std::vector<ResourceData>* resources);
+
+  // Sorts the redirects by score, decreasing.
+  static void SortRedirects(std::vector<RedirectStat>* redirects);
+
   // The maximum length of the string that can be stored in the DB.
   static constexpr size_t kMaxStringLength = 1024;
 
  private:
+  // Represents the type of information that is stored in prefetch database.
+  enum class PrefetchDataType { RESOURCE, REDIRECT, METADATA };
+
+  enum class TableOperationType { INSERT, REMOVE };
+
   friend class PredictorDatabaseInternal;
   friend class MockResourcePrefetchPredictorTables;
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest,
                            DatabaseVersionIsSet);
   FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest,
                            DatabaseIsResetWhenIncompatible);
-  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest, ComputeScore);
+  FRIEND_TEST_ALL_PREFIXES(ResourcePrefetchPredictorTablesTest,
+                           ComputeResourceScore);
 
   ResourcePrefetchPredictorTables();
   ~ResourcePrefetchPredictorTables() override;
 
   // Helper functions below help perform functions on the Url and host table
   // using the same code.
-  void GetAllDataHelper(PrefetchKeyType key_type,
-                        PrefetchDataMap* data_map,
-                        std::vector<std::string>* to_delete);
-  bool UpdateDataHelper(const PrefetchData& data);
+  void GetAllResourceDataHelper(PrefetchKeyType key_type,
+                                PrefetchDataMap* data_map,
+                                std::vector<std::string>* to_delete);
+  void GetAllRedirectDataHelper(PrefetchKeyType key_type,
+                                RedirectDataMap* redirect_map);
+  bool UpdateResourceDataHelper(PrefetchKeyType key_type,
+                                const PrefetchData& data);
+  bool UpdateRedirectDataHelper(PrefetchKeyType key_type,
+                                const RedirectData& data);
   void DeleteDataHelper(PrefetchKeyType key_type,
+                        PrefetchDataType data_type,
                         const std::vector<std::string>& keys);
 
   // Returns true if the strings in the |data| are less than |kMaxStringLength|
   // in length.
   static bool StringsAreSmallerThanDBLimit(const PrefetchData& data);
+  static bool StringsAreSmallerThanDBLimit(const RedirectData& data);
 
   // Computes score of |data|.
-  static float ComputeScore(const ResourceData& data);
+  static float ComputeResourceScore(const ResourceData& data);
+  static float ComputeRedirectScore(const RedirectStat& data);
 
   // PredictorTableBase methods.
   void CreateTableIfNonExistent() override;
@@ -122,23 +160,24 @@
 
   // Database version. Always increment it when any change is made to the data
   // schema (including the .proto).
-  static constexpr int kDatabaseVersion = 2;
+  static constexpr int kDatabaseVersion = 3;
 
   static bool DropTablesIfOutdated(sql::Connection* db);
   static int GetDatabaseVersion(sql::Connection* db);
   static bool SetDatabaseVersion(sql::Connection* db, int version);
 
-  // Helpers to return Statements for cached Statements. The caller must take
-  // ownership of the return Statements.
-  sql::Statement* GetUrlResourceDeleteStatement();
-  sql::Statement* GetUrlResourceUpdateStatement();
-  sql::Statement* GetUrlMetadataDeleteStatement();
-  sql::Statement* GetUrlMetadataUpdateStatement();
+  // Helper to return Statements for cached Statements.
+  std::unique_ptr<sql::Statement> GetTableUpdateStatement(
+      PrefetchKeyType key_type,
+      PrefetchDataType data_type,
+      TableOperationType op_type);
 
-  sql::Statement* GetHostResourceDeleteStatement();
-  sql::Statement* GetHostResourceUpdateStatement();
-  sql::Statement* GetHostMetadataDeleteStatement();
-  sql::Statement* GetHostMetadataUpdateStatement();
+  static const char* GetTableUpdateStatementTemplate(
+      TableOperationType op_type,
+      PrefetchDataType data_type);
+  static const char* GetTableUpdateStatementTableName(
+      PrefetchKeyType key_type,
+      PrefetchDataType data_type);
 
   DISALLOW_COPY_AND_ASSIGN(ResourcePrefetchPredictorTables);
 };
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
index e7835442..c969bdea 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_tables_unittest.cc
@@ -2,6 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <memory>
 #include <set>
 #include <utility>
 #include <vector>
@@ -41,6 +42,7 @@
   scoped_refptr<ResourcePrefetchPredictorTables> tables_;
 
   using PrefetchDataMap = ResourcePrefetchPredictorTables::PrefetchDataMap;
+  using RedirectDataMap = ResourcePrefetchPredictorTables::RedirectDataMap;
 
  private:
   using PrefetchData = ResourcePrefetchPredictorTables::PrefetchData;
@@ -55,10 +57,20 @@
   void TestResourcesAreEqual(const std::vector<ResourceData>& lhs,
                              const std::vector<ResourceData>& rhs) const;
 
+  // Checks that the input RedirectData are the same, although the redirects
+  // can be in different order.
+  void TestRedirectDataAreEqual(const RedirectDataMap& lhs,
+                                const RedirectDataMap& rhs) const;
+  void TestRedirectsAreEqual(const std::vector<RedirectStat>& lhs,
+                             const std::vector<RedirectStat>& rhs) const;
+
   void AddKey(PrefetchDataMap* m, const std::string& key) const;
+  void AddKey(RedirectDataMap* m, const std::string& key) const;
 
   PrefetchDataMap test_url_data_;
   PrefetchDataMap test_host_data_;
+  RedirectDataMap test_url_redirect_data_;
+  RedirectDataMap test_host_redirect_data_;
 };
 
 class ResourcePrefetchPredictorTablesReopenTest
@@ -95,38 +107,57 @@
 
 void ResourcePrefetchPredictorTablesTest::TestGetAllData() {
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   TestPrefetchDataAreEqual(test_url_data_, actual_url_data);
   TestPrefetchDataAreEqual(test_host_data_, actual_host_data);
+  TestRedirectDataAreEqual(test_url_redirect_data_, actual_url_redirect_data);
+  TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data);
 }
 
 void ResourcePrefetchPredictorTablesTest::TestDeleteData() {
-  std::vector<std::string> urls_to_delete, hosts_to_delete;
-  urls_to_delete.push_back("http://www.google.com");
-  urls_to_delete.push_back("http://www.yahoo.com");
-  hosts_to_delete.push_back("www.yahoo.com");
+  std::vector<std::string> urls_to_delete = {"http://www.google.com",
+                                             "http://www.yahoo.com"};
+  std::vector<std::string> hosts_to_delete = {"www.yahoo.com"};
 
-  tables_->DeleteData(urls_to_delete, hosts_to_delete);
+  tables_->DeleteResourceData(urls_to_delete, hosts_to_delete);
+
+  urls_to_delete = {"http://fb.com/google", "http://google.com"};
+  hosts_to_delete = {"microsoft.com"};
+
+  tables_->DeleteRedirectData(urls_to_delete, hosts_to_delete);
 
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   PrefetchDataMap expected_url_data, expected_host_data;
+  RedirectDataMap expected_url_redirect_data, expected_host_redirect_data;
   AddKey(&expected_url_data, "http://www.reddit.com");
   AddKey(&expected_host_data, "www.facebook.com");
+  AddKey(&expected_url_redirect_data, "http://nyt.com");
+  AddKey(&expected_host_redirect_data, "bbc.com");
 
   TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
   TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(expected_url_redirect_data,
+                           actual_url_redirect_data);
+  TestRedirectDataAreEqual(expected_host_redirect_data,
+                           actual_host_redirect_data);
 }
 
 void ResourcePrefetchPredictorTablesTest::TestDeleteSingleDataPoint() {
   // Delete a URL.
-  tables_->DeleteSingleDataPoint("http://www.reddit.com",
-                                 PREFETCH_KEY_TYPE_URL);
+  tables_->DeleteSingleResourceDataPoint("http://www.reddit.com",
+                                         PREFETCH_KEY_TYPE_URL);
 
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   PrefetchDataMap expected_url_data;
   AddKey(&expected_url_data, "http://www.google.com");
@@ -134,18 +165,65 @@
 
   TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
   TestPrefetchDataAreEqual(test_host_data_, actual_host_data);
+  TestRedirectDataAreEqual(test_url_redirect_data_, actual_url_redirect_data);
+  TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data);
 
   // Delete a host.
-  tables_->DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST);
+  tables_->DeleteSingleResourceDataPoint("www.facebook.com",
+                                         PREFETCH_KEY_TYPE_HOST);
   actual_url_data.clear();
   actual_host_data.clear();
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  actual_url_redirect_data.clear();
+  actual_host_redirect_data.clear();
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   PrefetchDataMap expected_host_data;
   AddKey(&expected_host_data, "www.yahoo.com");
 
   TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
   TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(test_url_redirect_data_, actual_url_redirect_data);
+  TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data);
+
+  // Delete a URL redirect.
+  tables_->DeleteSingleRedirectDataPoint("http://nyt.com",
+                                         PREFETCH_KEY_TYPE_URL);
+  actual_url_data.clear();
+  actual_host_data.clear();
+  actual_url_redirect_data.clear();
+  actual_host_redirect_data.clear();
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
+
+  RedirectDataMap expected_url_redirect_data;
+  AddKey(&expected_url_redirect_data, "http://fb.com/google");
+  AddKey(&expected_url_redirect_data, "http://google.com");
+
+  TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
+  TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(expected_url_redirect_data,
+                           actual_url_redirect_data);
+  TestRedirectDataAreEqual(test_host_redirect_data_, actual_host_redirect_data);
+
+  // Delete a host redirect.
+  tables_->DeleteSingleRedirectDataPoint("bbc.com", PREFETCH_KEY_TYPE_HOST);
+  actual_url_data.clear();
+  actual_host_data.clear();
+  actual_url_redirect_data.clear();
+  actual_host_redirect_data.clear();
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
+
+  RedirectDataMap expected_host_redirect_data;
+  AddKey(&expected_host_redirect_data, "microsoft.com");
+
+  TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
+  TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(expected_url_redirect_data,
+                           actual_url_redirect_data);
+  TestRedirectDataAreEqual(expected_host_redirect_data,
+                           actual_host_redirect_data);
 }
 
 void ResourcePrefetchPredictorTablesTest::TestUpdateData() {
@@ -170,12 +248,29 @@
       "http://www.yahoo.com/image.png", content::RESOURCE_TYPE_IMAGE, 120, 1, 1,
       10.0, net::MEDIUM, true, false));
 
-  tables_->UpdateData(google, yahoo);
+  RedirectData facebook;
+  facebook.set_primary_key("http://fb.com/google");
+  facebook.set_last_visit_time(20);
+  InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                         "https://facebook.fr/google", 4, 2, 1);
+
+  RedirectData microsoft;
+  microsoft.set_primary_key("microsoft.com");
+  microsoft.set_last_visit_time(21);
+  InitializeRedirectStat(microsoft.add_redirect_endpoints(), "m.microsoft.com",
+                         5, 7, 1);
+  InitializeRedirectStat(microsoft.add_redirect_endpoints(), "microsoft.org", 7,
+                         2, 0);
+
+  tables_->UpdateData(google, yahoo, facebook, microsoft);
 
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
 
   PrefetchDataMap expected_url_data, expected_host_data;
+  RedirectDataMap expected_url_redirect_data, expected_host_redirect_data;
   AddKey(&expected_url_data, "http://www.reddit.com");
   AddKey(&expected_url_data, "http://www.yahoo.com");
   expected_url_data.insert(std::make_pair("http://www.google.com", google));
@@ -183,17 +278,34 @@
   AddKey(&expected_host_data, "www.facebook.com");
   expected_host_data.insert(std::make_pair("www.yahoo.com", yahoo));
 
+  AddKey(&expected_url_redirect_data, "http://nyt.com");
+  AddKey(&expected_url_redirect_data, "http://google.com");
+  expected_url_redirect_data.insert(
+      std::make_pair("http://fb.com/google", facebook));
+
+  AddKey(&expected_host_redirect_data, "bbc.com");
+  expected_host_redirect_data.insert(
+      std::make_pair("microsoft.com", microsoft));
+
   TestPrefetchDataAreEqual(expected_url_data, actual_url_data);
   TestPrefetchDataAreEqual(expected_host_data, actual_host_data);
+  TestRedirectDataAreEqual(expected_url_redirect_data,
+                           actual_url_redirect_data);
+  TestRedirectDataAreEqual(expected_host_redirect_data,
+                           actual_host_redirect_data);
 }
 
 void ResourcePrefetchPredictorTablesTest::TestDeleteAllData() {
   tables_->DeleteAllData();
 
   PrefetchDataMap actual_url_data, actual_host_data;
-  tables_->GetAllData(&actual_url_data, &actual_host_data);
+  RedirectDataMap actual_url_redirect_data, actual_host_redirect_data;
+  tables_->GetAllData(&actual_url_data, &actual_host_data,
+                      &actual_url_redirect_data, &actual_host_redirect_data);
   EXPECT_TRUE(actual_url_data.empty());
   EXPECT_TRUE(actual_host_data.empty());
+  EXPECT_TRUE(actual_url_redirect_data.empty());
+  EXPECT_TRUE(actual_host_redirect_data.empty());
 }
 
 void ResourcePrefetchPredictorTablesTest::TestPrefetchDataAreEqual(
@@ -202,8 +314,10 @@
   EXPECT_EQ(lhs.size(), rhs.size());
 
   for (const std::pair<std::string, PrefetchData>& p : rhs) {
-    PrefetchDataMap::const_iterator lhs_it = lhs.find(p.first);
+    const auto lhs_it = lhs.find(p.first);
     ASSERT_TRUE(lhs_it != lhs.end()) << p.first;
+    EXPECT_TRUE(lhs_it->second.key_type == p.second.key_type);
+    EXPECT_TRUE(lhs_it->second.last_visit == p.second.last_visit);
 
     TestResourcesAreEqual(lhs_it->second.resources, p.second.resources);
   }
@@ -230,19 +344,81 @@
   EXPECT_EQ(lhs.size(), resources_seen.size());
 }
 
+void ResourcePrefetchPredictorTablesTest::TestRedirectDataAreEqual(
+    const RedirectDataMap& lhs,
+    const RedirectDataMap& rhs) const {
+  EXPECT_EQ(lhs.size(), rhs.size());
+
+  for (const auto& p : rhs) {
+    const auto lhs_it = lhs.find(p.first);
+    ASSERT_TRUE(lhs_it != lhs.end()) << p.first;
+    EXPECT_EQ(lhs_it->second.primary_key(), p.second.primary_key());
+    EXPECT_EQ(lhs_it->second.last_visit_time(), p.second.last_visit_time());
+
+    std::vector<RedirectStat> lhs_redirects(
+        lhs_it->second.redirect_endpoints().begin(),
+        lhs_it->second.redirect_endpoints().end());
+    std::vector<RedirectStat> rhs_redirects(
+        p.second.redirect_endpoints().begin(),
+        p.second.redirect_endpoints().end());
+
+    TestRedirectsAreEqual(lhs_redirects, rhs_redirects);
+  }
+}
+
+void ResourcePrefetchPredictorTablesTest::TestRedirectsAreEqual(
+    const std::vector<RedirectStat>& lhs,
+    const std::vector<RedirectStat>& rhs) const {
+  EXPECT_EQ(lhs.size(), rhs.size());
+
+  std::map<std::string, RedirectStat> lhs_index;
+  // Repeated redirects are not allowed.
+  for (const auto& r : lhs)
+    EXPECT_TRUE(lhs_index.insert(std::make_pair(r.url(), r)).second);
+
+  for (const auto& r : rhs) {
+    auto lhs_it = lhs_index.find(r.url());
+    if (lhs_it != lhs_index.end()) {
+      EXPECT_EQ(r, lhs_it->second);
+      lhs_index.erase(lhs_it);
+    } else {
+      ADD_FAILURE() << r.url();
+    }
+  }
+
+  EXPECT_TRUE(lhs_index.empty());
+}
+
 void ResourcePrefetchPredictorTablesTest::AddKey(PrefetchDataMap* m,
                                                  const std::string& key) const {
   PrefetchDataMap::const_iterator it = test_url_data_.find(key);
   if (it != test_url_data_.end()) {
-    m->insert(std::make_pair(it->first, it->second));
+    m->insert(*it);
     return;
   }
   it = test_host_data_.find(key);
   ASSERT_TRUE(it != test_host_data_.end());
-  m->insert(std::make_pair(it->first, it->second));
+  m->insert(*it);
+}
+
+void ResourcePrefetchPredictorTablesTest::AddKey(RedirectDataMap* m,
+                                                 const std::string& key) const {
+  auto it = test_url_redirect_data_.find(key);
+  if (it != test_url_redirect_data_.end()) {
+    m->insert(*it);
+    return;
+  }
+  it = test_host_redirect_data_.find(key);
+  ASSERT_TRUE(it != test_host_redirect_data_.end());
+  m->insert(*it);
 }
 
 void ResourcePrefetchPredictorTablesTest::InitializeSampleData() {
+  PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string());
+  PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string());
+  RedirectData empty_url_redirect_data;
+  RedirectData empty_host_redirect_data;
+
   {  // Url data.
     PrefetchData google(PREFETCH_KEY_TYPE_URL, "http://www.google.com");
     google.last_visit = base::Time::FromInternalValue(1);
@@ -283,10 +459,12 @@
     test_url_data_.insert(std::make_pair("http://www.reddit.com", reddit));
     test_url_data_.insert(std::make_pair("http://www.yahoo.com", yahoo));
 
-    PrefetchData empty_host_data(PREFETCH_KEY_TYPE_HOST, std::string());
-    tables_->UpdateData(google, empty_host_data);
-    tables_->UpdateData(reddit, empty_host_data);
-    tables_->UpdateData(yahoo, empty_host_data);
+    tables_->UpdateData(google, empty_host_data, empty_url_redirect_data,
+                        empty_host_redirect_data);
+    tables_->UpdateData(reddit, empty_host_data, empty_url_redirect_data,
+                        empty_host_redirect_data);
+    tables_->UpdateData(yahoo, empty_host_data, empty_url_redirect_data,
+                        empty_host_redirect_data);
   }
 
   {  // Host data.
@@ -319,9 +497,72 @@
     test_host_data_.insert(std::make_pair("www.facebook.com", facebook));
     test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo));
 
-    PrefetchData empty_url_data(PREFETCH_KEY_TYPE_URL, std::string());
-    tables_->UpdateData(empty_url_data, facebook);
-    tables_->UpdateData(empty_url_data, yahoo);
+    tables_->UpdateData(empty_url_data, facebook, empty_url_redirect_data,
+                        empty_host_redirect_data);
+    tables_->UpdateData(empty_url_data, yahoo, empty_url_redirect_data,
+                        empty_host_redirect_data);
+  }
+
+  {  // Url redirect data.
+    RedirectData facebook;
+    facebook.set_primary_key("http://fb.com/google");
+    facebook.set_last_visit_time(6);
+    InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                           "https://facebook.com/google", 5, 1, 0);
+    InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                           "https://facebook.com/login", 3, 5, 1);
+
+    RedirectData nytimes;
+    nytimes.set_primary_key("http://nyt.com");
+    nytimes.set_last_visit_time(7);
+    InitializeRedirectStat(nytimes.add_redirect_endpoints(),
+                           "https://nytimes.com", 2, 0, 0);
+
+    RedirectData google;
+    google.set_primary_key("http://google.com");
+    google.set_last_visit_time(8);
+    InitializeRedirectStat(google.add_redirect_endpoints(),
+                           "https://google.com", 3, 0, 0);
+
+    test_url_redirect_data_.clear();
+    test_url_redirect_data_.insert(
+        std::make_pair(facebook.primary_key(), facebook));
+    test_url_redirect_data_.insert(
+        std::make_pair(nytimes.primary_key(), nytimes));
+    test_url_redirect_data_.insert(
+        std::make_pair(google.primary_key(), google));
+
+    tables_->UpdateData(empty_url_data, empty_host_data, facebook,
+                        empty_host_redirect_data);
+    tables_->UpdateData(empty_url_data, empty_host_data, nytimes,
+                        empty_host_redirect_data);
+    tables_->UpdateData(empty_url_data, empty_host_data, google,
+                        empty_host_redirect_data);
+  }
+
+  {  // Host redirect data.
+    RedirectData bbc;
+    bbc.set_primary_key("bbc.com");
+    bbc.set_last_visit_time(9);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "www.bbc.com", 8, 4,
+                           1);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "m.bbc.com", 5, 8, 0);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "bbc.co.uk", 1, 3, 0);
+
+    RedirectData microsoft;
+    microsoft.set_primary_key("microsoft.com");
+    microsoft.set_last_visit_time(10);
+    InitializeRedirectStat(microsoft.add_redirect_endpoints(),
+                           "www.microsoft.com", 10, 0, 0);
+
+    test_host_redirect_data_.clear();
+    test_host_redirect_data_.insert(std::make_pair(bbc.primary_key(), bbc));
+    test_host_redirect_data_.insert(
+        std::make_pair(microsoft.primary_key(), microsoft));
+    tables_->UpdateData(empty_url_data, empty_host_data,
+                        empty_url_redirect_data, bbc);
+    tables_->UpdateData(empty_url_data, empty_host_data,
+                        empty_url_redirect_data, microsoft);
   }
 }
 
@@ -333,7 +574,7 @@
 
 // Test cases.
 
-TEST_F(ResourcePrefetchPredictorTablesTest, ComputeScore) {
+TEST_F(ResourcePrefetchPredictorTablesTest, ComputeResourceScore) {
   ResourceData js_resource = CreateResourceData(
       "http://www.resources.google.com/script.js",
       content::RESOURCE_TYPE_SCRIPT, 11, 0, 0, 1., net::MEDIUM, false, false);
@@ -349,13 +590,13 @@
                          content::RESOURCE_TYPE_FONT_RESOURCE, 11, 0, 0, 1.,
                          net::MEDIUM, false, false);
   float js_resource_score =
-      ResourcePrefetchPredictorTables::ComputeScore(js_resource);
+      ResourcePrefetchPredictorTables::ComputeResourceScore(js_resource);
   float css_resource_score =
-      ResourcePrefetchPredictorTables::ComputeScore(css_resource);
+      ResourcePrefetchPredictorTables::ComputeResourceScore(css_resource);
   float font_resource_score =
-      ResourcePrefetchPredictorTables::ComputeScore(font_resource);
+      ResourcePrefetchPredictorTables::ComputeResourceScore(font_resource);
   float image_resource_score =
-      ResourcePrefetchPredictorTables::ComputeScore(image_resource);
+      ResourcePrefetchPredictorTables::ComputeResourceScore(image_resource);
 
   EXPECT_TRUE(js_resource_score == css_resource_score);
   EXPECT_TRUE(js_resource_score == font_resource_score);
@@ -403,7 +644,9 @@
   ASSERT_EQ(version, ResourcePrefetchPredictorTables::GetDatabaseVersion(db));
 
   PrefetchDataMap url_data, host_data;
-  tables_->GetAllData(&url_data, &host_data);
+  RedirectDataMap url_redirect_data, host_redirect_data;
+  tables_->GetAllData(&url_data, &host_data, &url_redirect_data,
+                      &host_redirect_data);
   EXPECT_TRUE(url_data.empty());
   EXPECT_TRUE(host_data.empty());
 }
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc b/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
index 013e1d46..5e18536 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_test_util.cc
@@ -33,13 +33,21 @@
   return resource;
 }
 
-void PrintTo(const ResourceData& resource, ::std::ostream* os) {
-  *os << "[" << resource.resource_url() << "," << resource.resource_type()
-      << "," << resource.number_of_hits() << "," << resource.number_of_misses()
-      << "," << resource.consecutive_misses() << ","
-      << resource.average_position() << "," << resource.priority() << ","
-      << resource.has_validators() << "," << resource.always_revalidate()
-      << "]";
+void InitializeRedirectStat(RedirectStat* redirect,
+                            const std::string& url,
+                            int number_of_hits,
+                            int number_of_misses,
+                            int consecutive_misses) {
+  redirect->set_url(url);
+  redirect->set_number_of_hits(number_of_hits);
+  redirect->set_number_of_misses(number_of_misses);
+  redirect->set_consecutive_misses(consecutive_misses);
+}
+
+RedirectData CreateRedirectData(const std::string& primary_key) {
+  RedirectData data;
+  data.set_primary_key(primary_key);
+  return data;
 }
 
 void PrintTo(const PrefetchData& data, ::std::ostream* os) {
@@ -52,6 +60,44 @@
   }
 }
 
+void PrintTo(const ResourceData& resource, ::std::ostream* os) {
+  *os << "[" << resource.resource_url() << "," << resource.resource_type()
+      << "," << resource.number_of_hits() << "," << resource.number_of_misses()
+      << "," << resource.consecutive_misses() << ","
+      << resource.average_position() << "," << resource.priority() << ","
+      << resource.has_validators() << "," << resource.always_revalidate()
+      << "]";
+}
+
+void PrintTo(const RedirectStat& redirect, ::std::ostream* os) {
+  *os << "[" << redirect.url() << "," << redirect.number_of_hits() << ","
+      << redirect.number_of_misses() << "," << redirect.consecutive_misses()
+      << "]";
+}
+
+void PrintTo(const RedirectData& data, ::std::ostream* os) {
+  *os << "[" << data.primary_key() << "," << data.last_visit_time() << "]\n";
+  for (const RedirectStat& redirect : data.redirect_endpoints()) {
+    *os << "\t\t";
+    PrintTo(redirect, os);
+    *os << "\n";
+  }
+}
+
+bool operator==(const PrefetchData& lhs, const PrefetchData& rhs) {
+  bool equal = lhs.key_type == rhs.key_type &&
+               lhs.primary_key == rhs.primary_key &&
+               lhs.resources.size() == rhs.resources.size();
+
+  if (!equal)
+    return false;
+
+  for (size_t i = 0; i < lhs.resources.size(); ++i)
+    equal = equal && lhs.resources[i] == rhs.resources[i];
+
+  return equal;
+}
+
 bool operator==(const ResourceData& lhs, const ResourceData& rhs) {
   return lhs.resource_url() == rhs.resource_url() &&
          lhs.resource_type() == rhs.resource_type() &&
@@ -64,16 +110,22 @@
          lhs.always_revalidate() == rhs.always_revalidate();
 }
 
-bool operator==(const PrefetchData& lhs, const PrefetchData& rhs) {
-  bool equal = lhs.key_type == rhs.key_type &&
-               lhs.primary_key == rhs.primary_key &&
-               lhs.resources.size() == rhs.resources.size();
+bool operator==(const RedirectStat& lhs, const RedirectStat& rhs) {
+  return lhs.url() == rhs.url() &&
+         lhs.number_of_hits() == rhs.number_of_hits() &&
+         lhs.number_of_misses() == rhs.number_of_misses() &&
+         lhs.consecutive_misses() == rhs.consecutive_misses();
+}
+
+bool operator==(const RedirectData& lhs, const RedirectData& rhs) {
+  bool equal = lhs.primary_key() == rhs.primary_key() &&
+               lhs.redirect_endpoints_size() == rhs.redirect_endpoints_size();
 
   if (!equal)
     return false;
 
-  for (size_t i = 0; i < lhs.resources.size(); ++i)
-    equal = equal && lhs.resources[i] == rhs.resources[i];
+  for (int i = 0; i < lhs.redirect_endpoints_size(); ++i)
+    equal = equal && lhs.redirect_endpoints(i) == rhs.redirect_endpoints(i);
 
   return equal;
 }
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_test_util.h b/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
index c07fc13..ff707a3 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
+++ b/chrome/browser/predictors/resource_prefetch_predictor_test_util.h
@@ -4,6 +4,8 @@
 #ifndef CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCH_PREDICTOR_TEST_UTIL_H_
 #define CHROME_BROWSER_PREDICTORS_RESOURCE_PREFETCH_PREDICTOR_TEST_UTIL_H_
 
+#include <string>
+
 #include "chrome/browser/predictors/resource_prefetch_predictor_tables.h"
 
 namespace predictors {
@@ -18,14 +20,26 @@
                                 bool has_validators,
                                 bool always_revalidate);
 
+void InitializeRedirectStat(RedirectStat* redirect,
+                            const std::string& url,
+                            int number_of_hits,
+                            int number_of_misses,
+                            int consecutive_misses);
+
+RedirectData CreateRedirectData(const std::string& primary_key);
+
 // For printing failures nicely.
-void PrintTo(const ResourceData& resource, ::std::ostream* os);
 void PrintTo(const ResourcePrefetchPredictorTables::PrefetchData& data,
              ::std::ostream* os);
+void PrintTo(const ResourceData& resource, ::std::ostream* os);
+void PrintTo(const RedirectStat& redirect, ::std::ostream* os);
+void PrintTo(const RedirectData& data, ::std::ostream* os);
 
-bool operator==(const ResourceData& lhs, const ResourceData& rhs);
 bool operator==(const ResourcePrefetchPredictorTables::PrefetchData& lhs,
                 const ResourcePrefetchPredictorTables::PrefetchData& rhs);
+bool operator==(const ResourceData& lhs, const ResourceData& rhs);
+bool operator==(const RedirectStat& lhs, const RedirectStat& rhs);
+bool operator==(const RedirectData& lhs, const RedirectData& rhs);
 
 }  // namespace predictors
 
diff --git a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
index 81f6d48..8829036b 100644
--- a/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
+++ b/chrome/browser/predictors/resource_prefetch_predictor_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <iostream>
 #include <memory>
+#include <utility>
 
 #include "base/memory/ptr_util.h"
 #include "base/memory/ref_counted.h"
@@ -24,7 +25,6 @@
 #include "net/url_request/url_request_context.h"
 #include "net/url_request/url_request_job.h"
 #include "net/url_request/url_request_test_util.h"
-#include "net/url_request/url_request_test_util.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -38,6 +38,7 @@
 typedef ResourcePrefetchPredictor::URLRequestSummary URLRequestSummary;
 typedef ResourcePrefetchPredictorTables::PrefetchData PrefetchData;
 typedef ResourcePrefetchPredictorTables::PrefetchDataMap PrefetchDataMap;
+typedef ResourcePrefetchPredictorTables::RedirectDataMap RedirectDataMap;
 
 scoped_refptr<net::HttpResponseHeaders> MakeResponseHeaders(
     const char* headers) {
@@ -127,14 +128,26 @@
  public:
   MockResourcePrefetchPredictorTables() { }
 
-  MOCK_METHOD2(GetAllData, void(PrefetchDataMap* url_data_map,
-                                PrefetchDataMap* host_data_map));
-  MOCK_METHOD2(UpdateData, void(const PrefetchData& url_data,
-                                const PrefetchData& host_data));
-  MOCK_METHOD2(DeleteData, void(const std::vector<std::string>& urls,
-                                const std::vector<std::string>& hosts));
-  MOCK_METHOD2(DeleteSingleDataPoint, void(const std::string& key,
-                                           PrefetchKeyType key_type));
+  MOCK_METHOD4(GetAllData,
+               void(PrefetchDataMap* url_data_map,
+                    PrefetchDataMap* host_data_map,
+                    RedirectDataMap* url_redirect_data_map,
+                    RedirectDataMap* host_redirect_data_map));
+  MOCK_METHOD4(UpdateData,
+               void(const PrefetchData& url_data,
+                    const PrefetchData& host_data,
+                    const RedirectData& url_redirect_data,
+                    const RedirectData& host_redirect_data));
+  MOCK_METHOD2(DeleteResourceData,
+               void(const std::vector<std::string>& urls,
+                    const std::vector<std::string>& hosts));
+  MOCK_METHOD2(DeleteSingleResourceDataPoint,
+               void(const std::string& key, PrefetchKeyType key_type));
+  MOCK_METHOD2(DeleteRedirectData,
+               void(const std::vector<std::string>& urls,
+                    const std::vector<std::string>& hosts));
+  MOCK_METHOD2(DeleteSingleRedirectDataPoint,
+               void(const std::string& key, PrefetchKeyType key_type));
   MOCK_METHOD0(DeleteAllData, void());
 
  protected:
@@ -172,19 +185,20 @@
     return navigation_id;
   }
 
-  ResourcePrefetchPredictor::URLRequestSummary CreateURLRequestSummary(
+  URLRequestSummary CreateURLRequestSummary(
       int process_id,
       int render_frame_id,
       const std::string& main_frame_url,
-      const std::string& resource_url,
-      content::ResourceType resource_type,
-      net::RequestPriority priority,
-      const std::string& mime_type,
-      bool was_cached) {
-    ResourcePrefetchPredictor::URLRequestSummary summary;
+      const std::string& resource_url = std::string(),
+      content::ResourceType resource_type = content::RESOURCE_TYPE_MAIN_FRAME,
+      net::RequestPriority priority = net::MEDIUM,
+      const std::string& mime_type = std::string(),
+      bool was_cached = false) {
+    URLRequestSummary summary;
     summary.navigation_id = CreateNavigationID(process_id, render_frame_id,
                                                main_frame_url);
-    summary.resource_url = GURL(resource_url);
+    summary.resource_url =
+        resource_url.empty() ? GURL(main_frame_url) : GURL(resource_url);
     summary.resource_type = resource_type;
     summary.priority = priority;
     summary.mime_type = mime_type;
@@ -192,6 +206,17 @@
     return summary;
   }
 
+  URLRequestSummary CreateRedirectRequestSummary(
+      int process_id,
+      int render_frame_id,
+      const std::string& main_frame_url,
+      const std::string& redirect_url) {
+    URLRequestSummary summary =
+        CreateURLRequestSummary(process_id, render_frame_id, main_frame_url);
+    summary.redirect_url = GURL(redirect_url);
+    return summary;
+  }
+
   std::unique_ptr<net::URLRequest> CreateURLRequest(
       const GURL& url,
       net::RequestPriority priority,
@@ -254,8 +279,12 @@
 
   PrefetchDataMap test_url_data_;
   PrefetchDataMap test_host_data_;
+  RedirectDataMap test_url_redirect_data_;
+  RedirectDataMap test_host_redirect_data_;
   PrefetchData empty_url_data_;
   PrefetchData empty_host_data_;
+  RedirectData empty_url_redirect_data_;
+  RedirectData empty_host_redirect_data_;
 
   MockURLRequestJobFactory url_request_job_factory_;
   EmptyURLRequestDelegate url_request_delegate_;
@@ -268,7 +297,9 @@
       profile_(new TestingProfile()),
       mock_tables_(new StrictMock<MockResourcePrefetchPredictorTables>()),
       empty_url_data_(PREFETCH_KEY_TYPE_URL, std::string()),
-      empty_host_data_(PREFETCH_KEY_TYPE_HOST, std::string()) {}
+      empty_host_data_(PREFETCH_KEY_TYPE_HOST, std::string()),
+      empty_url_redirect_data_(),
+      empty_host_redirect_data_() {}
 
 ResourcePrefetchPredictorTest::~ResourcePrefetchPredictorTest() {
   profile_.reset(NULL);
@@ -288,7 +319,9 @@
             ResourcePrefetchPredictor::NOT_INITIALIZED);
   EXPECT_CALL(*mock_tables_.get(),
               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
-                         Pointee(ContainerEq(PrefetchDataMap()))));
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))));
   InitializePredictor();
   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
   EXPECT_EQ(predictor_->initialization_state_,
@@ -373,24 +406,81 @@
     test_host_data_.insert(std::make_pair("www.facebook.com", facebook));
     test_host_data_.insert(std::make_pair("www.yahoo.com", yahoo));
   }
+
+  {  // Url redirect data.
+    RedirectData facebook;
+    facebook.set_primary_key("http://fb.com/google");
+    facebook.set_last_visit_time(6);
+    InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                           "https://facebook.com/google", 5, 1, 0);
+    InitializeRedirectStat(facebook.add_redirect_endpoints(),
+                           "https://facebook.com/login", 3, 5, 1);
+
+    RedirectData nytimes;
+    nytimes.set_primary_key("http://nyt.com");
+    nytimes.set_last_visit_time(7);
+    InitializeRedirectStat(nytimes.add_redirect_endpoints(),
+                           "https://nytimes.com", 2, 0, 0);
+
+    RedirectData google;
+    google.set_primary_key("http://google.com");
+    google.set_last_visit_time(8);
+    InitializeRedirectStat(google.add_redirect_endpoints(),
+                           "https://google.com", 3, 0, 0);
+
+    test_url_redirect_data_.clear();
+    test_url_redirect_data_.insert(
+        std::make_pair(facebook.primary_key(), facebook));
+    test_url_redirect_data_.insert(
+        std::make_pair(nytimes.primary_key(), nytimes));
+    test_url_redirect_data_.insert(
+        std::make_pair(google.primary_key(), google));
+  }
+
+  {  // Host redirect data.
+    RedirectData bbc;
+    bbc.set_primary_key("bbc.com");
+    bbc.set_last_visit_time(9);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "www.bbc.com", 8, 4,
+                           1);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "m.bbc.com", 5, 8, 0);
+    InitializeRedirectStat(bbc.add_redirect_endpoints(), "bbc.co.uk", 1, 3, 0);
+
+    RedirectData microsoft;
+    microsoft.set_primary_key("microsoft.com");
+    microsoft.set_last_visit_time(10);
+    InitializeRedirectStat(microsoft.add_redirect_endpoints(),
+                           "www.microsoft.com", 10, 0, 0);
+
+    test_host_redirect_data_.clear();
+    test_host_redirect_data_.insert(std::make_pair(bbc.primary_key(), bbc));
+    test_host_redirect_data_.insert(
+        std::make_pair(microsoft.primary_key(), microsoft));
+  }
 }
 
+// Tests that the predictor initializes correctly without any data.
 TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeEmpty) {
-  // Tests that the predictor initializes correctly without any data.
   EXPECT_TRUE(predictor_->url_table_cache_->empty());
   EXPECT_TRUE(predictor_->host_table_cache_->empty());
+  EXPECT_TRUE(predictor_->url_redirect_table_cache_->empty());
+  EXPECT_TRUE(predictor_->host_redirect_table_cache_->empty());
 }
 
+// Tests that the history and the db tables data are loaded correctly.
 TEST_F(ResourcePrefetchPredictorTest, LazilyInitializeWithData) {
-  // Tests that the history and the db tables data are loaded correctly.
   AddUrlToHistory("http://www.google.com/", 4);
   AddUrlToHistory("http://www.yahoo.com/", 2);
 
   EXPECT_CALL(*mock_tables_.get(),
               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
-                         Pointee(ContainerEq(PrefetchDataMap()))))
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))))
       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
-                      SetArgPointee<1>(test_host_data_)));
+                      SetArgPointee<1>(test_host_data_),
+                      SetArgPointee<2>(test_url_redirect_data_),
+                      SetArgPointee<3>(test_host_redirect_data_)));
 
   ResetPredictor();
   InitializePredictor();
@@ -402,56 +492,64 @@
 
   EXPECT_EQ(test_url_data_, *predictor_->url_table_cache_);
   EXPECT_EQ(test_host_data_, *predictor_->host_table_cache_);
+  EXPECT_EQ(test_url_redirect_data_, *predictor_->url_redirect_table_cache_);
+  EXPECT_EQ(test_host_redirect_data_, *predictor_->host_redirect_table_cache_);
 }
 
+// Single navigation but history count is low, so should not record.
 TEST_F(ResourcePrefetchPredictorTest, NavigationNotRecorded) {
-  // Single navigation but history count is low, so should not record.
   AddUrlToHistory("http://www.google.com", 1);
 
-  URLRequestSummary main_frame = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://www.google.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
+  URLRequestSummary main_frame =
+      CreateURLRequestSummary(1, 1, "http://www.google.com");
   predictor_->RecordURLRequest(main_frame);
   EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
 
+  URLRequestSummary main_frame_redirect = CreateRedirectRequestSummary(
+      1, 1, "http://www.google.com", "https://www.google.com");
+  predictor_->RecordURLRedirect(main_frame_redirect);
+  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
+  main_frame = CreateURLRequestSummary(1, 1, "https://www.google.com");
+
   // Now add a few subresources.
   URLRequestSummary resource1 = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://google.com/style1.css",
+      1, 1, "https://www.google.com", "https://google.com/style1.css",
       content::RESOURCE_TYPE_STYLESHEET, net::MEDIUM, "text/css", false);
   predictor_->RecordURLResponse(resource1);
   URLRequestSummary resource2 = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://google.com/script1.js",
+      1, 1, "https://www.google.com", "https://google.com/script1.js",
       content::RESOURCE_TYPE_SCRIPT, net::MEDIUM, "text/javascript", false);
   predictor_->RecordURLResponse(resource2);
   URLRequestSummary resource3 = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://google.com/script2.js",
+      1, 1, "https://www.google.com", "https://google.com/script2.js",
       content::RESOURCE_TYPE_SCRIPT, net::MEDIUM, "text/javascript", false);
   predictor_->RecordURLResponse(resource3);
 
   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
   host_data.resources.push_back(CreateResourceData(
-      "http://google.com/style1.css", content::RESOURCE_TYPE_STYLESHEET, 1, 0,
+      "https://google.com/style1.css", content::RESOURCE_TYPE_STYLESHEET, 1, 0,
       0, 1.0, net::MEDIUM, false, false));
   host_data.resources.push_back(CreateResourceData(
-      "http://google.com/script1.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
+      "https://google.com/script1.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
       2.0, net::MEDIUM, false, false));
   host_data.resources.push_back(CreateResourceData(
-      "http://google.com/script2.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
+      "https://google.com/script2.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
       3.0, net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, host_data, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
-  predictor_->OnNavigationComplete(main_frame.navigation_id);
+  predictor_->RecordMainFrameLoadComplete(main_frame.navigation_id);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 }
 
+// Single navigation that will be recorded. Will check for duplicate
+// resources and also for number of resources saved.
 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDB) {
-  // Single navigation that will be recorded. Will check for duplicate
-  // resources and also for number of resources saved.
   AddUrlToHistory("http://www.google.com", 4);
 
-  URLRequestSummary main_frame = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://www.google.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
+  URLRequestSummary main_frame =
+      CreateURLRequestSummary(1, 1, "http://www.google.com");
   predictor_->RecordURLRequest(main_frame);
   EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
 
@@ -497,24 +595,30 @@
   url_data.resources.push_back(CreateResourceData(
       "http://google.com/style2.css", content::RESOURCE_TYPE_STYLESHEET, 1, 0,
       0, 7.0, net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(url_data, empty_host_data_, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
   host_data.resources = url_data.resources;
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, host_data, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   predictor_->OnNavigationComplete(main_frame.navigation_id);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 }
 
+// Tests that navigation is recorded correctly for URL already present in
+// the database cache.
 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlInDB) {
-  // Tests that navigation is recorded correctly for URL already present in
-  // the database cache.
   AddUrlToHistory("http://www.google.com", 4);
 
   EXPECT_CALL(*mock_tables_.get(),
               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
-                         Pointee(ContainerEq(PrefetchDataMap()))))
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))))
       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
                       SetArgPointee<1>(test_host_data_)));
   ResetPredictor();
@@ -570,11 +674,12 @@
   url_data.resources.push_back(CreateResourceData(
       "http://google.com/script2.js", content::RESOURCE_TYPE_SCRIPT, 1, 0, 0,
       3.0, net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
-
-  EXPECT_CALL(
-      *mock_tables_.get(),
-      DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(url_data, empty_host_data_, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("www.facebook.com",
+                                            PREFETCH_KEY_TYPE_HOST));
 
   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.google.com");
   host_data.resources.push_back(CreateResourceData(
@@ -589,19 +694,23 @@
   host_data.resources.push_back(CreateResourceData(
       "http://google.com/style2.css", content::RESOURCE_TYPE_STYLESHEET, 1, 0,
       0, 7.0, net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, host_data, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   predictor_->OnNavigationComplete(main_frame.navigation_id);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 }
 
+// Tests that a URL is deleted before another is added if the cache is full.
 TEST_F(ResourcePrefetchPredictorTest, NavigationUrlNotInDBAndDBFull) {
-  // Tests that a URL is deleted before another is added if the cache is full.
   AddUrlToHistory("http://www.nike.com/", 4);
 
   EXPECT_CALL(*mock_tables_.get(),
               GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
-                         Pointee(ContainerEq(PrefetchDataMap()))))
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))))
       .WillOnce(DoAll(SetArgPointee<0>(test_url_data_),
                       SetArgPointee<1>(test_host_data_)));
   ResetPredictor();
@@ -624,12 +733,12 @@
       content::RESOURCE_TYPE_IMAGE, net::MEDIUM, "image/png", false);
   predictor_->RecordURLResponse(resource2);
 
-  EXPECT_CALL(
-      *mock_tables_.get(),
-      DeleteSingleDataPoint("http://www.google.com/", PREFETCH_KEY_TYPE_URL));
-  EXPECT_CALL(
-      *mock_tables_.get(),
-      DeleteSingleDataPoint("www.facebook.com", PREFETCH_KEY_TYPE_HOST));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("http://www.google.com/",
+                                            PREFETCH_KEY_TYPE_URL));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("www.facebook.com",
+                                            PREFETCH_KEY_TYPE_HOST));
 
   PrefetchData url_data(PREFETCH_KEY_TYPE_URL, "http://www.nike.com/");
   url_data.resources.push_back(CreateResourceData(
@@ -638,16 +747,126 @@
   url_data.resources.push_back(CreateResourceData(
       "http://nike.com/image2.png", content::RESOURCE_TYPE_IMAGE, 1, 0, 0, 2.0,
       net::MEDIUM, false, false));
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(url_data, empty_host_data_));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(url_data, empty_host_data_, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   PrefetchData host_data(PREFETCH_KEY_TYPE_HOST, "www.nike.com");
   host_data.resources = url_data.resources;
-  EXPECT_CALL(*mock_tables_.get(), UpdateData(empty_url_data_, host_data));
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, host_data, empty_url_redirect_data_,
+                         empty_host_redirect_data_));
 
   predictor_->OnNavigationComplete(main_frame.navigation_id);
   profile_->BlockUntilHistoryProcessesPendingRequests();
 }
 
+TEST_F(ResourcePrefetchPredictorTest, RedirectUrlNotInDB) {
+  AddUrlToHistory("https://facebook.com/google", 4);
+
+  URLRequestSummary fb1 = CreateURLRequestSummary(1, 1, "http://fb.com/google");
+  predictor_->RecordURLRequest(fb1);
+  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
+
+  URLRequestSummary fb2 = CreateRedirectRequestSummary(
+      1, 1, "http://fb.com/google", "http://facebook.com/google");
+  predictor_->RecordURLRedirect(fb2);
+  URLRequestSummary fb3 = CreateRedirectRequestSummary(
+      1, 1, "http://facebook.com/google", "https://facebook.com/google");
+  predictor_->RecordURLRedirect(fb3);
+  NavigationID fb_end = CreateNavigationID(1, 1, "https://facebook.com/google");
+
+  // Since the navigation hasn't resources, corresponding entry
+  // in resource table will be deleted.
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("https://facebook.com/google",
+                                            PREFETCH_KEY_TYPE_URL));
+  EXPECT_CALL(*mock_tables_.get(), DeleteSingleResourceDataPoint(
+                                       "facebook.com", PREFETCH_KEY_TYPE_HOST));
+
+  RedirectData url_redirect_data;
+  url_redirect_data.set_primary_key("http://fb.com/google");
+  InitializeRedirectStat(url_redirect_data.add_redirect_endpoints(),
+                         "https://facebook.com/google", 1, 0, 0);
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, empty_host_data_, url_redirect_data,
+                         empty_host_redirect_data_));
+
+  RedirectData host_redirect_data;
+  host_redirect_data.set_primary_key("fb.com");
+  InitializeRedirectStat(host_redirect_data.add_redirect_endpoints(),
+                         "facebook.com", 1, 0, 0);
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, empty_host_data_,
+                         empty_url_redirect_data_, host_redirect_data));
+
+  predictor_->RecordMainFrameLoadComplete(fb_end);
+  profile_->BlockUntilHistoryProcessesPendingRequests();
+}
+
+// Tests that redirect is recorded correctly for URL already present in
+// the database cache.
+TEST_F(ResourcePrefetchPredictorTest, RedirectUrlInDB) {
+  AddUrlToHistory("https://facebook.com/google", 4);
+
+  EXPECT_CALL(*mock_tables_.get(),
+              GetAllData(Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(PrefetchDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap())),
+                         Pointee(ContainerEq(RedirectDataMap()))))
+      .WillOnce(DoAll(SetArgPointee<2>(test_url_redirect_data_),
+                      SetArgPointee<3>(test_host_redirect_data_)));
+  ResetPredictor();
+  InitializePredictor();
+  EXPECT_EQ(3U, predictor_->url_redirect_table_cache_->size());
+  EXPECT_EQ(2U, predictor_->host_redirect_table_cache_->size());
+
+  URLRequestSummary fb1 = CreateURLRequestSummary(1, 1, "http://fb.com/google");
+  predictor_->RecordURLRequest(fb1);
+  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
+
+  URLRequestSummary fb2 = CreateRedirectRequestSummary(
+      1, 1, "http://fb.com/google", "http://facebook.com/google");
+  predictor_->RecordURLRedirect(fb2);
+  URLRequestSummary fb3 = CreateRedirectRequestSummary(
+      1, 1, "http://facebook.com/google", "https://facebook.com/google");
+  predictor_->RecordURLRedirect(fb3);
+  NavigationID fb_end = CreateNavigationID(1, 1, "https://facebook.com/google");
+
+  // Oldest entries in tables will be superseded and deleted.
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleRedirectDataPoint("bbc.com", PREFETCH_KEY_TYPE_HOST));
+
+  // Since the navigation hasn't resources, corresponding entry
+  // in resource table will be deleted.
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteSingleResourceDataPoint("https://facebook.com/google",
+                                            PREFETCH_KEY_TYPE_URL));
+  EXPECT_CALL(*mock_tables_.get(), DeleteSingleResourceDataPoint(
+                                       "facebook.com", PREFETCH_KEY_TYPE_HOST));
+
+  RedirectData url_redirect_data;
+  url_redirect_data.set_primary_key("http://fb.com/google");
+  InitializeRedirectStat(url_redirect_data.add_redirect_endpoints(),
+                         "https://facebook.com/google", 6, 1, 0);
+  // Existing redirect to https://facebook.com/login will be deleted because of
+  // too many consecutive misses.
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, empty_host_data_, url_redirect_data,
+                         empty_host_redirect_data_));
+
+  RedirectData host_redirect_data;
+  host_redirect_data.set_primary_key("fb.com");
+  InitializeRedirectStat(host_redirect_data.add_redirect_endpoints(),
+                         "facebook.com", 1, 0, 0);
+  EXPECT_CALL(*mock_tables_.get(),
+              UpdateData(empty_url_data_, empty_host_data_,
+                         empty_url_redirect_data_, host_redirect_data));
+
+  predictor_->RecordMainFrameLoadComplete(fb_end);
+  profile_->BlockUntilHistoryProcessesPendingRequests();
+}
+
 TEST_F(ResourcePrefetchPredictorTest, DeleteUrls) {
   // Add some dummy entries to cache.
   predictor_->url_table_cache_->insert(std::make_pair(
@@ -676,31 +895,61 @@
       "www.apple.com",
       PrefetchData(PREFETCH_KEY_TYPE_HOST, "www.apple.com")));
 
+  predictor_->url_redirect_table_cache_->insert(
+      std::make_pair("http://www.google.com/page1.html",
+                     CreateRedirectData("http://www.google.com/page1.html")));
+  predictor_->url_redirect_table_cache_->insert(
+      std::make_pair("http://www.google.com/page2.html",
+                     CreateRedirectData("http://www.google.com/page2.html")));
+  predictor_->url_redirect_table_cache_->insert(std::make_pair(
+      "http://www.apple.com/", CreateRedirectData("http://www.apple.com/")));
+  predictor_->url_redirect_table_cache_->insert(
+      std::make_pair("http://nyt.com/", CreateRedirectData("http://nyt.com/")));
+
+  predictor_->host_redirect_table_cache_->insert(
+      std::make_pair("www.google.com", CreateRedirectData("www.google.com")));
+  predictor_->host_redirect_table_cache_->insert(
+      std::make_pair("www.nike.com", CreateRedirectData("www.nike.com")));
+  predictor_->host_redirect_table_cache_->insert(std::make_pair(
+      "www.wikipedia.org", CreateRedirectData("www.wikipedia.org")));
+
   history::URLRows rows;
   rows.push_back(history::URLRow(GURL("http://www.google.com/page2.html")));
   rows.push_back(history::URLRow(GURL("http://www.apple.com")));
   rows.push_back(history::URLRow(GURL("http://www.nike.com")));
 
-  std::vector<std::string> urls_to_delete, hosts_to_delete;
+  std::vector<std::string> urls_to_delete, hosts_to_delete,
+      url_redirects_to_delete, host_redirects_to_delete;
   urls_to_delete.push_back("http://www.google.com/page2.html");
   urls_to_delete.push_back("http://www.apple.com/");
   urls_to_delete.push_back("http://www.nike.com/");
   hosts_to_delete.push_back("www.google.com");
   hosts_to_delete.push_back("www.apple.com");
+  url_redirects_to_delete.push_back("http://www.google.com/page2.html");
+  url_redirects_to_delete.push_back("http://www.apple.com/");
+  host_redirects_to_delete.push_back("www.google.com");
+  host_redirects_to_delete.push_back("www.nike.com");
 
-  EXPECT_CALL(
-      *mock_tables_.get(),
-      DeleteData(ContainerEq(urls_to_delete), ContainerEq(hosts_to_delete)));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteResourceData(ContainerEq(urls_to_delete),
+                                 ContainerEq(hosts_to_delete)));
+  EXPECT_CALL(*mock_tables_.get(),
+              DeleteRedirectData(ContainerEq(url_redirects_to_delete),
+                                 ContainerEq(host_redirects_to_delete)));
 
   predictor_->DeleteUrls(rows);
   EXPECT_EQ(2U, predictor_->url_table_cache_->size());
   EXPECT_EQ(1U, predictor_->host_table_cache_->size());
+  EXPECT_EQ(2U, predictor_->url_redirect_table_cache_->size());
+  EXPECT_EQ(1U, predictor_->host_redirect_table_cache_->size());
 
   EXPECT_CALL(*mock_tables_.get(), DeleteAllData());
 
   predictor_->DeleteAllUrls();
   EXPECT_TRUE(predictor_->url_table_cache_->empty());
   EXPECT_TRUE(predictor_->host_table_cache_->empty());
+  EXPECT_TRUE(predictor_->url_redirect_table_cache_->empty());
+  EXPECT_TRUE(predictor_->host_redirect_table_cache_->empty());
 }
 
 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRequest) {
@@ -721,7 +970,7 @@
   predictor_->OnMainFrameRequest(summary3);
   EXPECT_EQ(3U, predictor_->inflight_navigations_.size());
 
-  // Insert anther with same navigation id. It should replace.
+  // Insert another with same navigation id. It should replace.
   URLRequestSummary summary4 = CreateURLRequestSummary(
       1, 1, "http://www.nike.com", "http://www.nike.com",
       content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
@@ -753,30 +1002,78 @@
 }
 
 TEST_F(ResourcePrefetchPredictorTest, OnMainFrameRedirect) {
-  URLRequestSummary summary1 = CreateURLRequestSummary(
-      1, 1, "http://www.google.com", "http://www.google.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
-  URLRequestSummary summary2 = CreateURLRequestSummary(
-      1, 2, "http://www.google.com", "http://www.google.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
-  URLRequestSummary summary3 = CreateURLRequestSummary(
-      2, 1, "http://www.yahoo.com", "http://www.yahoo.com",
-      content::RESOURCE_TYPE_MAIN_FRAME, net::MEDIUM, std::string(), false);
+  URLRequestSummary yahoo = CreateURLRequestSummary(1, 1, "http://yahoo.com");
 
-  predictor_->OnMainFrameRedirect(summary1);
+  URLRequestSummary bbc1 = CreateURLRequestSummary(2, 2, "http://bbc.com");
+  URLRequestSummary bbc2 = CreateRedirectRequestSummary(2, 2, "http://bbc.com",
+                                                        "https://www.bbc.com");
+  NavigationID bbc_end = CreateNavigationID(2, 2, "https://www.bbc.com");
+
+  URLRequestSummary youtube1 =
+      CreateURLRequestSummary(1, 2, "http://youtube.com");
+  URLRequestSummary youtube2 = CreateRedirectRequestSummary(
+      1, 2, "http://youtube.com", "https://youtube.com");
+  NavigationID youtube_end = CreateNavigationID(1, 2, "https://youtube.com");
+
+  URLRequestSummary nyt1 = CreateURLRequestSummary(2, 1, "http://nyt.com");
+  URLRequestSummary nyt2 = CreateRedirectRequestSummary(2, 1, "http://nyt.com",
+                                                        "http://nytimes.com");
+  URLRequestSummary nyt3 = CreateRedirectRequestSummary(
+      2, 1, "http://nytimes.com", "http://m.nytimes.com");
+  NavigationID nyt_end = CreateNavigationID(2, 1, "http://m.nytimes.com");
+
+  URLRequestSummary fb1 = CreateURLRequestSummary(1, 3, "http://fb.com");
+  URLRequestSummary fb2 = CreateRedirectRequestSummary(1, 3, "http://fb.com",
+                                                       "http://facebook.com");
+  URLRequestSummary fb3 = CreateRedirectRequestSummary(
+      1, 3, "http://facebook.com", "https://facebook.com");
+  URLRequestSummary fb4 = CreateRedirectRequestSummary(
+      1, 3, "https://facebook.com",
+      "https://m.facebook.com/?refsrc=https%3A%2F%2Fwww.facebook.com%2F&_rdr");
+  NavigationID fb_end = CreateNavigationID(
+      1, 3,
+      "https://m.facebook.com/?refsrc=https%3A%2F%2Fwww.facebook.com%2F&_rdr");
+
+  // Redirect with empty redirect_url will be deleted.
+  predictor_->OnMainFrameRequest(yahoo);
+  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
+  predictor_->OnMainFrameRedirect(yahoo);
   EXPECT_TRUE(predictor_->inflight_navigations_.empty());
 
-  predictor_->OnMainFrameRequest(summary1);
+  // Redirect without previous request works fine.
+  // predictor_->OnMainFrameRequest(bbc1) missing.
+  predictor_->OnMainFrameRedirect(bbc2);
   EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
-  predictor_->OnMainFrameRequest(summary2);
-  EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
+  EXPECT_EQ(bbc1.navigation_id.main_frame_url,
+            predictor_->inflight_navigations_[bbc_end]->initial_url);
 
-  predictor_->OnMainFrameRedirect(summary3);
+  // http://youtube.com -> https://youtube.com.
+  predictor_->OnMainFrameRequest(youtube1);
   EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
-  predictor_->OnMainFrameRedirect(summary1);
-  EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
-  predictor_->OnMainFrameRedirect(summary2);
-  EXPECT_TRUE(predictor_->inflight_navigations_.empty());
+  predictor_->OnMainFrameRedirect(youtube2);
+  EXPECT_EQ(2U, predictor_->inflight_navigations_.size());
+  EXPECT_EQ(youtube1.navigation_id.main_frame_url,
+            predictor_->inflight_navigations_[youtube_end]->initial_url);
+
+  // http://nyt.com -> http://nytimes.com -> http://m.nytimes.com.
+  predictor_->OnMainFrameRequest(nyt1);
+  EXPECT_EQ(3U, predictor_->inflight_navigations_.size());
+  predictor_->OnMainFrameRedirect(nyt2);
+  predictor_->OnMainFrameRedirect(nyt3);
+  EXPECT_EQ(3U, predictor_->inflight_navigations_.size());
+  EXPECT_EQ(nyt1.navigation_id.main_frame_url,
+            predictor_->inflight_navigations_[nyt_end]->initial_url);
+
+  // http://fb.com -> http://facebook.com -> https://facebook.com ->
+  // https://m.facebook.com/?refsrc=https%3A%2F%2Fwww.facebook.com%2F&_rdr.
+  predictor_->OnMainFrameRequest(fb1);
+  EXPECT_EQ(4U, predictor_->inflight_navigations_.size());
+  predictor_->OnMainFrameRedirect(fb2);
+  predictor_->OnMainFrameRedirect(fb3);
+  predictor_->OnMainFrameRedirect(fb4);
+  EXPECT_EQ(4U, predictor_->inflight_navigations_.size());
+  EXPECT_EQ(fb1.navigation_id.main_frame_url,
+            predictor_->inflight_navigations_[fb_end]->initial_url);
 }
 
 TEST_F(ResourcePrefetchPredictorTest, OnSubresourceResponse) {
@@ -806,17 +1103,17 @@
   predictor_->OnSubresourceResponse(resource3);
 
   EXPECT_EQ(1U, predictor_->inflight_navigations_.size());
-  EXPECT_EQ(3U,
-      predictor_->inflight_navigations_[main_frame1.navigation_id]->size());
+  EXPECT_EQ(3U, predictor_->inflight_navigations_[main_frame1.navigation_id]
+                    ->subresource_requests.size());
   EXPECT_TRUE(URLRequestSummaryAreEqual(
-      resource1,
-      predictor_->inflight_navigations_[main_frame1.navigation_id]->at(0)));
+      resource1, predictor_->inflight_navigations_[main_frame1.navigation_id]
+                     ->subresource_requests[0]));
   EXPECT_TRUE(URLRequestSummaryAreEqual(
-      resource2,
-      predictor_->inflight_navigations_[main_frame1.navigation_id]->at(1)));
+      resource2, predictor_->inflight_navigations_[main_frame1.navigation_id]
+                     ->subresource_requests[1]));
   EXPECT_TRUE(URLRequestSummaryAreEqual(
-      resource3,
-      predictor_->inflight_navigations_[main_frame1.navigation_id]->at(2)));
+      resource3, predictor_->inflight_navigations_[main_frame1.navigation_id]
+                     ->subresource_requests[2]));
 }
 
 TEST_F(ResourcePrefetchPredictorTest, HandledResourceTypes) {
@@ -911,7 +1208,7 @@
   response_info.was_cached = true;
   url_request_job_factory_.set_response_info(response_info);
 
-  // Protocol
+  // Protocol.
   std::unique_ptr<net::URLRequest> http_image_request =
       CreateURLRequest(GURL("http://www.google.com/cat.png"), net::MEDIUM,
                        content::RESOURCE_TYPE_IMAGE, 1, 1, true);
@@ -930,7 +1227,7 @@
   EXPECT_FALSE(ResourcePrefetchPredictor::ShouldRecordResponse(
       file_image_request.get()));
 
-  // ResourceType
+  // ResourceType.
   std::unique_ptr<net::URLRequest> sub_frame_request =
       CreateURLRequest(GURL("http://www.google.com/frame.html"), net::MEDIUM,
                        content::RESOURCE_TYPE_SUB_FRAME, 1, 1, true);
@@ -973,7 +1270,7 @@
   EXPECT_FALSE(ResourcePrefetchPredictor::ShouldRecordResponse(
       prefetch_unknown_font_request.get()));
 
-  // Not main frame
+  // Not main frame.
   std::unique_ptr<net::URLRequest> font_request_sub_frame = CreateURLRequest(
       GURL("http://www.google.com/comic-sans-ms.woff"), net::MEDIUM,
       content::RESOURCE_TYPE_FONT_RESOURCE, 1, 1, false);
diff --git a/chrome/browser/resources/chromeos/keyboard_overlay_data.js b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
index 275cb4c..3501bd3 100644
--- a/chrome/browser/resources/chromeos/keyboard_overlay_data.js
+++ b/chrome/browser/resources/chromeos/keyboard_overlay_data.js
@@ -15870,6 +15870,7 @@
     'full screen<>SEARCH': 'keyboardOverlayF4',
     'g<>CTRL': 'keyboardOverlayFindTextAgain',
     'g<>CTRL<>SHIFT': 'keyboardOverlayFindPreviousText',
+    'h<>ALT<>CTRL': 'keyboardOverlayToggleHighContrastMode',
     'h<>CTRL': 'keyboardOverlayHistory',
     'i<>ALT<>SHIFT': 'keyboardOverlayReportIssue',
     'i<>CTRL<>SHIFT': 'keyboardOverlayDeveloperTools',
diff --git a/chrome/browser/resources/md_downloads/crisper.js b/chrome/browser/resources/md_downloads/crisper.js
index 34ccde3e..288a392 100644
--- a/chrome/browser/resources/md_downloads/crisper.js
+++ b/chrome/browser/resources/md_downloads/crisper.js
@@ -1,7030 +1,72 @@
 // Copyright (c) 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.
-function assert(condition, opt_message) {
-  if (!condition) {
-    var message = 'Assertion failed';
-    if (opt_message) message = message + ': ' + opt_message;
-    var error = new Error(message);
-    var global = function() {
-      return this;
-    }();
-    if (global.traceAssertionsForTesting) console.warn(error.stack);
-    throw error;
-  }
-  return condition;
-}
-
-function assertNotReached(opt_message) {
-  assert(false, opt_message || 'Unreachable code hit');
-}
-
-function assertInstanceof(value, type, opt_message) {
-  if (!(value instanceof type)) {
-    assertNotReached(opt_message || 'Value ' + value + ' is not a[n] ' + (type.name || typeof type));
-  }
-  return value;
-}
-
+function assert(condition,opt_message){if(!condition){var message="Assertion failed";if(opt_message)message=message+": "+opt_message;var error=new Error(message);var global=function(){return this}();if(global.traceAssertionsForTesting)console.warn(error.stack);throw error}return condition}function assertNotReached(opt_message){assert(false,opt_message||"Unreachable code hit")}function assertInstanceof(value,type,opt_message){if(!(value instanceof type)){assertNotReached(opt_message||"Value "+value+" is not a[n] "+(type.name||typeof type))}return value}
 // Copyright 2016 The Chromium 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 PromiseResolver() {
-  this.resolve_;
-  this.reject_;
-  this.promise_ = new Promise(function(resolve, reject) {
-    this.resolve_ = resolve;
-    this.reject_ = reject;
-  }.bind(this));
-}
-
-PromiseResolver.prototype = {
-  get promise() {
-    return this.promise_;
-  },
-  set promise(p) {
-    assertNotReached();
-  },
-  get resolve() {
-    return this.resolve_;
-  },
-  set resolve(r) {
-    assertNotReached();
-  },
-  get reject() {
-    return this.reject_;
-  },
-  set reject(s) {
-    assertNotReached();
-  }
-};
-
+function PromiseResolver(){this.resolve_;this.reject_;this.promise_=new Promise(function(resolve,reject){this.resolve_=resolve;this.reject_=reject}.bind(this))}PromiseResolver.prototype={get promise(){return this.promise_},set promise(p){assertNotReached()},get resolve(){return this.resolve_},set resolve(r){assertNotReached()},get reject(){return this.reject_},set reject(s){assertNotReached()}};
 // 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.
-var global = this;
-
-var WebUIListener;
-
-var cr = cr || function() {
-  'use strict';
-  function exportPath(name, opt_object, opt_objectToExportTo) {
-    var parts = name.split('.');
-    var cur = opt_objectToExportTo || global;
-    for (var part; parts.length && (part = parts.shift()); ) {
-      if (!parts.length && opt_object !== undefined) {
-        cur[part] = opt_object;
-      } else if (part in cur) {
-        cur = cur[part];
-      } else {
-        cur = cur[part] = {};
-      }
-    }
-    return cur;
-  }
-  function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
-    var e = new Event(propertyName + 'Change');
-    e.propertyName = propertyName;
-    e.newValue = newValue;
-    e.oldValue = oldValue;
-    target.dispatchEvent(e);
-  }
-  function getAttributeName(jsName) {
-    return jsName.replace(/([A-Z])/g, '-$1').toLowerCase();
-  }
-  var PropertyKind = {
-    JS: 'js',
-    ATTR: 'attr',
-    BOOL_ATTR: 'boolAttr'
-  };
-  function getGetter(name, kind) {
-    switch (kind) {
-     case PropertyKind.JS:
-      var privateName = name + '_';
-      return function() {
-        return this[privateName];
-      };
-
-     case PropertyKind.ATTR:
-      var attributeName = getAttributeName(name);
-      return function() {
-        return this.getAttribute(attributeName);
-      };
-
-     case PropertyKind.BOOL_ATTR:
-      var attributeName = getAttributeName(name);
-      return function() {
-        return this.hasAttribute(attributeName);
-      };
-    }
-    throw 'not reached';
-  }
-  function getSetter(name, kind, opt_setHook) {
-    switch (kind) {
-     case PropertyKind.JS:
-      var privateName = name + '_';
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          this[privateName] = value;
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-
-     case PropertyKind.ATTR:
-      var attributeName = getAttributeName(name);
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          if (value == undefined) this.removeAttribute(attributeName); else this.setAttribute(attributeName, value);
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-
-     case PropertyKind.BOOL_ATTR:
-      var attributeName = getAttributeName(name);
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          if (value) this.setAttribute(attributeName, name); else this.removeAttribute(attributeName);
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-    }
-    throw 'not reached';
-  }
-  function defineProperty(obj, name, opt_kind, opt_setHook) {
-    if (typeof obj == 'function') obj = obj.prototype;
-    var kind = opt_kind || PropertyKind.JS;
-    if (!obj.__lookupGetter__(name)) obj.__defineGetter__(name, getGetter(name, kind));
-    if (!obj.__lookupSetter__(name)) obj.__defineSetter__(name, getSetter(name, kind, opt_setHook));
-  }
-  var uidCounter = 1;
-  function createUid() {
-    return uidCounter++;
-  }
-  function getUid(item) {
-    if (item.hasOwnProperty('uid')) return item.uid;
-    return item.uid = createUid();
-  }
-  function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
-    var e = new Event(type, {
-      bubbles: opt_bubbles,
-      cancelable: opt_cancelable === undefined || opt_cancelable
-    });
-    return target.dispatchEvent(e);
-  }
-  function define(name, fun) {
-    var obj = exportPath(name);
-    var exports = fun();
-    for (var propertyName in exports) {
-      var propertyDescriptor = Object.getOwnPropertyDescriptor(exports, propertyName);
-      if (propertyDescriptor) Object.defineProperty(obj, propertyName, propertyDescriptor);
-    }
-  }
-  function addSingletonGetter(ctor) {
-    ctor.getInstance = function() {
-      return ctor.instance_ || (ctor.instance_ = new ctor());
-    };
-  }
-  function makePublic(ctor, methods, opt_target) {
-    methods.forEach(function(method) {
-      ctor[method] = function() {
-        var target = opt_target ? document.getElementById(opt_target) : ctor.getInstance();
-        return target[method + '_'].apply(target, arguments);
-      };
-    });
-  }
-  var chromeSendResolverMap = {};
-  function webUIResponse(id, isSuccess, response) {
-    var resolver = chromeSendResolverMap[id];
-    delete chromeSendResolverMap[id];
-    if (isSuccess) resolver.resolve(response); else resolver.reject(response);
-  }
-  function sendWithPromise(methodName, var_args) {
-    var args = Array.prototype.slice.call(arguments, 1);
-    var promiseResolver = new PromiseResolver();
-    var id = methodName + '_' + createUid();
-    chromeSendResolverMap[id] = promiseResolver;
-    chrome.send(methodName, [ id ].concat(args));
-    return promiseResolver.promise;
-  }
-  var webUIListenerMap = {};
-  function webUIListenerCallback(event, var_args) {
-    var eventListenersMap = webUIListenerMap[event];
-    if (!eventListenersMap) {
-      return;
-    }
-    var args = Array.prototype.slice.call(arguments, 1);
-    for (var listenerId in eventListenersMap) {
-      eventListenersMap[listenerId].apply(null, args);
-    }
-  }
-  function addWebUIListener(eventName, callback) {
-    webUIListenerMap[eventName] = webUIListenerMap[eventName] || {};
-    var uid = createUid();
-    webUIListenerMap[eventName][uid] = callback;
-    return {
-      eventName: eventName,
-      uid: uid
-    };
-  }
-  function removeWebUIListener(listener) {
-    var listenerExists = webUIListenerMap[listener.eventName] && webUIListenerMap[listener.eventName][listener.uid];
-    if (listenerExists) {
-      delete webUIListenerMap[listener.eventName][listener.uid];
-      return true;
-    }
-    return false;
-  }
-  return {
-    addSingletonGetter: addSingletonGetter,
-    createUid: createUid,
-    define: define,
-    defineProperty: defineProperty,
-    dispatchPropertyChange: dispatchPropertyChange,
-    dispatchSimpleEvent: dispatchSimpleEvent,
-    exportPath: exportPath,
-    getUid: getUid,
-    makePublic: makePublic,
-    PropertyKind: PropertyKind,
-    addWebUIListener: addWebUIListener,
-    removeWebUIListener: removeWebUIListener,
-    sendWithPromise: sendWithPromise,
-    webUIListenerCallback: webUIListenerCallback,
-    webUIResponse: webUIResponse,
-    get doc() {
-      return document;
-    },
-    get isMac() {
-      return /Mac/.test(navigator.platform);
-    },
-    get isWindows() {
-      return /Win/.test(navigator.platform);
-    },
-    get isChromeOS() {
-      return /CrOS/.test(navigator.userAgent);
-    },
-    get isLinux() {
-      return /Linux/.test(navigator.userAgent);
-    },
-    get isAndroid() {
-      return /Android/.test(navigator.userAgent);
-    },
-    get isIOS() {
-      return /iPad|iPhone|iPod/.test(navigator.platform);
-    }
-  };
-}();
-
+var global=this;var WebUIListener;var cr=cr||function(){"use strict";function exportPath(name,opt_object,opt_objectToExportTo){var parts=name.split(".");var cur=opt_objectToExportTo||global;for(var part;parts.length&&(part=parts.shift());){if(!parts.length&&opt_object!==undefined){cur[part]=opt_object}else if(part in cur){cur=cur[part]}else{cur=cur[part]={}}}return cur}function dispatchPropertyChange(target,propertyName,newValue,oldValue){var e=new Event(propertyName+"Change");e.propertyName=propertyName;e.newValue=newValue;e.oldValue=oldValue;target.dispatchEvent(e)}function getAttributeName(jsName){return jsName.replace(/([A-Z])/g,"-$1").toLowerCase()}var PropertyKind={JS:"js",ATTR:"attr",BOOL_ATTR:"boolAttr"};function getGetter(name,kind){switch(kind){case PropertyKind.JS:var privateName=name+"_";return function(){return this[privateName]};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(){return this.getAttribute(attributeName)};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(){return this.hasAttribute(attributeName)}}throw"not reached"}function getSetter(name,kind,opt_setHook){switch(kind){case PropertyKind.JS:var privateName=name+"_";return function(value){var oldValue=this[name];if(value!==oldValue){this[privateName]=value;if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this[name];if(value!==oldValue){if(value==undefined)this.removeAttribute(attributeName);else this.setAttribute(attributeName,value);if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this[name];if(value!==oldValue){if(value)this.setAttribute(attributeName,name);else this.removeAttribute(attributeName);if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}}}throw"not reached"}function defineProperty(obj,name,opt_kind,opt_setHook){if(typeof obj=="function")obj=obj.prototype;var kind=opt_kind||PropertyKind.JS;if(!obj.__lookupGetter__(name))obj.__defineGetter__(name,getGetter(name,kind));if(!obj.__lookupSetter__(name))obj.__defineSetter__(name,getSetter(name,kind,opt_setHook))}var uidCounter=1;function createUid(){return uidCounter++}function getUid(item){if(item.hasOwnProperty("uid"))return item.uid;return item.uid=createUid()}function dispatchSimpleEvent(target,type,opt_bubbles,opt_cancelable){var e=new Event(type,{bubbles:opt_bubbles,cancelable:opt_cancelable===undefined||opt_cancelable});return target.dispatchEvent(e)}function define(name,fun){var obj=exportPath(name);var exports=fun();for(var propertyName in exports){var propertyDescriptor=Object.getOwnPropertyDescriptor(exports,propertyName);if(propertyDescriptor)Object.defineProperty(obj,propertyName,propertyDescriptor)}}function addSingletonGetter(ctor){ctor.getInstance=function(){return ctor.instance_||(ctor.instance_=new ctor)}}function makePublic(ctor,methods,opt_target){methods.forEach(function(method){ctor[method]=function(){var target=opt_target?document.getElementById(opt_target):ctor.getInstance();return target[method+"_"].apply(target,arguments)}})}var chromeSendResolverMap={};function webUIResponse(id,isSuccess,response){var resolver=chromeSendResolverMap[id];delete chromeSendResolverMap[id];if(isSuccess)resolver.resolve(response);else resolver.reject(response)}function sendWithPromise(methodName,var_args){var args=Array.prototype.slice.call(arguments,1);var promiseResolver=new PromiseResolver;var id=methodName+"_"+createUid();chromeSendResolverMap[id]=promiseResolver;chrome.send(methodName,[id].concat(args));return promiseResolver.promise}var webUIListenerMap={};function webUIListenerCallback(event,var_args){var eventListenersMap=webUIListenerMap[event];if(!eventListenersMap){return}var args=Array.prototype.slice.call(arguments,1);for(var listenerId in eventListenersMap){eventListenersMap[listenerId].apply(null,args)}}function addWebUIListener(eventName,callback){webUIListenerMap[eventName]=webUIListenerMap[eventName]||{};var uid=createUid();webUIListenerMap[eventName][uid]=callback;return{eventName:eventName,uid:uid}}function removeWebUIListener(listener){var listenerExists=webUIListenerMap[listener.eventName]&&webUIListenerMap[listener.eventName][listener.uid];if(listenerExists){delete webUIListenerMap[listener.eventName][listener.uid];return true}return false}return{addSingletonGetter:addSingletonGetter,createUid:createUid,define:define,defineProperty:defineProperty,dispatchPropertyChange:dispatchPropertyChange,dispatchSimpleEvent:dispatchSimpleEvent,exportPath:exportPath,getUid:getUid,makePublic:makePublic,PropertyKind:PropertyKind,addWebUIListener:addWebUIListener,removeWebUIListener:removeWebUIListener,sendWithPromise:sendWithPromise,webUIListenerCallback:webUIListenerCallback,webUIResponse:webUIResponse,get doc(){return document},get isMac(){return/Mac/.test(navigator.platform)},get isWindows(){return/Win/.test(navigator.platform)},get isChromeOS(){return/CrOS/.test(navigator.userAgent)},get isLinux(){return/Linux/.test(navigator.userAgent)},get isAndroid(){return/Android/.test(navigator.userAgent)},get isIOS(){return/iPad|iPhone|iPod/.test(navigator.platform)}}}();
 // 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.
-cr.define('cr.ui', function() {
-  function decorate(source, constr) {
-    var elements;
-    if (typeof source == 'string') elements = cr.doc.querySelectorAll(source); else elements = [ source ];
-    for (var i = 0, el; el = elements[i]; i++) {
-      if (!(el instanceof constr)) constr.decorate(el);
-    }
-  }
-  function createElementHelper(tagName, opt_bag) {
-    var doc;
-    if (opt_bag && opt_bag.ownerDocument) doc = opt_bag.ownerDocument; else doc = cr.doc;
-    return doc.createElement(tagName);
-  }
-  function define(tagNameOrFunction) {
-    var createFunction, tagName;
-    if (typeof tagNameOrFunction == 'function') {
-      createFunction = tagNameOrFunction;
-      tagName = '';
-    } else {
-      createFunction = createElementHelper;
-      tagName = tagNameOrFunction;
-    }
-    function f(opt_propertyBag) {
-      var el = createFunction(tagName, opt_propertyBag);
-      f.decorate(el);
-      for (var propertyName in opt_propertyBag) {
-        el[propertyName] = opt_propertyBag[propertyName];
-      }
-      return el;
-    }
-    f.decorate = function(el) {
-      el.__proto__ = f.prototype;
-      el.decorate();
-    };
-    return f;
-  }
-  function limitInputWidth(el, parentEl, min, opt_scale) {
-    el.style.width = '10px';
-    var doc = el.ownerDocument;
-    var win = doc.defaultView;
-    var computedStyle = win.getComputedStyle(el);
-    var parentComputedStyle = win.getComputedStyle(parentEl);
-    var rtl = computedStyle.direction == 'rtl';
-    var inputRect = el.getBoundingClientRect();
-    var parentRect = parentEl.getBoundingClientRect();
-    var startPos = rtl ? parentRect.right - inputRect.right : inputRect.left - parentRect.left;
-    var inner = parseInt(computedStyle.borderLeftWidth, 10) + parseInt(computedStyle.paddingLeft, 10) + parseInt(computedStyle.paddingRight, 10) + parseInt(computedStyle.borderRightWidth, 10);
-    var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) : parseInt(parentComputedStyle.paddingRight, 10);
-    var max = parentEl.clientWidth - startPos - inner - parentPadding;
-    if (opt_scale) max *= opt_scale;
-    function limit() {
-      if (el.scrollWidth > max) {
-        el.style.width = max + 'px';
-      } else {
-        el.style.width = 0;
-        var sw = el.scrollWidth;
-        if (sw < min) {
-          el.style.width = min + 'px';
-        } else {
-          el.style.width = sw + 'px';
-        }
-      }
-    }
-    el.addEventListener('input', limit);
-    limit();
-  }
-  function toCssPx(pixels) {
-    if (!window.isFinite(pixels)) console.error('Pixel value is not a number: ' + pixels);
-    return Math.round(pixels) + 'px';
-  }
-  function swallowDoubleClick(e) {
-    var doc = e.target.ownerDocument;
-    var counter = Math.min(1, e.detail);
-    function swallow(e) {
-      e.stopPropagation();
-      e.preventDefault();
-    }
-    function onclick(e) {
-      if (e.detail > counter) {
-        counter = e.detail;
-        swallow(e);
-      } else {
-        doc.removeEventListener('dblclick', swallow, true);
-        doc.removeEventListener('click', onclick, true);
-      }
-    }
-    setTimeout(function() {
-      doc.addEventListener('click', onclick, true);
-      doc.addEventListener('dblclick', swallow, true);
-    }, 0);
-  }
-  return {
-    decorate: decorate,
-    define: define,
-    limitInputWidth: limitInputWidth,
-    toCssPx: toCssPx,
-    swallowDoubleClick: swallowDoubleClick
-  };
-});
-
+cr.define("cr.ui",function(){function decorate(source,constr){var elements;if(typeof source=="string")elements=cr.doc.querySelectorAll(source);else elements=[source];for(var i=0,el;el=elements[i];i++){if(!(el instanceof constr))constr.decorate(el)}}function createElementHelper(tagName,opt_bag){var doc;if(opt_bag&&opt_bag.ownerDocument)doc=opt_bag.ownerDocument;else doc=cr.doc;return doc.createElement(tagName)}function define(tagNameOrFunction){var createFunction,tagName;if(typeof tagNameOrFunction=="function"){createFunction=tagNameOrFunction;tagName=""}else{createFunction=createElementHelper;tagName=tagNameOrFunction}function f(opt_propertyBag){var el=createFunction(tagName,opt_propertyBag);f.decorate(el);for(var propertyName in opt_propertyBag){el[propertyName]=opt_propertyBag[propertyName]}return el}f.decorate=function(el){el.__proto__=f.prototype;el.decorate()};return f}function limitInputWidth(el,parentEl,min,opt_scale){el.style.width="10px";var doc=el.ownerDocument;var win=doc.defaultView;var computedStyle=win.getComputedStyle(el);var parentComputedStyle=win.getComputedStyle(parentEl);var rtl=computedStyle.direction=="rtl";var inputRect=el.getBoundingClientRect();var parentRect=parentEl.getBoundingClientRect();var startPos=rtl?parentRect.right-inputRect.right:inputRect.left-parentRect.left;var inner=parseInt(computedStyle.borderLeftWidth,10)+parseInt(computedStyle.paddingLeft,10)+parseInt(computedStyle.paddingRight,10)+parseInt(computedStyle.borderRightWidth,10);var parentPadding=rtl?parseInt(parentComputedStyle.paddingLeft,10):parseInt(parentComputedStyle.paddingRight,10);var max=parentEl.clientWidth-startPos-inner-parentPadding;if(opt_scale)max*=opt_scale;function limit(){if(el.scrollWidth>max){el.style.width=max+"px"}else{el.style.width=0;var sw=el.scrollWidth;if(sw<min){el.style.width=min+"px"}else{el.style.width=sw+"px"}}}el.addEventListener("input",limit);limit()}function toCssPx(pixels){if(!window.isFinite(pixels))console.error("Pixel value is not a number: "+pixels);return Math.round(pixels)+"px"}function swallowDoubleClick(e){var doc=e.target.ownerDocument;var counter=Math.min(1,e.detail);function swallow(e){e.stopPropagation();e.preventDefault()}function onclick(e){if(e.detail>counter){counter=e.detail;swallow(e)}else{doc.removeEventListener("dblclick",swallow,true);doc.removeEventListener("click",onclick,true)}}setTimeout(function(){doc.addEventListener("click",onclick,true);doc.addEventListener("dblclick",swallow,true)},0)}return{decorate:decorate,define:define,limitInputWidth:limitInputWidth,toCssPx:toCssPx,swallowDoubleClick:swallowDoubleClick}});
 // 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.
-cr.define('cr.ui', function() {
-  function KeyboardShortcut(shortcut) {
-    var mods = {};
-    var ident = '';
-    shortcut.split('|').forEach(function(part) {
-      var partLc = part.toLowerCase();
-      switch (partLc) {
-       case 'alt':
-       case 'ctrl':
-       case 'meta':
-       case 'shift':
-        mods[partLc + 'Key'] = true;
-        break;
-
-       default:
-        if (ident) throw Error('Invalid shortcut');
-        ident = part;
-      }
-    });
-    this.ident_ = ident;
-    this.mods_ = mods;
-  }
-  KeyboardShortcut.prototype = {
-    matchesEvent: function(e) {
-      if (e.key == this.ident_) {
-        var mods = this.mods_;
-        return [ 'altKey', 'ctrlKey', 'metaKey', 'shiftKey' ].every(function(k) {
-          return e[k] == !!mods[k];
-        });
-      }
-      return false;
-    }
-  };
-  var Command = cr.ui.define('command');
-  Command.prototype = {
-    __proto__: HTMLElement.prototype,
-    decorate: function() {
-      CommandManager.init(assert(this.ownerDocument));
-      if (this.hasAttribute('shortcut')) this.shortcut = this.getAttribute('shortcut');
-    },
-    execute: function(opt_element) {
-      if (this.disabled) return;
-      var doc = this.ownerDocument;
-      if (doc.activeElement) {
-        var e = new Event('command', {
-          bubbles: true
-        });
-        e.command = this;
-        (opt_element || doc.activeElement).dispatchEvent(e);
-      }
-    },
-    canExecuteChange: function(opt_node) {
-      dispatchCanExecuteEvent(this, opt_node || this.ownerDocument.activeElement);
-    },
-    shortcut_: '',
-    get shortcut() {
-      return this.shortcut_;
-    },
-    set shortcut(shortcut) {
-      var oldShortcut = this.shortcut_;
-      if (shortcut !== oldShortcut) {
-        this.keyboardShortcuts_ = shortcut.split(/\s+/).map(function(shortcut) {
-          return new KeyboardShortcut(shortcut);
-        });
-        this.shortcut_ = shortcut;
-        cr.dispatchPropertyChange(this, 'shortcut', this.shortcut_, oldShortcut);
-      }
-    },
-    matchesEvent: function(e) {
-      if (!this.keyboardShortcuts_) return false;
-      return this.keyboardShortcuts_.some(function(keyboardShortcut) {
-        return keyboardShortcut.matchesEvent(e);
-      });
-    }
-  };
-  cr.defineProperty(Command, 'label', cr.PropertyKind.ATTR);
-  cr.defineProperty(Command, 'disabled', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'hideShortcutText', cr.PropertyKind.BOOL_ATTR);
-  function dispatchCanExecuteEvent(command, target) {
-    var e = new CanExecuteEvent(command);
-    target.dispatchEvent(e);
-    command.disabled = !e.canExecute;
-  }
-  var commandManagers = {};
-  function CommandManager(doc) {
-    doc.addEventListener('focus', this.handleFocus_.bind(this), true);
-    doc.addEventListener('keydown', this.handleKeyDown_.bind(this), false);
-  }
-  CommandManager.init = function(doc) {
-    var uid = cr.getUid(doc);
-    if (!(uid in commandManagers)) {
-      commandManagers[uid] = new CommandManager(doc);
-    }
-  };
-  CommandManager.prototype = {
-    handleFocus_: function(e) {
-      var target = e.target;
-      if (target.menu || target.command) return;
-      var commands = Array.prototype.slice.call(target.ownerDocument.querySelectorAll('command'));
-      commands.forEach(function(command) {
-        dispatchCanExecuteEvent(command, target);
-      });
-    },
-    handleKeyDown_: function(e) {
-      var target = e.target;
-      var commands = Array.prototype.slice.call(target.ownerDocument.querySelectorAll('command'));
-      for (var i = 0, command; command = commands[i]; i++) {
-        if (command.matchesEvent(e)) {
-          command.canExecuteChange();
-          if (!command.disabled) {
-            e.preventDefault();
-            e.stopPropagation();
-            command.execute();
-            return;
-          }
-        }
-      }
-    }
-  };
-  function CanExecuteEvent(command) {
-    var e = new Event('canExecute', {
-      bubbles: true,
-      cancelable: true
-    });
-    e.__proto__ = CanExecuteEvent.prototype;
-    e.command = command;
-    return e;
-  }
-  CanExecuteEvent.prototype = {
-    __proto__: Event.prototype,
-    command: null,
-    canExecute_: false,
-    get canExecute() {
-      return this.canExecute_;
-    },
-    set canExecute(canExecute) {
-      this.canExecute_ = !!canExecute;
-      this.stopPropagation();
-      this.preventDefault();
-    }
-  };
-  return {
-    Command: Command,
-    CanExecuteEvent: CanExecuteEvent
-  };
-});
-
+cr.define("cr.ui",function(){function KeyboardShortcut(shortcut){var mods={};var ident="";shortcut.split("|").forEach(function(part){var partLc=part.toLowerCase();switch(partLc){case"alt":case"ctrl":case"meta":case"shift":mods[partLc+"Key"]=true;break;default:if(ident)throw Error("Invalid shortcut");ident=part}});this.ident_=ident;this.mods_=mods}KeyboardShortcut.prototype={matchesEvent:function(e){if(e.key==this.ident_){var mods=this.mods_;return["altKey","ctrlKey","metaKey","shiftKey"].every(function(k){return e[k]==!!mods[k]})}return false}};var Command=cr.ui.define("command");Command.prototype={__proto__:HTMLElement.prototype,decorate:function(){CommandManager.init(assert(this.ownerDocument));if(this.hasAttribute("shortcut"))this.shortcut=this.getAttribute("shortcut")},execute:function(opt_element){if(this.disabled)return;var doc=this.ownerDocument;if(doc.activeElement){var e=new Event("command",{bubbles:true});e.command=this;(opt_element||doc.activeElement).dispatchEvent(e)}},canExecuteChange:function(opt_node){dispatchCanExecuteEvent(this,opt_node||this.ownerDocument.activeElement)},shortcut_:"",get shortcut(){return this.shortcut_},set shortcut(shortcut){var oldShortcut=this.shortcut_;if(shortcut!==oldShortcut){this.keyboardShortcuts_=shortcut.split(/\s+/).map(function(shortcut){return new KeyboardShortcut(shortcut)});this.shortcut_=shortcut;cr.dispatchPropertyChange(this,"shortcut",this.shortcut_,oldShortcut)}},matchesEvent:function(e){if(!this.keyboardShortcuts_)return false;return this.keyboardShortcuts_.some(function(keyboardShortcut){return keyboardShortcut.matchesEvent(e)})}};cr.defineProperty(Command,"label",cr.PropertyKind.ATTR);cr.defineProperty(Command,"disabled",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hidden",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"checked",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hideShortcutText",cr.PropertyKind.BOOL_ATTR);function dispatchCanExecuteEvent(command,target){var e=new CanExecuteEvent(command);target.dispatchEvent(e);command.disabled=!e.canExecute}var commandManagers={};function CommandManager(doc){doc.addEventListener("focus",this.handleFocus_.bind(this),true);doc.addEventListener("keydown",this.handleKeyDown_.bind(this),false)}CommandManager.init=function(doc){var uid=cr.getUid(doc);if(!(uid in commandManagers)){commandManagers[uid]=new CommandManager(doc)}};CommandManager.prototype={handleFocus_:function(e){var target=e.target;if(target.menu||target.command)return;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));commands.forEach(function(command){dispatchCanExecuteEvent(command,target)})},handleKeyDown_:function(e){var target=e.target;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));for(var i=0,command;command=commands[i];i++){if(command.matchesEvent(e)){command.canExecuteChange();if(!command.disabled){e.preventDefault();e.stopPropagation();command.execute();return}}}}};function CanExecuteEvent(command){var e=new Event("canExecute",{bubbles:true,cancelable:true});e.__proto__=CanExecuteEvent.prototype;e.command=command;return e}CanExecuteEvent.prototype={__proto__:Event.prototype,command:null,canExecute_:false,get canExecute(){return this.canExecute_},set canExecute(canExecute){this.canExecute_=!!canExecute;this.stopPropagation();this.preventDefault()}};return{Command:Command,CanExecuteEvent:CanExecuteEvent}});
 // 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.
-function $(id) {
-  var el = document.getElementById(id);
-  return el ? assertInstanceof(el, HTMLElement) : null;
-}
-
-function getSVGElement(id) {
-  var el = document.getElementById(id);
-  return el ? assertInstanceof(el, Element) : null;
-}
-
-function announceAccessibleMessage(msg) {
-  var element = document.createElement('div');
-  element.setAttribute('aria-live', 'polite');
-  element.style.position = 'relative';
-  element.style.left = '-9999px';
-  element.style.height = '0px';
-  element.innerText = msg;
-  document.body.appendChild(element);
-  window.setTimeout(function() {
-    document.body.removeChild(element);
-  }, 0);
-}
-
-function url(s) {
-  var s2 = s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g, '\\$1');
-  if (/\\\\$/.test(s2)) {
-    s2 += ' ';
-  }
-  return 'url("' + s2 + '")';
-}
-
-function parseQueryParams(location) {
-  var params = {};
-  var query = unescape(location.search.substring(1));
-  var vars = query.split('&');
-  for (var i = 0; i < vars.length; i++) {
-    var pair = vars[i].split('=');
-    params[pair[0]] = pair[1];
-  }
-  return params;
-}
-
-function setQueryParam(location, key, value) {
-  var query = parseQueryParams(location);
-  query[encodeURIComponent(key)] = encodeURIComponent(value);
-  var newQuery = '';
-  for (var q in query) {
-    newQuery += (newQuery ? '&' : '?') + q + '=' + query[q];
-  }
-  return location.origin + location.pathname + newQuery + location.hash;
-}
-
-function findAncestorByClass(el, className) {
-  return findAncestor(el, function(el) {
-    return el.classList && el.classList.contains(className);
-  });
-}
-
-function findAncestor(node, predicate) {
-  var last = false;
-  while (node != null && !(last = predicate(node))) {
-    node = node.parentNode;
-  }
-  return last ? node : null;
-}
-
-function swapDomNodes(a, b) {
-  var afterA = a.nextSibling;
-  if (afterA == b) {
-    swapDomNodes(b, a);
-    return;
-  }
-  var aParent = a.parentNode;
-  b.parentNode.replaceChild(a, b);
-  aParent.insertBefore(b, afterA);
-}
-
-function disableTextSelectAndDrag(opt_allowSelectStart, opt_allowDragStart) {
-  document.onselectstart = function(e) {
-    if (!(opt_allowSelectStart && opt_allowSelectStart.call(this, e))) e.preventDefault();
-  };
-  document.ondragstart = function(e) {
-    if (!(opt_allowDragStart && opt_allowDragStart.call(this, e))) e.preventDefault();
-  };
-}
-
-function preventDefaultOnPoundLinkClicks() {
-  document.addEventListener('click', function(e) {
-    var anchor = findAncestor(e.target, function(el) {
-      return el.tagName == 'A';
-    });
-    if (anchor && anchor.getAttribute('href') == '#') e.preventDefault();
-  });
-}
-
-function isRTL() {
-  return document.documentElement.dir == 'rtl';
-}
-
-function getRequiredElement(id) {
-  return assertInstanceof($(id), HTMLElement, 'Missing required element: ' + id);
-}
-
-function queryRequiredElement(selectors, opt_context) {
-  var element = (opt_context || document).querySelector(selectors);
-  return assertInstanceof(element, HTMLElement, 'Missing required element: ' + selectors);
-}
-
-[ 'click', 'auxclick' ].forEach(function(eventName) {
-  document.addEventListener(eventName, function(e) {
-    if (e.button > 1) return;
-    if (e.defaultPrevented) return;
-    var eventPath = e.path;
-    var anchor = null;
-    if (eventPath) {
-      for (var i = 0; i < eventPath.length; i++) {
-        var element = eventPath[i];
-        if (element.tagName === 'A' && element.href) {
-          anchor = element;
-          break;
-        }
-      }
-    }
-    var el = e.target;
-    if (!anchor && el.nodeType == Node.ELEMENT_NODE && el.webkitMatchesSelector('A, A *')) {
-      while (el.tagName != 'A') {
-        el = el.parentElement;
-      }
-      anchor = el;
-    }
-    if (!anchor) return;
-    anchor = anchor;
-    if ((anchor.protocol == 'file:' || anchor.protocol == 'about:') && (e.button == 0 || e.button == 1)) {
-      chrome.send('navigateToUrl', [ anchor.href, anchor.target, e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey ]);
-      e.preventDefault();
-    }
-  });
-});
-
-function appendParam(url, key, value) {
-  var param = encodeURIComponent(key) + '=' + encodeURIComponent(value);
-  if (url.indexOf('?') == -1) return url + '?' + param;
-  return url + '&' + param;
-}
-
-function createElementWithClassName(type, className) {
-  var elm = document.createElement(type);
-  elm.className = className;
-  return elm;
-}
-
-function ensureTransitionEndEvent(el, opt_timeOut) {
-  if (opt_timeOut === undefined) {
-    var style = getComputedStyle(el);
-    opt_timeOut = parseFloat(style.transitionDuration) * 1e3;
-    opt_timeOut += 50;
-  }
-  var fired = false;
-  el.addEventListener('webkitTransitionEnd', function f(e) {
-    el.removeEventListener('webkitTransitionEnd', f);
-    fired = true;
-  });
-  window.setTimeout(function() {
-    if (!fired) cr.dispatchSimpleEvent(el, 'webkitTransitionEnd', true);
-  }, opt_timeOut);
-}
-
-function scrollTopForDocument(doc) {
-  return doc.documentElement.scrollTop || doc.body.scrollTop;
-}
-
-function setScrollTopForDocument(doc, value) {
-  doc.documentElement.scrollTop = doc.body.scrollTop = value;
-}
-
-function scrollLeftForDocument(doc) {
-  return doc.documentElement.scrollLeft || doc.body.scrollLeft;
-}
-
-function setScrollLeftForDocument(doc, value) {
-  doc.documentElement.scrollLeft = doc.body.scrollLeft = value;
-}
-
-function HTMLEscape(original) {
-  return original.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;').replace(/'/g, '&#39;');
-}
-
-function elide(original, maxLength) {
-  if (original.length <= maxLength) return original;
-  return original.substring(0, maxLength - 1) + '…';
-}
-
-function quoteString(str) {
-  return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g, '\\$1');
-}
-
-function listenOnce(target, eventNames, callback) {
-  if (!Array.isArray(eventNames)) eventNames = eventNames.split(/ +/);
-  var removeAllAndCallCallback = function(event) {
-    eventNames.forEach(function(eventName) {
-      target.removeEventListener(eventName, removeAllAndCallCallback, false);
-    });
-    return callback(event);
-  };
-  eventNames.forEach(function(eventName) {
-    target.addEventListener(eventName, removeAllAndCallCallback, false);
-  });
-}
-
+function $(id){var el=document.getElementById(id);return el?assertInstanceof(el,HTMLElement):null}function getSVGElement(id){var el=document.getElementById(id);return el?assertInstanceof(el,Element):null}function announceAccessibleMessage(msg){var element=document.createElement("div");element.setAttribute("aria-live","polite");element.style.position="relative";element.style.left="-9999px";element.style.height="0px";element.innerText=msg;document.body.appendChild(element);window.setTimeout(function(){document.body.removeChild(element)},0)}function url(s){var s2=s.replace(/(\(|\)|\,|\s|\'|\"|\\)/g,"\\$1");if(/\\\\$/.test(s2)){s2+=" "}return'url("'+s2+'")'}function parseQueryParams(location){var params={};var query=unescape(location.search.substring(1));var vars=query.split("&");for(var i=0;i<vars.length;i++){var pair=vars[i].split("=");params[pair[0]]=pair[1]}return params}function setQueryParam(location,key,value){var query=parseQueryParams(location);query[encodeURIComponent(key)]=encodeURIComponent(value);var newQuery="";for(var q in query){newQuery+=(newQuery?"&":"?")+q+"="+query[q]}return location.origin+location.pathname+newQuery+location.hash}function findAncestorByClass(el,className){return findAncestor(el,function(el){return el.classList&&el.classList.contains(className)})}function findAncestor(node,predicate){var last=false;while(node!=null&&!(last=predicate(node))){node=node.parentNode}return last?node:null}function swapDomNodes(a,b){var afterA=a.nextSibling;if(afterA==b){swapDomNodes(b,a);return}var aParent=a.parentNode;b.parentNode.replaceChild(a,b);aParent.insertBefore(b,afterA)}function disableTextSelectAndDrag(opt_allowSelectStart,opt_allowDragStart){document.onselectstart=function(e){if(!(opt_allowSelectStart&&opt_allowSelectStart.call(this,e)))e.preventDefault()};document.ondragstart=function(e){if(!(opt_allowDragStart&&opt_allowDragStart.call(this,e)))e.preventDefault()}}function preventDefaultOnPoundLinkClicks(){document.addEventListener("click",function(e){var anchor=findAncestor(e.target,function(el){return el.tagName=="A"});if(anchor&&anchor.getAttribute("href")=="#")e.preventDefault()})}function isRTL(){return document.documentElement.dir=="rtl"}function getRequiredElement(id){return assertInstanceof($(id),HTMLElement,"Missing required element: "+id)}function queryRequiredElement(selectors,opt_context){var element=(opt_context||document).querySelector(selectors);return assertInstanceof(element,HTMLElement,"Missing required element: "+selectors)}["click","auxclick"].forEach(function(eventName){document.addEventListener(eventName,function(e){if(e.button>1)return;if(e.defaultPrevented)return;var eventPath=e.path;var anchor=null;if(eventPath){for(var i=0;i<eventPath.length;i++){var element=eventPath[i];if(element.tagName==="A"&&element.href){anchor=element;break}}}var el=e.target;if(!anchor&&el.nodeType==Node.ELEMENT_NODE&&el.webkitMatchesSelector("A, A *")){while(el.tagName!="A"){el=el.parentElement}anchor=el}if(!anchor)return;anchor=anchor;if((anchor.protocol=="file:"||anchor.protocol=="about:")&&(e.button==0||e.button==1)){chrome.send("navigateToUrl",[anchor.href,anchor.target,e.button,e.altKey,e.ctrlKey,e.metaKey,e.shiftKey]);e.preventDefault()}})});function appendParam(url,key,value){var param=encodeURIComponent(key)+"="+encodeURIComponent(value);if(url.indexOf("?")==-1)return url+"?"+param;return url+"&"+param}function createElementWithClassName(type,className){var elm=document.createElement(type);elm.className=className;return elm}function ensureTransitionEndEvent(el,opt_timeOut){if(opt_timeOut===undefined){var style=getComputedStyle(el);opt_timeOut=parseFloat(style.transitionDuration)*1e3;opt_timeOut+=50}var fired=false;el.addEventListener("webkitTransitionEnd",function f(e){el.removeEventListener("webkitTransitionEnd",f);fired=true});window.setTimeout(function(){if(!fired)cr.dispatchSimpleEvent(el,"webkitTransitionEnd",true)},opt_timeOut)}function scrollTopForDocument(doc){return doc.documentElement.scrollTop||doc.body.scrollTop}function setScrollTopForDocument(doc,value){doc.documentElement.scrollTop=doc.body.scrollTop=value}function scrollLeftForDocument(doc){return doc.documentElement.scrollLeft||doc.body.scrollLeft}function setScrollLeftForDocument(doc,value){doc.documentElement.scrollLeft=doc.body.scrollLeft=value}function HTMLEscape(original){return original.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;").replace(/'/g,"&#39;")}function elide(original,maxLength){if(original.length<=maxLength)return original;return original.substring(0,maxLength-1)+"…"}function quoteString(str){return str.replace(/([\\\.\+\*\?\[\^\]\$\(\)\{\}\=\!\<\>\|\:])/g,"\\$1")}function listenOnce(target,eventNames,callback){if(!Array.isArray(eventNames))eventNames=eventNames.split(/ +/);var removeAllAndCallCallback=function(event){eventNames.forEach(function(eventName){target.removeEventListener(eventName,removeAllAndCallCallback,false)});return callback(event)};eventNames.forEach(function(eventName){target.addEventListener(eventName,removeAllAndCallCallback,false)})}
 // <if expr="is_ios">
-if (!('key' in KeyboardEvent.prototype)) {
-  Object.defineProperty(KeyboardEvent.prototype, 'key', {
-    get: function() {
-      if (this.keyCode >= 48 && this.keyCode <= 57) return String.fromCharCode(this.keyCode);
-      if (this.keyCode >= 65 && this.keyCode <= 90) {
-        var result = String.fromCharCode(this.keyCode).toLowerCase();
-        if (this.shiftKey) result = result.toUpperCase();
-        return result;
-      }
-      switch (this.keyCode) {
-       case 8:
-        return 'Backspace';
-
-       case 9:
-        return 'Tab';
-
-       case 13:
-        return 'Enter';
-
-       case 16:
-        return 'Shift';
-
-       case 17:
-        return 'Control';
-
-       case 18:
-        return 'Alt';
-
-       case 27:
-        return 'Escape';
-
-       case 32:
-        return ' ';
-
-       case 33:
-        return 'PageUp';
-
-       case 34:
-        return 'PageDown';
-
-       case 35:
-        return 'End';
-
-       case 36:
-        return 'Home';
-
-       case 37:
-        return 'ArrowLeft';
-
-       case 38:
-        return 'ArrowUp';
-
-       case 39:
-        return 'ArrowRight';
-
-       case 40:
-        return 'ArrowDown';
-
-       case 45:
-        return 'Insert';
-
-       case 46:
-        return 'Delete';
-
-       case 91:
-        return 'Meta';
-
-       case 112:
-        return 'F1';
-
-       case 113:
-        return 'F2';
-
-       case 114:
-        return 'F3';
-
-       case 115:
-        return 'F4';
-
-       case 116:
-        return 'F5';
-
-       case 117:
-        return 'F6';
-
-       case 118:
-        return 'F7';
-
-       case 119:
-        return 'F8';
-
-       case 120:
-        return 'F9';
-
-       case 121:
-        return 'F10';
-
-       case 122:
-        return 'F11';
-
-       case 123:
-        return 'F12';
-
-       case 187:
-        return '=';
-
-       case 189:
-        return '-';
-
-       case 219:
-        return '[';
-
-       case 221:
-        return ']';
-      }
-      return 'Unidentified';
-    }
-  });
-} else {
-  window.console.log("KeyboardEvent.Key polyfill not required");
-}
-
+if(!("key"in KeyboardEvent.prototype)){Object.defineProperty(KeyboardEvent.prototype,"key",{get:function(){if(this.keyCode>=48&&this.keyCode<=57)return String.fromCharCode(this.keyCode);if(this.keyCode>=65&&this.keyCode<=90){var result=String.fromCharCode(this.keyCode).toLowerCase();if(this.shiftKey)result=result.toUpperCase();return result}switch(this.keyCode){case 8:return"Backspace";case 9:return"Tab";case 13:return"Enter";case 16:return"Shift";case 17:return"Control";case 18:return"Alt";case 27:return"Escape";case 32:return" ";case 33:return"PageUp";case 34:return"PageDown";case 35:return"End";case 36:return"Home";case 37:return"ArrowLeft";case 38:return"ArrowUp";case 39:return"ArrowRight";case 40:return"ArrowDown";case 45:return"Insert";case 46:return"Delete";case 91:return"Meta";case 112:return"F1";case 113:return"F2";case 114:return"F3";case 115:return"F4";case 116:return"F5";case 117:return"F6";case 118:return"F7";case 119:return"F8";case 120:return"F9";case 121:return"F10";case 122:return"F11";case 123:return"F12";case 187:return"=";case 189:return"-";case 219:return"[";case 221:return"]"}return"Unidentified"}})}else{window.console.log("KeyboardEvent.Key polyfill not required")}
 // </if>  /* is_ios */
-Polymer.IronResizableBehavior = {
-  properties: {
-    _parentResizable: {
-      type: Object,
-      observer: '_parentResizableChanged'
-    },
-    _notifyingDescendant: {
-      type: Boolean,
-      value: false
-    }
-  },
-  listeners: {
-    'iron-request-resize-notifications': '_onIronRequestResizeNotifications'
-  },
-  created: function() {
-    this._interestedResizables = [];
-    this._boundNotifyResize = this.notifyResize.bind(this);
-  },
-  attached: function() {
-    this.fire('iron-request-resize-notifications', null, {
-      node: this,
-      bubbles: true,
-      cancelable: true
-    });
-    if (!this._parentResizable) {
-      window.addEventListener('resize', this._boundNotifyResize);
-      this.notifyResize();
-    }
-  },
-  detached: function() {
-    if (this._parentResizable) {
-      this._parentResizable.stopResizeNotificationsFor(this);
-    } else {
-      window.removeEventListener('resize', this._boundNotifyResize);
-    }
-    this._parentResizable = null;
-  },
-  notifyResize: function() {
-    if (!this.isAttached) {
-      return;
-    }
-    this._interestedResizables.forEach(function(resizable) {
-      if (this.resizerShouldNotify(resizable)) {
-        this._notifyDescendant(resizable);
-      }
-    }, this);
-    this._fireResize();
-  },
-  assignParentResizable: function(parentResizable) {
-    this._parentResizable = parentResizable;
-  },
-  stopResizeNotificationsFor: function(target) {
-    var index = this._interestedResizables.indexOf(target);
-    if (index > -1) {
-      this._interestedResizables.splice(index, 1);
-      this.unlisten(target, 'iron-resize', '_onDescendantIronResize');
-    }
-  },
-  resizerShouldNotify: function(element) {
-    return true;
-  },
-  _onDescendantIronResize: function(event) {
-    if (this._notifyingDescendant) {
-      event.stopPropagation();
-      return;
-    }
-    if (!Polymer.Settings.useShadow) {
-      this._fireResize();
-    }
-  },
-  _fireResize: function() {
-    this.fire('iron-resize', null, {
-      node: this,
-      bubbles: false
-    });
-  },
-  _onIronRequestResizeNotifications: function(event) {
-    var target = event.path ? event.path[0] : event.target;
-    if (target === this) {
-      return;
-    }
-    if (this._interestedResizables.indexOf(target) === -1) {
-      this._interestedResizables.push(target);
-      this.listen(target, 'iron-resize', '_onDescendantIronResize');
-    }
-    target.assignParentResizable(this);
-    this._notifyDescendant(target);
-    event.stopPropagation();
-  },
-  _parentResizableChanged: function(parentResizable) {
-    if (parentResizable) {
-      window.removeEventListener('resize', this._boundNotifyResize);
-    }
-  },
-  _notifyDescendant: function(descendant) {
-    if (!this.isAttached) {
-      return;
-    }
-    this._notifyingDescendant = true;
-    descendant.notifyResize();
-    this._notifyingDescendant = false;
-  }
-};
+Polymer.IronResizableBehavior={properties:{_parentResizable:{type:Object,observer:"_parentResizableChanged"},_notifyingDescendant:{type:Boolean,value:false}},listeners:{"iron-request-resize-notifications":"_onIronRequestResizeNotifications"},created:function(){this._interestedResizables=[];this._boundNotifyResize=this.notifyResize.bind(this)},attached:function(){this.fire("iron-request-resize-notifications",null,{node:this,bubbles:true,cancelable:true});if(!this._parentResizable){window.addEventListener("resize",this._boundNotifyResize);this.notifyResize()}},detached:function(){if(this._parentResizable){this._parentResizable.stopResizeNotificationsFor(this)}else{window.removeEventListener("resize",this._boundNotifyResize)}this._parentResizable=null},notifyResize:function(){if(!this.isAttached){return}this._interestedResizables.forEach(function(resizable){if(this.resizerShouldNotify(resizable)){this._notifyDescendant(resizable)}},this);this._fireResize()},assignParentResizable:function(parentResizable){this._parentResizable=parentResizable},stopResizeNotificationsFor:function(target){var index=this._interestedResizables.indexOf(target);if(index>-1){this._interestedResizables.splice(index,1);this.unlisten(target,"iron-resize","_onDescendantIronResize")}},resizerShouldNotify:function(element){return true},_onDescendantIronResize:function(event){if(this._notifyingDescendant){event.stopPropagation();return}if(!Polymer.Settings.useShadow){this._fireResize()}},_fireResize:function(){this.fire("iron-resize",null,{node:this,bubbles:false})},_onIronRequestResizeNotifications:function(event){var target=event.path?event.path[0]:event.target;if(target===this){return}if(this._interestedResizables.indexOf(target)===-1){this._interestedResizables.push(target);this.listen(target,"iron-resize","_onDescendantIronResize")}target.assignParentResizable(this);this._notifyDescendant(target);event.stopPropagation()},_parentResizableChanged:function(parentResizable){if(parentResizable){window.removeEventListener("resize",this._boundNotifyResize)}},_notifyDescendant:function(descendant){if(!this.isAttached){return}this._notifyingDescendant=true;descendant.notifyResize();this._notifyingDescendant=false}};(function(){"use strict";var KEY_IDENTIFIER={"U+0008":"backspace","U+0009":"tab","U+001B":"esc","U+0020":"space","U+007F":"del"};var KEY_CODE={8:"backspace",9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var MODIFIER_KEYS={shift:"shiftKey",ctrl:"ctrlKey",alt:"altKey",meta:"metaKey"};var KEY_CHAR=/[a-z0-9*]/;var IDENT_CHAR=/U\+/;var ARROW_KEY=/^arrow/;var SPACE_KEY=/^space(bar)?/;var ESC_KEY=/^escape$/;function transformKey(key,noSpecialChars){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey===" "||SPACE_KEY.test(lKey)){validKey="space"}else if(ESC_KEY.test(lKey)){validKey="esc"}else if(lKey.length==1){if(!noSpecialChars||KEY_CHAR.test(lKey)){validKey=lKey}}else if(ARROW_KEY.test(lKey)){validKey=lKey.replace("arrow","")}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(keyIdent in KEY_IDENTIFIER){validKey=KEY_IDENTIFIER[keyIdent]}else if(IDENT_CHAR.test(keyIdent)){keyIdent=parseInt(keyIdent.replace("U+","0x"),16);validKey=String.fromCharCode(keyIdent).toLowerCase()}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(keyCode-48)}else if(keyCode>=96&&keyCode<=105){validKey=String(keyCode-96)}else{validKey=KEY_CODE[keyCode]}}return validKey}function normalizedKeyForEvent(keyEvent,noSpecialChars){if(keyEvent.key){return transformKey(keyEvent.key,noSpecialChars)}if(keyEvent.detail&&keyEvent.detail.key){return transformKey(keyEvent.detail.key,noSpecialChars)}return transformKeyIdentifier(keyEvent.keyIdentifier)||transformKeyCode(keyEvent.keyCode)||""}function keyComboMatchesEvent(keyCombo,event){var keyEvent=normalizedKeyForEvent(event,keyCombo.hasModifiers);return keyEvent===keyCombo.key&&(!keyCombo.hasModifiers||!!event.shiftKey===!!keyCombo.shiftKey&&!!event.ctrlKey===!!keyCombo.ctrlKey&&!!event.altKey===!!keyCombo.altKey&&!!event.metaKey===!!keyCombo.metaKey)}function parseKeyComboString(keyComboString){if(keyComboString.length===1){return{combo:keyComboString,key:keyComboString,event:"keydown"}}return keyComboString.split("+").reduce(function(parsedKeyCombo,keyComboPart){var eventParts=keyComboPart.split(":");var keyName=eventParts[0];var event=eventParts[1];if(keyName in MODIFIER_KEYS){parsedKeyCombo[MODIFIER_KEYS[keyName]]=true;parsedKeyCombo.hasModifiers=true}else{parsedKeyCombo.key=keyName;parsedKeyCombo.event=event||"keydown"}return parsedKeyCombo},{combo:keyComboString.split(":").shift()})}function parseEventString(eventString){return eventString.trim().split(" ").map(function(keyComboString){return parseKeyComboString(keyComboString)})}Polymer.IronA11yKeysBehavior={properties:{keyEventTarget:{type:Object,value:function(){return this}},stopKeyboardEventPropagation:{type:Boolean,value:false},_boundKeyHandlers:{type:Array,value:function(){return[]}},_imperativeKeyBindings:{type:Object,value:function(){return{}}}},observers:["_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)"],keyBindings:{},registered:function(){this._prepKeyBindings()},attached:function(){this._listenKeyEventListeners()},detached:function(){this._unlistenKeyEventListeners()},addOwnKeyBinding:function(eventString,handlerName){this._imperativeKeyBindings[eventString]=handlerName;this._prepKeyBindings();this._resetKeyEventListeners()},removeOwnKeyBindings:function(){this._imperativeKeyBindings={};this._prepKeyBindings();this._resetKeyEventListeners()},keyboardEventMatchesKeys:function(event,eventString){var keyCombos=parseEventString(eventString);for(var i=0;i<keyCombos.length;++i){if(keyComboMatchesEvent(keyCombos[i],event)){return true}}return false},_collectKeyBindings:function(){var keyBindings=this.behaviors.map(function(behavior){return behavior.keyBindings});if(keyBindings.indexOf(this.keyBindings)===-1){keyBindings.push(this.keyBindings)}return keyBindings},_prepKeyBindings:function(){this._keyBindings={};this._collectKeyBindings().forEach(function(keyBindings){for(var eventString in keyBindings){this._addKeyBinding(eventString,keyBindings[eventString])}},this);for(var eventString in this._imperativeKeyBindings){this._addKeyBinding(eventString,this._imperativeKeyBindings[eventString])}for(var eventName in this._keyBindings){this._keyBindings[eventName].sort(function(kb1,kb2){var b1=kb1[0].hasModifiers;var b2=kb2[0].hasModifiers;return b1===b2?0:b1?-1:1})}},_addKeyBinding:function(eventString,handlerName){parseEventString(eventString).forEach(function(keyCombo){this._keyBindings[keyCombo.event]=this._keyBindings[keyCombo.event]||[];this._keyBindings[keyCombo.event].push([keyCombo,handlerName])},this)},_resetKeyEventListeners:function(){this._unlistenKeyEventListeners();if(this.isAttached){this._listenKeyEventListeners()}},_listenKeyEventListeners:function(){if(!this.keyEventTarget){return}Object.keys(this._keyBindings).forEach(function(eventName){var keyBindings=this._keyBindings[eventName];var boundKeyHandler=this._onKeyBindingEvent.bind(this,keyBindings);this._boundKeyHandlers.push([this.keyEventTarget,eventName,boundKeyHandler]);this.keyEventTarget.addEventListener(eventName,boundKeyHandler)},this)},_unlistenKeyEventListeners:function(){var keyHandlerTuple;var keyEventTarget;var eventName;var boundKeyHandler;while(this._boundKeyHandlers.length){keyHandlerTuple=this._boundKeyHandlers.pop();keyEventTarget=keyHandlerTuple[0];eventName=keyHandlerTuple[1];boundKeyHandler=keyHandlerTuple[2];keyEventTarget.removeEventListener(eventName,boundKeyHandler)}},_onKeyBindingEvent:function(keyBindings,event){if(this.stopKeyboardEventPropagation){event.stopPropagation()}if(event.defaultPrevented){return}for(var i=0;i<keyBindings.length;i++){var keyCombo=keyBindings[i][0];var handlerName=keyBindings[i][1];if(keyComboMatchesEvent(keyCombo,event)){this._triggerKeyHandler(keyCombo,handlerName,event);if(event.defaultPrevented){return}}}},_triggerKeyHandler:function(keyCombo,handlerName,keyboardEvent){var detail=Object.create(keyCombo);detail.keyboardEvent=keyboardEvent;var event=new CustomEvent(keyCombo.event,{detail:detail,cancelable:true});this[handlerName].call(this,event);if(event.defaultPrevented){keyboardEvent.preventDefault()}}}})();Polymer.IronScrollTargetBehavior={properties:{scrollTarget:{type:HTMLElement,value:function(){return this._defaultScrollTarget}}},observers:["_scrollTargetChanged(scrollTarget, isAttached)"],_scrollTargetChanged:function(scrollTarget,isAttached){var eventTarget;if(this._oldScrollTarget){eventTarget=this._oldScrollTarget===this._doc?window:this._oldScrollTarget;eventTarget.removeEventListener("scroll",this._boundScrollHandler);this._oldScrollTarget=null}if(!isAttached){return}if(scrollTarget==="document"){this.scrollTarget=this._doc}else if(typeof scrollTarget==="string"){this.scrollTarget=this.domHost?this.domHost.$[scrollTarget]:Polymer.dom(this.ownerDocument).querySelector("#"+scrollTarget)}else if(this._isValidScrollTarget()){eventTarget=scrollTarget===this._doc?window:scrollTarget;this._boundScrollHandler=this._boundScrollHandler||this._scrollHandler.bind(this);this._oldScrollTarget=scrollTarget;eventTarget.addEventListener("scroll",this._boundScrollHandler)}},_scrollHandler:function scrollHandler(){},get _defaultScrollTarget(){return this._doc},get _doc(){return this.ownerDocument.documentElement},get _scrollTop(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageYOffset:this.scrollTarget.scrollTop}return 0},get _scrollLeft(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageXOffset:this.scrollTarget.scrollLeft}return 0},set _scrollTop(top){if(this.scrollTarget===this._doc){window.scrollTo(window.pageXOffset,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollTop=top}},set _scrollLeft(left){if(this.scrollTarget===this._doc){window.scrollTo(left,window.pageYOffset)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left}},scroll:function(left,top){if(this.scrollTarget===this._doc){window.scrollTo(left,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left;this.scrollTarget.scrollTop=top}},get _scrollTargetWidth(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerWidth:this.scrollTarget.offsetWidth}return 0},get _scrollTargetHeight(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerHeight:this.scrollTarget.offsetHeight}return 0},_isValidScrollTarget:function(){return this.scrollTarget instanceof HTMLElement}};(function(){var IOS=navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);var IOS_TOUCH_SCROLLING=IOS&&IOS[1]>=8;var DEFAULT_PHYSICAL_COUNT=3;var HIDDEN_Y="-10000px";var DEFAULT_GRID_SIZE=200;var SECRET_TABINDEX=-100;Polymer({is:"iron-list",properties:{items:{type:Array},maxPhysicalCount:{type:Number,value:500},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},selectedAs:{type:String,value:"selected"},grid:{type:Boolean,value:false,reflectToAttribute:true},selectionEnabled:{type:Boolean,value:false},selectedItem:{type:Object,notify:true},selectedItems:{type:Object,notify:true},multiSelection:{type:Boolean,value:false}},observers:["_itemsChanged(items.*)","_selectionEnabledChanged(selectionEnabled)","_multiSelectionChanged(multiSelection)","_setOverflow(scrollTarget)"],behaviors:[Polymer.Templatizer,Polymer.IronResizableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronScrollTargetBehavior],keyBindings:{up:"_didMoveUp",down:"_didMoveDown",enter:"_didEnter"},_ratio:.5,_scrollerPaddingTop:0,_scrollPosition:0,_physicalSize:0,_physicalAverage:0,_physicalAverageCount:0,_physicalTop:0,_virtualCount:0,_physicalIndexForKey:null,_estScrollHeight:0,_scrollHeight:0,_viewportHeight:0,_viewportWidth:0,_physicalItems:null,_physicalSizes:null,_firstVisibleIndexVal:null,_lastVisibleIndexVal:null,_collection:null,_maxPages:3,_focusedItem:null,_focusedIndex:-1,_offscreenFocusedItem:null,_focusBackfillItem:null,_itemsPerRow:1,_itemWidth:0,_rowHeight:0,_templateCost:0,get _physicalBottom(){return this._physicalTop+this._physicalSize},get _scrollBottom(){return this._scrollPosition+this._viewportHeight},get _virtualEnd(){return this._virtualStart+this._physicalCount-1},get _hiddenContentSize(){var size=this.grid?this._physicalRows*this._rowHeight:this._physicalSize;return size-this._viewportHeight},get _maxScrollTop(){return this._estScrollHeight-this._viewportHeight+this._scrollerPaddingTop},_minVirtualStart:0,get _maxVirtualStart(){return Math.max(0,this._virtualCount-this._physicalCount)},_virtualStartVal:0,set _virtualStart(val){this._virtualStartVal=Math.min(this._maxVirtualStart,Math.max(this._minVirtualStart,val))},get _virtualStart(){return this._virtualStartVal||0},_physicalStartVal:0,set _physicalStart(val){this._physicalStartVal=val%this._physicalCount;if(this._physicalStartVal<0){this._physicalStartVal=this._physicalCount+this._physicalStartVal}this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalStart(){return this._physicalStartVal||0},_physicalCountVal:0,set _physicalCount(val){this._physicalCountVal=val;this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalCount(){return this._physicalCountVal},_physicalEnd:0,get _optPhysicalSize(){if(this.grid){return this._estRowsInView*this._rowHeight*this._maxPages}return this._viewportHeight*this._maxPages},get _optPhysicalCount(){return this._estRowsInView*this._itemsPerRow*this._maxPages},get _isVisible(){return Boolean(this.offsetWidth||this.offsetHeight)},get firstVisibleIndex(){if(this._firstVisibleIndexVal===null){var physicalOffset=Math.floor(this._physicalTop+this._scrollerPaddingTop);this._firstVisibleIndexVal=this._iterateItems(function(pidx,vidx){physicalOffset+=this._getPhysicalSizeIncrement(pidx);if(physicalOffset>this._scrollPosition){return this.grid?vidx-vidx%this._itemsPerRow:vidx}if(this.grid&&this._virtualCount-1===vidx){return vidx-vidx%this._itemsPerRow}})||0}return this._firstVisibleIndexVal},get lastVisibleIndex(){if(this._lastVisibleIndexVal===null){if(this.grid){var lastIndex=this.firstVisibleIndex+this._estRowsInView*this._itemsPerRow-1;this._lastVisibleIndexVal=Math.min(this._virtualCount,lastIndex)}else{var physicalOffset=this._physicalTop;this._iterateItems(function(pidx,vidx){if(physicalOffset<this._scrollBottom){this._lastVisibleIndexVal=vidx}else{return true}physicalOffset+=this._getPhysicalSizeIncrement(pidx)})}}return this._lastVisibleIndexVal},get _defaultScrollTarget(){return this},get _virtualRowCount(){return Math.ceil(this._virtualCount/this._itemsPerRow)},get _estRowsInView(){return Math.ceil(this._viewportHeight/this._rowHeight)},get _physicalRows(){return Math.ceil(this._physicalCount/this._itemsPerRow)},ready:function(){this.addEventListener("focus",this._didFocus.bind(this),true)},attached:function(){this.updateViewportBoundaries();if(this._physicalCount===0){this._debounceTemplate(this._render)}this.listen(this,"iron-resize","_resizeHandler")},detached:function(){this.unlisten(this,"iron-resize","_resizeHandler")},_setOverflow:function(scrollTarget){this.style.webkitOverflowScrolling=scrollTarget===this?"touch":"";this.style.overflow=scrollTarget===this?"auto":""},updateViewportBoundaries:function(){this._scrollerPaddingTop=this.scrollTarget===this?0:parseInt(window.getComputedStyle(this)["padding-top"],10);this._viewportHeight=this._scrollTargetHeight;if(this.grid){this._updateGridMetrics()}},_scrollHandler:function(){var scrollTop=Math.max(0,Math.min(this._maxScrollTop,this._scrollTop));var delta=scrollTop-this._scrollPosition;var tileHeight,tileTop,kth,recycledTileSet,scrollBottom,physicalBottom;var ratio=this._ratio;var recycledTiles=0;var hiddenContentSize=this._hiddenContentSize;var currentRatio=ratio;var movingUp=[];this._scrollPosition=scrollTop;this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;scrollBottom=this._scrollBottom;physicalBottom=this._physicalBottom;if(Math.abs(delta)>this._physicalSize){this._physicalTop+=delta;recycledTiles=Math.round(delta/this._physicalAverage)}else if(delta<0){var topSpace=scrollTop-this._physicalTop;var virtualStart=this._virtualStart;recycledTileSet=[];kth=this._physicalEnd;currentRatio=topSpace/hiddenContentSize;while(currentRatio<ratio&&recycledTiles<this._physicalCount&&virtualStart-recycledTiles>0&&physicalBottom-this._getPhysicalSizeIncrement(kth)>scrollBottom){tileHeight=this._getPhysicalSizeIncrement(kth);currentRatio+=tileHeight/hiddenContentSize;physicalBottom-=tileHeight;recycledTileSet.push(kth);recycledTiles++;kth=kth===0?this._physicalCount-1:kth-1}movingUp=recycledTileSet;recycledTiles=-recycledTiles}else if(delta>0){var bottomSpace=physicalBottom-scrollBottom;var virtualEnd=this._virtualEnd;var lastVirtualItemIndex=this._virtualCount-1;recycledTileSet=[];kth=this._physicalStart;currentRatio=bottomSpace/hiddenContentSize;while(currentRatio<ratio&&recycledTiles<this._physicalCount&&virtualEnd+recycledTiles<lastVirtualItemIndex&&this._physicalTop+this._getPhysicalSizeIncrement(kth)<scrollTop){tileHeight=this._getPhysicalSizeIncrement(kth);currentRatio+=tileHeight/hiddenContentSize;this._physicalTop+=tileHeight;recycledTileSet.push(kth);recycledTiles++;kth=(kth+1)%this._physicalCount}}if(recycledTiles===0){if(physicalBottom<scrollBottom||this._physicalTop>scrollTop){this._increasePoolIfNeeded()}}else{this._virtualStart=this._virtualStart+recycledTiles;this._physicalStart=this._physicalStart+recycledTiles;this._update(recycledTileSet,movingUp)}},_update:function(itemSet,movingUp){this._manageFocus();this._assignModels(itemSet);this._updateMetrics(itemSet);if(movingUp){while(movingUp.length){var idx=movingUp.pop();this._physicalTop-=this._getPhysicalSizeIncrement(idx)}}this._positionItems();this._updateScrollerSize();this._increasePoolIfNeeded()},_createPool:function(size){var physicalItems=new Array(size);this._ensureTemplatized();for(var i=0;i<size;i++){var inst=this.stamp(null);physicalItems[i]=inst.root.querySelector("*");Polymer.dom(this).appendChild(inst.root)}return physicalItems},_increasePoolIfNeeded:function(){if(this._viewportHeight===0){return false}var self=this;var isClientFull=this._physicalBottom>=this._scrollBottom&&this._physicalTop<=this._scrollPosition;if(this._physicalSize>=this._optPhysicalSize&&isClientFull){return false}var maxPoolSize=Math.round(this._physicalCount*.5);if(!isClientFull){this._debounceTemplate(this._increasePool.bind(this,maxPoolSize));return true}this._yield(function(){self._increasePool(Math.min(maxPoolSize,Math.max(1,Math.round(50/self._templateCost))))});return true},_yield:function(cb){var g=window;var handle=g.requestIdleCallback?g.requestIdleCallback(cb):g.setTimeout(cb,16);Polymer.dom.addDebouncer({complete:function(){g.cancelIdleCallback?g.cancelIdleCallback(handle):g.clearTimeout(handle);cb()}})},_increasePool:function(missingItems){var nextPhysicalCount=Math.min(this._physicalCount+missingItems,this._virtualCount-this._virtualStart,Math.max(this.maxPhysicalCount,DEFAULT_PHYSICAL_COUNT));var prevPhysicalCount=this._physicalCount;var delta=nextPhysicalCount-prevPhysicalCount;var ts=window.performance.now();if(delta<=0){return}[].push.apply(this._physicalItems,this._createPool(delta));[].push.apply(this._physicalSizes,new Array(delta));this._physicalCount=prevPhysicalCount+delta;if(this._physicalStart>this._physicalEnd&&this._isIndexRendered(this._focusedIndex)&&this._getPhysicalIndex(this._focusedIndex)<this._physicalEnd){this._physicalStart=this._physicalStart+delta}this._update();this._templateCost=(window.performance.now()-ts)/delta},_render:function(){if(this.isAttached&&this._isVisible){if(this._physicalCount===0){this._increasePool(DEFAULT_PHYSICAL_COUNT)}else{this._update()}}},_ensureTemplatized:function(){if(!this.ctor){var props={};props.__key__=true;props[this.as]=true;props[this.indexAs]=true;props[this.selectedAs]=true;props.tabIndex=true;this._instanceProps=props;this._userTemplate=Polymer.dom(this).querySelector("template");if(this._userTemplate){this.templatize(this._userTemplate)}else{console.warn("iron-list requires a template to be provided in light-dom")}}},_getStampedChildren:function(){return this._physicalItems},_forwardInstancePath:function(inst,path,value){if(path.indexOf(this.as+".")===0){this.notifyPath("items."+inst.__key__+"."+path.slice(this.as.length+1),value)}},_forwardParentProp:function(prop,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance[prop]=value},this)}},_forwardParentPath:function(path,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance.notifyPath(path,value,true)},this)}},_forwardItemPath:function(path,value){if(!this._physicalIndexForKey){return}var dot=path.indexOf(".");var key=path.substring(0,dot<0?path.length:dot);var idx=this._physicalIndexForKey[key];var offscreenItem=this._offscreenFocusedItem;var el=offscreenItem&&offscreenItem._templateInstance.__key__===key?offscreenItem:this._physicalItems[idx];if(!el||el._templateInstance.__key__!==key){return}if(dot>=0){path=this.as+"."+path.substring(dot+1);el._templateInstance.notifyPath(path,value,true)}else{var currentItem=el._templateInstance[this.as];if(Array.isArray(this.selectedItems)){for(var i=0;i<this.selectedItems.length;i++){if(this.selectedItems[i]===currentItem){this.set("selectedItems."+i,value);break}}}else if(this.selectedItem===currentItem){this.set("selectedItem",value)}el._templateInstance[this.as]=value}},_itemsChanged:function(change){if(change.path==="items"){this._virtualStart=0;this._physicalTop=0;this._virtualCount=this.items?this.items.length:0;this._collection=this.items?Polymer.Collection.get(this.items):null;this._physicalIndexForKey={};this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;this._physicalCount=this._physicalCount||0;this._physicalItems=this._physicalItems||[];this._physicalSizes=this._physicalSizes||[];this._physicalStart=0;this._resetScrollPosition(0);this._removeFocusedItem();this._debounceTemplate(this._render)}else if(change.path==="items.splices"){this._adjustVirtualIndex(change.value.indexSplices);this._virtualCount=this.items?this.items.length:0;this._debounceTemplate(this._render)}else{this._forwardItemPath(change.path.split(".").slice(1).join("."),change.value)}},_adjustVirtualIndex:function(splices){splices.forEach(function(splice){splice.removed.forEach(this._removeItem,this);if(splice.index<this._virtualStart){var delta=Math.max(splice.addedCount-splice.removed.length,splice.index-this._virtualStart);this._virtualStart=this._virtualStart+delta;if(this._focusedIndex>=0){this._focusedIndex=this._focusedIndex+delta}}},this)},_removeItem:function(item){this.$.selector.deselect(item);if(this._focusedItem&&this._focusedItem._templateInstance[this.as]===item){this._removeFocusedItem()}},_iterateItems:function(fn,itemSet){var pidx,vidx,rtn,i;if(arguments.length===2&&itemSet){for(i=0;i<itemSet.length;i++){pidx=itemSet[i];vidx=this._computeVidx(pidx);if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}else{pidx=this._physicalStart;vidx=this._virtualStart;for(;pidx<this._physicalCount;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}for(pidx=0;pidx<this._physicalStart;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}},_computeVidx:function(pidx){if(pidx>=this._physicalStart){return this._virtualStart+(pidx-this._physicalStart)}return this._virtualStart+(this._physicalCount-this._physicalStart)+pidx},_assignModels:function(itemSet){this._iterateItems(function(pidx,vidx){var el=this._physicalItems[pidx];var inst=el._templateInstance;var item=this.items&&this.items[vidx];if(item!=null){inst[this.as]=item;inst.__key__=this._collection.getKey(item);inst[this.selectedAs]=this.$.selector.isSelected(item);inst[this.indexAs]=vidx;inst.tabIndex=this._focusedIndex===vidx?0:-1;this._physicalIndexForKey[inst.__key__]=pidx;el.removeAttribute("hidden")}else{inst.__key__=null;el.setAttribute("hidden","")}},itemSet)},_updateMetrics:function(itemSet){Polymer.dom.flush();var newPhysicalSize=0;var oldPhysicalSize=0;var prevAvgCount=this._physicalAverageCount;var prevPhysicalAvg=this._physicalAverage;this._iterateItems(function(pidx,vidx){oldPhysicalSize+=this._physicalSizes[pidx]||0;this._physicalSizes[pidx]=this._physicalItems[pidx].offsetHeight;newPhysicalSize+=this._physicalSizes[pidx];this._physicalAverageCount+=this._physicalSizes[pidx]?1:0},itemSet);this._viewportHeight=this._scrollTargetHeight;if(this.grid){this._updateGridMetrics();this._physicalSize=Math.ceil(this._physicalCount/this._itemsPerRow)*this._rowHeight}else{this._physicalSize=this._physicalSize+newPhysicalSize-oldPhysicalSize}if(this._physicalAverageCount!==prevAvgCount){this._physicalAverage=Math.round((prevPhysicalAvg*prevAvgCount+newPhysicalSize)/this._physicalAverageCount)}},_updateGridMetrics:function(){this._viewportWidth=this.$.items.offsetWidth;this._itemWidth=this._physicalCount>0?this._physicalItems[0].getBoundingClientRect().width:DEFAULT_GRID_SIZE;this._rowHeight=this._physicalCount>0?this._physicalItems[0].offsetHeight:DEFAULT_GRID_SIZE;this._itemsPerRow=this._itemWidth?Math.floor(this._viewportWidth/this._itemWidth):this._itemsPerRow},_positionItems:function(){this._adjustScrollPosition();var y=this._physicalTop;if(this.grid){var totalItemWidth=this._itemsPerRow*this._itemWidth;var rowOffset=(this._viewportWidth-totalItemWidth)/2;this._iterateItems(function(pidx,vidx){var modulus=vidx%this._itemsPerRow;var x=Math.floor(modulus*this._itemWidth+rowOffset);this.translate3d(x+"px",y+"px",0,this._physicalItems[pidx]);if(this._shouldRenderNextRow(vidx)){y+=this._rowHeight}})}else{this._iterateItems(function(pidx,vidx){this.translate3d(0,y+"px",0,this._physicalItems[pidx]);y+=this._physicalSizes[pidx]})}},_getPhysicalSizeIncrement:function(pidx){if(!this.grid){return this._physicalSizes[pidx]}if(this._computeVidx(pidx)%this._itemsPerRow!==this._itemsPerRow-1){return 0}return this._rowHeight},_shouldRenderNextRow:function(vidx){return vidx%this._itemsPerRow===this._itemsPerRow-1},_adjustScrollPosition:function(){var deltaHeight=this._virtualStart===0?this._physicalTop:Math.min(this._scrollPosition+this._physicalTop,0);if(deltaHeight){this._physicalTop=this._physicalTop-deltaHeight;if(!IOS_TOUCH_SCROLLING&&this._physicalTop!==0){this._resetScrollPosition(this._scrollTop-deltaHeight)}}},_resetScrollPosition:function(pos){if(this.scrollTarget){this._scrollTop=pos;this._scrollPosition=this._scrollTop}},_updateScrollerSize:function(forceUpdate){if(this.grid){this._estScrollHeight=this._virtualRowCount*this._rowHeight}else{this._estScrollHeight=this._physicalBottom+Math.max(this._virtualCount-this._physicalCount-this._virtualStart,0)*this._physicalAverage}forceUpdate=forceUpdate||this._scrollHeight===0;forceUpdate=forceUpdate||this._scrollPosition>=this._estScrollHeight-this._physicalSize;forceUpdate=forceUpdate||this.grid&&this.$.items.style.height<this._estScrollHeight;if(forceUpdate||Math.abs(this._estScrollHeight-this._scrollHeight)>=this._optPhysicalSize){this.$.items.style.height=this._estScrollHeight+"px";this._scrollHeight=this._estScrollHeight}},scrollToItem:function(item){return this.scrollToIndex(this.items.indexOf(item))},scrollToIndex:function(idx){if(typeof idx!=="number"||idx<0||idx>this.items.length-1){return}Polymer.dom.flush();if(this._physicalCount===0){return}idx=Math.min(Math.max(idx,0),this._virtualCount-1);if(!this._isIndexRendered(idx)||idx>=this._maxVirtualStart){this._virtualStart=this.grid?idx-this._itemsPerRow*2:idx-1}this._manageFocus();this._assignModels();this._updateMetrics();this._physicalTop=Math.floor(this._virtualStart/this._itemsPerRow)*this._physicalAverage;var currentTopItem=this._physicalStart;var currentVirtualItem=this._virtualStart;var targetOffsetTop=0;var hiddenContentSize=this._hiddenContentSize;while(currentVirtualItem<idx&&targetOffsetTop<=hiddenContentSize){targetOffsetTop=targetOffsetTop+this._getPhysicalSizeIncrement(currentTopItem);currentTopItem=(currentTopItem+1)%this._physicalCount;currentVirtualItem++}this._updateScrollerSize(true);this._positionItems();this._resetScrollPosition(this._physicalTop+this._scrollerPaddingTop+targetOffsetTop);this._increasePoolIfNeeded();this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null},_resetAverage:function(){this._physicalAverage=0;this._physicalAverageCount=0},_resizeHandler:function(){if(IOS&&Math.abs(this._viewportHeight-this._scrollTargetHeight)<100){return}Polymer.dom.addDebouncer(this.debounce("_debounceTemplate",function(){this.updateViewportBoundaries();this._render();if(this._physicalCount>0&&this._isVisible){this._resetAverage();this.scrollToIndex(this.firstVisibleIndex)}}.bind(this),1))},_getModelFromItem:function(item){var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){return this._physicalItems[pidx]._templateInstance}return null},_getNormalizedItem:function(item){if(this._collection.getKey(item)===undefined){if(typeof item==="number"){item=this.items[item];if(!item){throw new RangeError("<item> not found")}return item}throw new TypeError("<item> should be a valid item")}return item},selectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(!this.multiSelection&&this.selectedItem){this.deselectItem(this.selectedItem)}if(model){model[this.selectedAs]=true}this.$.selector.select(item);this.updateSizeForItem(item)},deselectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}this.$.selector.deselect(item);this.updateSizeForItem(item)},toggleSelectionForItem:function(item){item=this._getNormalizedItem(item);if(this.$.selector.isSelected(item)){this.deselectItem(item)}else{this.selectItem(item)}},clearSelection:function(){function unselect(item){var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}}if(Array.isArray(this.selectedItems)){this.selectedItems.forEach(unselect,this)}else if(this.selectedItem){unselect.call(this,this.selectedItem)}this.$.selector.clearSelection()},_selectionEnabledChanged:function(selectionEnabled){var handler=selectionEnabled?this.listen:this.unlisten;handler.call(this,this,"tap","_selectionHandler")},_selectionHandler:function(e){var model=this.modelForElement(e.target);if(!model){return}var modelTabIndex,activeElTabIndex;var target=Polymer.dom(e).path[0];var activeEl=Polymer.dom(this.domHost?this.domHost.root:document).activeElement;var physicalItem=this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];if(target.localName==="input"||target.localName==="button"||target.localName==="select"){return}modelTabIndex=model.tabIndex;model.tabIndex=SECRET_TABINDEX;activeElTabIndex=activeEl?activeEl.tabIndex:-1;model.tabIndex=modelTabIndex;if(activeEl&&physicalItem!==activeEl&&physicalItem.contains(activeEl)&&activeElTabIndex!==SECRET_TABINDEX){return}this.toggleSelectionForItem(model[this.as])},_multiSelectionChanged:function(multiSelection){this.clearSelection();this.$.selector.multi=multiSelection},updateSizeForItem:function(item){item=this._getNormalizedItem(item);var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){this._updateMetrics([pidx]);this._positionItems()}},_manageFocus:function(){var fidx=this._focusedIndex;if(fidx>=0&&fidx<this._virtualCount){if(this._isIndexRendered(fidx)){this._restoreFocusedItem();
 
-(function() {
-  'use strict';
-  var KEY_IDENTIFIER = {
-    'U+0008': 'backspace',
-    'U+0009': 'tab',
-    'U+001B': 'esc',
-    'U+0020': 'space',
-    'U+007F': 'del'
-  };
-  var KEY_CODE = {
-    8: 'backspace',
-    9: 'tab',
-    13: 'enter',
-    27: 'esc',
-    33: 'pageup',
-    34: 'pagedown',
-    35: 'end',
-    36: 'home',
-    32: 'space',
-    37: 'left',
-    38: 'up',
-    39: 'right',
-    40: 'down',
-    46: 'del',
-    106: '*'
-  };
-  var MODIFIER_KEYS = {
-    shift: 'shiftKey',
-    ctrl: 'ctrlKey',
-    alt: 'altKey',
-    meta: 'metaKey'
-  };
-  var KEY_CHAR = /[a-z0-9*]/;
-  var IDENT_CHAR = /U\+/;
-  var ARROW_KEY = /^arrow/;
-  var SPACE_KEY = /^space(bar)?/;
-  var ESC_KEY = /^escape$/;
-  function transformKey(key, noSpecialChars) {
-    var validKey = '';
-    if (key) {
-      var lKey = key.toLowerCase();
-      if (lKey === ' ' || SPACE_KEY.test(lKey)) {
-        validKey = 'space';
-      } else if (ESC_KEY.test(lKey)) {
-        validKey = 'esc';
-      } else if (lKey.length == 1) {
-        if (!noSpecialChars || KEY_CHAR.test(lKey)) {
-          validKey = lKey;
-        }
-      } else if (ARROW_KEY.test(lKey)) {
-        validKey = lKey.replace('arrow', '');
-      } else if (lKey == 'multiply') {
-        validKey = '*';
-      } else {
-        validKey = lKey;
-      }
-    }
-    return validKey;
-  }
-  function transformKeyIdentifier(keyIdent) {
-    var validKey = '';
-    if (keyIdent) {
-      if (keyIdent in KEY_IDENTIFIER) {
-        validKey = KEY_IDENTIFIER[keyIdent];
-      } else if (IDENT_CHAR.test(keyIdent)) {
-        keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16);
-        validKey = String.fromCharCode(keyIdent).toLowerCase();
-      } else {
-        validKey = keyIdent.toLowerCase();
-      }
-    }
-    return validKey;
-  }
-  function transformKeyCode(keyCode) {
-    var validKey = '';
-    if (Number(keyCode)) {
-      if (keyCode >= 65 && keyCode <= 90) {
-        validKey = String.fromCharCode(32 + keyCode);
-      } else if (keyCode >= 112 && keyCode <= 123) {
-        validKey = 'f' + (keyCode - 112);
-      } else if (keyCode >= 48 && keyCode <= 57) {
-        validKey = String(keyCode - 48);
-      } else if (keyCode >= 96 && keyCode <= 105) {
-        validKey = String(keyCode - 96);
-      } else {
-        validKey = KEY_CODE[keyCode];
-      }
-    }
-    return validKey;
-  }
-  function normalizedKeyForEvent(keyEvent, noSpecialChars) {
-    if (keyEvent.key) {
-      return transformKey(keyEvent.key, noSpecialChars);
-    }
-    if (keyEvent.detail && keyEvent.detail.key) {
-      return transformKey(keyEvent.detail.key, noSpecialChars);
-    }
-    return transformKeyIdentifier(keyEvent.keyIdentifier) || transformKeyCode(keyEvent.keyCode) || '';
-  }
-  function keyComboMatchesEvent(keyCombo, event) {
-    var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers);
-    return keyEvent === keyCombo.key && (!keyCombo.hasModifiers || !!event.shiftKey === !!keyCombo.shiftKey && !!event.ctrlKey === !!keyCombo.ctrlKey && !!event.altKey === !!keyCombo.altKey && !!event.metaKey === !!keyCombo.metaKey);
-  }
-  function parseKeyComboString(keyComboString) {
-    if (keyComboString.length === 1) {
-      return {
-        combo: keyComboString,
-        key: keyComboString,
-        event: 'keydown'
-      };
-    }
-    return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboPart) {
-      var eventParts = keyComboPart.split(':');
-      var keyName = eventParts[0];
-      var event = eventParts[1];
-      if (keyName in MODIFIER_KEYS) {
-        parsedKeyCombo[MODIFIER_KEYS[keyName]] = true;
-        parsedKeyCombo.hasModifiers = true;
-      } else {
-        parsedKeyCombo.key = keyName;
-        parsedKeyCombo.event = event || 'keydown';
-      }
-      return parsedKeyCombo;
-    }, {
-      combo: keyComboString.split(':').shift()
-    });
-  }
-  function parseEventString(eventString) {
-    return eventString.trim().split(' ').map(function(keyComboString) {
-      return parseKeyComboString(keyComboString);
-    });
-  }
-  Polymer.IronA11yKeysBehavior = {
-    properties: {
-      keyEventTarget: {
-        type: Object,
-        value: function() {
-          return this;
-        }
-      },
-      stopKeyboardEventPropagation: {
-        type: Boolean,
-        value: false
-      },
-      _boundKeyHandlers: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      _imperativeKeyBindings: {
-        type: Object,
-        value: function() {
-          return {};
-        }
-      }
-    },
-    observers: [ '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)' ],
-    keyBindings: {},
-    registered: function() {
-      this._prepKeyBindings();
-    },
-    attached: function() {
-      this._listenKeyEventListeners();
-    },
-    detached: function() {
-      this._unlistenKeyEventListeners();
-    },
-    addOwnKeyBinding: function(eventString, handlerName) {
-      this._imperativeKeyBindings[eventString] = handlerName;
-      this._prepKeyBindings();
-      this._resetKeyEventListeners();
-    },
-    removeOwnKeyBindings: function() {
-      this._imperativeKeyBindings = {};
-      this._prepKeyBindings();
-      this._resetKeyEventListeners();
-    },
-    keyboardEventMatchesKeys: function(event, eventString) {
-      var keyCombos = parseEventString(eventString);
-      for (var i = 0; i < keyCombos.length; ++i) {
-        if (keyComboMatchesEvent(keyCombos[i], event)) {
-          return true;
-        }
-      }
-      return false;
-    },
-    _collectKeyBindings: function() {
-      var keyBindings = this.behaviors.map(function(behavior) {
-        return behavior.keyBindings;
-      });
-      if (keyBindings.indexOf(this.keyBindings) === -1) {
-        keyBindings.push(this.keyBindings);
-      }
-      return keyBindings;
-    },
-    _prepKeyBindings: function() {
-      this._keyBindings = {};
-      this._collectKeyBindings().forEach(function(keyBindings) {
-        for (var eventString in keyBindings) {
-          this._addKeyBinding(eventString, keyBindings[eventString]);
-        }
-      }, this);
-      for (var eventString in this._imperativeKeyBindings) {
-        this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString]);
-      }
-      for (var eventName in this._keyBindings) {
-        this._keyBindings[eventName].sort(function(kb1, kb2) {
-          var b1 = kb1[0].hasModifiers;
-          var b2 = kb2[0].hasModifiers;
-          return b1 === b2 ? 0 : b1 ? -1 : 1;
-        });
-      }
-    },
-    _addKeyBinding: function(eventString, handlerName) {
-      parseEventString(eventString).forEach(function(keyCombo) {
-        this._keyBindings[keyCombo.event] = this._keyBindings[keyCombo.event] || [];
-        this._keyBindings[keyCombo.event].push([ keyCombo, handlerName ]);
-      }, this);
-    },
-    _resetKeyEventListeners: function() {
-      this._unlistenKeyEventListeners();
-      if (this.isAttached) {
-        this._listenKeyEventListeners();
-      }
-    },
-    _listenKeyEventListeners: function() {
-      if (!this.keyEventTarget) {
-        return;
-      }
-      Object.keys(this._keyBindings).forEach(function(eventName) {
-        var keyBindings = this._keyBindings[eventName];
-        var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings);
-        this._boundKeyHandlers.push([ this.keyEventTarget, eventName, boundKeyHandler ]);
-        this.keyEventTarget.addEventListener(eventName, boundKeyHandler);
-      }, this);
-    },
-    _unlistenKeyEventListeners: function() {
-      var keyHandlerTuple;
-      var keyEventTarget;
-      var eventName;
-      var boundKeyHandler;
-      while (this._boundKeyHandlers.length) {
-        keyHandlerTuple = this._boundKeyHandlers.pop();
-        keyEventTarget = keyHandlerTuple[0];
-        eventName = keyHandlerTuple[1];
-        boundKeyHandler = keyHandlerTuple[2];
-        keyEventTarget.removeEventListener(eventName, boundKeyHandler);
-      }
-    },
-    _onKeyBindingEvent: function(keyBindings, event) {
-      if (this.stopKeyboardEventPropagation) {
-        event.stopPropagation();
-      }
-      if (event.defaultPrevented) {
-        return;
-      }
-      for (var i = 0; i < keyBindings.length; i++) {
-        var keyCombo = keyBindings[i][0];
-        var handlerName = keyBindings[i][1];
-        if (keyComboMatchesEvent(keyCombo, event)) {
-          this._triggerKeyHandler(keyCombo, handlerName, event);
-          if (event.defaultPrevented) {
-            return;
-          }
-        }
-      }
-    },
-    _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) {
-      var detail = Object.create(keyCombo);
-      detail.keyboardEvent = keyboardEvent;
-      var event = new CustomEvent(keyCombo.event, {
-        detail: detail,
-        cancelable: true
-      });
-      this[handlerName].call(this, event);
-      if (event.defaultPrevented) {
-        keyboardEvent.preventDefault();
-      }
-    }
-  };
-})();
-
-Polymer.IronScrollTargetBehavior = {
-  properties: {
-    scrollTarget: {
-      type: HTMLElement,
-      value: function() {
-        return this._defaultScrollTarget;
-      }
-    }
-  },
-  observers: [ '_scrollTargetChanged(scrollTarget, isAttached)' ],
-  _scrollTargetChanged: function(scrollTarget, isAttached) {
-    var eventTarget;
-    if (this._oldScrollTarget) {
-      eventTarget = this._oldScrollTarget === this._doc ? window : this._oldScrollTarget;
-      eventTarget.removeEventListener('scroll', this._boundScrollHandler);
-      this._oldScrollTarget = null;
-    }
-    if (!isAttached) {
-      return;
-    }
-    if (scrollTarget === 'document') {
-      this.scrollTarget = this._doc;
-    } else if (typeof scrollTarget === 'string') {
-      this.scrollTarget = this.domHost ? this.domHost.$[scrollTarget] : Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
-    } else if (this._isValidScrollTarget()) {
-      eventTarget = scrollTarget === this._doc ? window : scrollTarget;
-      this._boundScrollHandler = this._boundScrollHandler || this._scrollHandler.bind(this);
-      this._oldScrollTarget = scrollTarget;
-      eventTarget.addEventListener('scroll', this._boundScrollHandler);
-    }
-  },
-  _scrollHandler: function scrollHandler() {},
-  get _defaultScrollTarget() {
-    return this._doc;
-  },
-  get _doc() {
-    return this.ownerDocument.documentElement;
-  },
-  get _scrollTop() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.pageYOffset : this.scrollTarget.scrollTop;
-    }
-    return 0;
-  },
-  get _scrollLeft() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.pageXOffset : this.scrollTarget.scrollLeft;
-    }
-    return 0;
-  },
-  set _scrollTop(top) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(window.pageXOffset, top);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollTop = top;
-    }
-  },
-  set _scrollLeft(left) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(left, window.pageYOffset);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollLeft = left;
-    }
-  },
-  scroll: function(left, top) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(left, top);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollLeft = left;
-      this.scrollTarget.scrollTop = top;
-    }
-  },
-  get _scrollTargetWidth() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.innerWidth : this.scrollTarget.offsetWidth;
-    }
-    return 0;
-  },
-  get _scrollTargetHeight() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.innerHeight : this.scrollTarget.offsetHeight;
-    }
-    return 0;
-  },
-  _isValidScrollTarget: function() {
-    return this.scrollTarget instanceof HTMLElement;
-  }
-};
-
-(function() {
-  var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
-  var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
-  var DEFAULT_PHYSICAL_COUNT = 3;
-  var HIDDEN_Y = '-10000px';
-  var DEFAULT_GRID_SIZE = 200;
-  var SECRET_TABINDEX = -100;
-  Polymer({
-    is: 'iron-list',
-    properties: {
-      items: {
-        type: Array
-      },
-      maxPhysicalCount: {
-        type: Number,
-        value: 500
-      },
-      as: {
-        type: String,
-        value: 'item'
-      },
-      indexAs: {
-        type: String,
-        value: 'index'
-      },
-      selectedAs: {
-        type: String,
-        value: 'selected'
-      },
-      grid: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true
-      },
-      selectionEnabled: {
-        type: Boolean,
-        value: false
-      },
-      selectedItem: {
-        type: Object,
-        notify: true
-      },
-      selectedItems: {
-        type: Object,
-        notify: true
-      },
-      multiSelection: {
-        type: Boolean,
-        value: false
-      }
-    },
-    observers: [ '_itemsChanged(items.*)', '_selectionEnabledChanged(selectionEnabled)', '_multiSelectionChanged(multiSelection)', '_setOverflow(scrollTarget)' ],
-    behaviors: [ Polymer.Templatizer, Polymer.IronResizableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronScrollTargetBehavior ],
-    keyBindings: {
-      up: '_didMoveUp',
-      down: '_didMoveDown',
-      enter: '_didEnter'
-    },
-    _ratio: .5,
-    _scrollerPaddingTop: 0,
-    _scrollPosition: 0,
-    _physicalSize: 0,
-    _physicalAverage: 0,
-    _physicalAverageCount: 0,
-    _physicalTop: 0,
-    _virtualCount: 0,
-    _physicalIndexForKey: null,
-    _estScrollHeight: 0,
-    _scrollHeight: 0,
-    _viewportHeight: 0,
-    _viewportWidth: 0,
-    _physicalItems: null,
-    _physicalSizes: null,
-    _firstVisibleIndexVal: null,
-    _lastVisibleIndexVal: null,
-    _collection: null,
-    _maxPages: 3,
-    _focusedItem: null,
-    _focusedIndex: -1,
-    _offscreenFocusedItem: null,
-    _focusBackfillItem: null,
-    _itemsPerRow: 1,
-    _itemWidth: 0,
-    _rowHeight: 0,
-    _templateCost: 0,
-    get _physicalBottom() {
-      return this._physicalTop + this._physicalSize;
-    },
-    get _scrollBottom() {
-      return this._scrollPosition + this._viewportHeight;
-    },
-    get _virtualEnd() {
-      return this._virtualStart + this._physicalCount - 1;
-    },
-    get _hiddenContentSize() {
-      var size = this.grid ? this._physicalRows * this._rowHeight : this._physicalSize;
-      return size - this._viewportHeight;
-    },
-    get _maxScrollTop() {
-      return this._estScrollHeight - this._viewportHeight + this._scrollerPaddingTop;
-    },
-    _minVirtualStart: 0,
-    get _maxVirtualStart() {
-      return Math.max(0, this._virtualCount - this._physicalCount);
-    },
-    _virtualStartVal: 0,
-    set _virtualStart(val) {
-      this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val));
-    },
-    get _virtualStart() {
-      return this._virtualStartVal || 0;
-    },
-    _physicalStartVal: 0,
-    set _physicalStart(val) {
-      this._physicalStartVal = val % this._physicalCount;
-      if (this._physicalStartVal < 0) {
-        this._physicalStartVal = this._physicalCount + this._physicalStartVal;
-      }
-      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-    },
-    get _physicalStart() {
-      return this._physicalStartVal || 0;
-    },
-    _physicalCountVal: 0,
-    set _physicalCount(val) {
-      this._physicalCountVal = val;
-      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-    },
-    get _physicalCount() {
-      return this._physicalCountVal;
-    },
-    _physicalEnd: 0,
-    get _optPhysicalSize() {
-      if (this.grid) {
-        return this._estRowsInView * this._rowHeight * this._maxPages;
-      }
-      return this._viewportHeight * this._maxPages;
-    },
-    get _optPhysicalCount() {
-      return this._estRowsInView * this._itemsPerRow * this._maxPages;
-    },
-    get _isVisible() {
-      return Boolean(this.offsetWidth || this.offsetHeight);
-    },
-    get firstVisibleIndex() {
-      if (this._firstVisibleIndexVal === null) {
-        var physicalOffset = Math.floor(this._physicalTop + this._scrollerPaddingTop);
-        this._firstVisibleIndexVal = this._iterateItems(function(pidx, vidx) {
-          physicalOffset += this._getPhysicalSizeIncrement(pidx);
-          if (physicalOffset > this._scrollPosition) {
-            return this.grid ? vidx - vidx % this._itemsPerRow : vidx;
-          }
-          if (this.grid && this._virtualCount - 1 === vidx) {
-            return vidx - vidx % this._itemsPerRow;
-          }
-        }) || 0;
-      }
-      return this._firstVisibleIndexVal;
-    },
-    get lastVisibleIndex() {
-      if (this._lastVisibleIndexVal === null) {
-        if (this.grid) {
-          var lastIndex = this.firstVisibleIndex + this._estRowsInView * this._itemsPerRow - 1;
-          this._lastVisibleIndexVal = Math.min(this._virtualCount, lastIndex);
-        } else {
-          var physicalOffset = this._physicalTop;
-          this._iterateItems(function(pidx, vidx) {
-            if (physicalOffset < this._scrollBottom) {
-              this._lastVisibleIndexVal = vidx;
-            } else {
-              return true;
-            }
-            physicalOffset += this._getPhysicalSizeIncrement(pidx);
-          });
-        }
-      }
-      return this._lastVisibleIndexVal;
-    },
-    get _defaultScrollTarget() {
-      return this;
-    },
-    get _virtualRowCount() {
-      return Math.ceil(this._virtualCount / this._itemsPerRow);
-    },
-    get _estRowsInView() {
-      return Math.ceil(this._viewportHeight / this._rowHeight);
-    },
-    get _physicalRows() {
-      return Math.ceil(this._physicalCount / this._itemsPerRow);
-    },
-    ready: function() {
-      this.addEventListener('focus', this._didFocus.bind(this), true);
-    },
-    attached: function() {
-      this.updateViewportBoundaries();
-      if (this._physicalCount === 0) {
-        this._debounceTemplate(this._render);
-      }
-      this.listen(this, 'iron-resize', '_resizeHandler');
-    },
-    detached: function() {
-      this.unlisten(this, 'iron-resize', '_resizeHandler');
-    },
-    _setOverflow: function(scrollTarget) {
-      this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
-      this.style.overflow = scrollTarget === this ? 'auto' : '';
-    },
-    updateViewportBoundaries: function() {
-      this._scrollerPaddingTop = this.scrollTarget === this ? 0 : parseInt(window.getComputedStyle(this)['padding-top'], 10);
-      this._viewportHeight = this._scrollTargetHeight;
-      if (this.grid) {
-        this._updateGridMetrics();
-      }
-    },
-    _scrollHandler: function() {
-      var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
-      var delta = scrollTop - this._scrollPosition;
-      var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
-      var ratio = this._ratio;
-      var recycledTiles = 0;
-      var hiddenContentSize = this._hiddenContentSize;
-      var currentRatio = ratio;
-      var movingUp = [];
-      this._scrollPosition = scrollTop;
-      this._firstVisibleIndexVal = null;
-      this._lastVisibleIndexVal = null;
-      scrollBottom = this._scrollBottom;
-      physicalBottom = this._physicalBottom;
-      if (Math.abs(delta) > this._physicalSize) {
-        this._physicalTop += delta;
-        recycledTiles = Math.round(delta / this._physicalAverage);
-      } else if (delta < 0) {
-        var topSpace = scrollTop - this._physicalTop;
-        var virtualStart = this._virtualStart;
-        recycledTileSet = [];
-        kth = this._physicalEnd;
-        currentRatio = topSpace / hiddenContentSize;
-        while (currentRatio < ratio && recycledTiles < this._physicalCount && virtualStart - recycledTiles > 0 && physicalBottom - this._getPhysicalSizeIncrement(kth) > scrollBottom) {
-          tileHeight = this._getPhysicalSizeIncrement(kth);
-          currentRatio += tileHeight / hiddenContentSize;
-          physicalBottom -= tileHeight;
-          recycledTileSet.push(kth);
-          recycledTiles++;
-          kth = kth === 0 ? this._physicalCount - 1 : kth - 1;
-        }
-        movingUp = recycledTileSet;
-        recycledTiles = -recycledTiles;
-      } else if (delta > 0) {
-        var bottomSpace = physicalBottom - scrollBottom;
-        var virtualEnd = this._virtualEnd;
-        var lastVirtualItemIndex = this._virtualCount - 1;
-        recycledTileSet = [];
-        kth = this._physicalStart;
-        currentRatio = bottomSpace / hiddenContentSize;
-        while (currentRatio < ratio && recycledTiles < this._physicalCount && virtualEnd + recycledTiles < lastVirtualItemIndex && this._physicalTop + this._getPhysicalSizeIncrement(kth) < scrollTop) {
-          tileHeight = this._getPhysicalSizeIncrement(kth);
-          currentRatio += tileHeight / hiddenContentSize;
-          this._physicalTop += tileHeight;
-          recycledTileSet.push(kth);
-          recycledTiles++;
-          kth = (kth + 1) % this._physicalCount;
-        }
-      }
-      if (recycledTiles === 0) {
-        if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
-          this._increasePoolIfNeeded();
-        }
-      } else {
-        this._virtualStart = this._virtualStart + recycledTiles;
-        this._physicalStart = this._physicalStart + recycledTiles;
-        this._update(recycledTileSet, movingUp);
-      }
-    },
-    _update: function(itemSet, movingUp) {
-      this._manageFocus();
-      this._assignModels(itemSet);
-      this._updateMetrics(itemSet);
-      if (movingUp) {
-        while (movingUp.length) {
-          var idx = movingUp.pop();
-          this._physicalTop -= this._getPhysicalSizeIncrement(idx);
-        }
-      }
-      this._positionItems();
-      this._updateScrollerSize();
-      this._increasePoolIfNeeded();
-    },
-    _createPool: function(size) {
-      var physicalItems = new Array(size);
-      this._ensureTemplatized();
-      for (var i = 0; i < size; i++) {
-        var inst = this.stamp(null);
-        physicalItems[i] = inst.root.querySelector('*');
-        Polymer.dom(this).appendChild(inst.root);
-      }
-      return physicalItems;
-    },
-    _increasePoolIfNeeded: function() {
-      if (this._viewportHeight === 0) {
-        return false;
-      }
-      var self = this;
-      var isClientFull = this._physicalBottom >= this._scrollBottom && this._physicalTop <= this._scrollPosition;
-      if (this._physicalSize >= this._optPhysicalSize && isClientFull) {
-        return false;
-      }
-      var maxPoolSize = Math.round(this._physicalCount * .5);
-      if (!isClientFull) {
-        this._debounceTemplate(this._increasePool.bind(this, maxPoolSize));
-        return true;
-      }
-      this._yield(function() {
-        self._increasePool(Math.min(maxPoolSize, Math.max(1, Math.round(50 / self._templateCost))));
-      });
-      return true;
-    },
-    _yield: function(cb) {
-      var g = window;
-      var handle = g.requestIdleCallback ? g.requestIdleCallback(cb) : g.setTimeout(cb, 16);
-      Polymer.dom.addDebouncer({
-        complete: function() {
-          g.cancelIdleCallback ? g.cancelIdleCallback(handle) : g.clearTimeout(handle);
-          cb();
-        }
-      });
-    },
-    _increasePool: function(missingItems) {
-      var nextPhysicalCount = Math.min(this._physicalCount + missingItems, this._virtualCount - this._virtualStart, Math.max(this.maxPhysicalCount, DEFAULT_PHYSICAL_COUNT));
-      var prevPhysicalCount = this._physicalCount;
-      var delta = nextPhysicalCount - prevPhysicalCount;
-      var ts = window.performance.now();
-      if (delta <= 0) {
-        return;
-      }
-      [].push.apply(this._physicalItems, this._createPool(delta));
-      [].push.apply(this._physicalSizes, new Array(delta));
-      this._physicalCount = prevPhysicalCount + delta;
-      if (this._physicalStart > this._physicalEnd && this._isIndexRendered(this._focusedIndex) && this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
-        this._physicalStart = this._physicalStart + delta;
-      }
-      this._update();
-      this._templateCost = (window.performance.now() - ts) / delta;
-    },
-    _render: function() {
-      if (this.isAttached && this._isVisible) {
-        if (this._physicalCount === 0) {
-          this._increasePool(DEFAULT_PHYSICAL_COUNT);
-        } else {
-          this._update();
-        }
-      }
-    },
-    _ensureTemplatized: function() {
-      if (!this.ctor) {
-        var props = {};
-        props.__key__ = true;
-        props[this.as] = true;
-        props[this.indexAs] = true;
-        props[this.selectedAs] = true;
-        props.tabIndex = true;
-        this._instanceProps = props;
-        this._userTemplate = Polymer.dom(this).querySelector('template');
-        if (this._userTemplate) {
-          this.templatize(this._userTemplate);
-        } else {
-          console.warn('iron-list requires a template to be provided in light-dom');
-        }
-      }
-    },
-    _getStampedChildren: function() {
-      return this._physicalItems;
-    },
-    _forwardInstancePath: function(inst, path, value) {
-      if (path.indexOf(this.as + '.') === 0) {
-        this.notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
-      }
-    },
-    _forwardParentProp: function(prop, value) {
-      if (this._physicalItems) {
-        this._physicalItems.forEach(function(item) {
-          item._templateInstance[prop] = value;
-        }, this);
-      }
-    },
-    _forwardParentPath: function(path, value) {
-      if (this._physicalItems) {
-        this._physicalItems.forEach(function(item) {
-          item._templateInstance.notifyPath(path, value, true);
-        }, this);
-      }
-    },
-    _forwardItemPath: function(path, value) {
-      if (!this._physicalIndexForKey) {
-        return;
-      }
-      var dot = path.indexOf('.');
-      var key = path.substring(0, dot < 0 ? path.length : dot);
-      var idx = this._physicalIndexForKey[key];
-      var offscreenItem = this._offscreenFocusedItem;
-      var el = offscreenItem && offscreenItem._templateInstance.__key__ === key ? offscreenItem : this._physicalItems[idx];
-      if (!el || el._templateInstance.__key__ !== key) {
-        return;
-      }
-      if (dot >= 0) {
-        path = this.as + '.' + path.substring(dot + 1);
-        el._templateInstance.notifyPath(path, value, true);
-      } else {
-        var currentItem = el._templateInstance[this.as];
-        if (Array.isArray(this.selectedItems)) {
-          for (var i = 0; i < this.selectedItems.length; i++) {
-            if (this.selectedItems[i] === currentItem) {
-              this.set('selectedItems.' + i, value);
-              break;
-            }
-          }
-        } else if (this.selectedItem === currentItem) {
-          this.set('selectedItem', value);
-        }
-        el._templateInstance[this.as] = value;
-      }
-    },
-    _itemsChanged: function(change) {
-      if (change.path === 'items') {
-        this._virtualStart = 0;
-        this._physicalTop = 0;
-        this._virtualCount = this.items ? this.items.length : 0;
-        this._collection = this.items ? Polymer.Collection.get(this.items) : null;
-        this._physicalIndexForKey = {};
-        this._firstVisibleIndexVal = null;
-        this._lastVisibleIndexVal = null;
-        this._physicalCount = this._physicalCount || 0;
-        this._physicalItems = this._physicalItems || [];
-        this._physicalSizes = this._physicalSizes || [];
-        this._physicalStart = 0;
-        this._resetScrollPosition(0);
-        this._removeFocusedItem();
-        this._debounceTemplate(this._render);
-      } else if (change.path === 'items.splices') {
-        this._adjustVirtualIndex(change.value.indexSplices);
-        this._virtualCount = this.items ? this.items.length : 0;
-        this._debounceTemplate(this._render);
-      } else {
-        this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.value);
-      }
-    },
-    _adjustVirtualIndex: function(splices) {
-      splices.forEach(function(splice) {
-        splice.removed.forEach(this._removeItem, this);
-        if (splice.index < this._virtualStart) {
-          var delta = Math.max(splice.addedCount - splice.removed.length, splice.index - this._virtualStart);
-          this._virtualStart = this._virtualStart + delta;
-          if (this._focusedIndex >= 0) {
-            this._focusedIndex = this._focusedIndex + delta;
-          }
-        }
-      }, this);
-    },
-    _removeItem: function(item) {
-      this.$.selector.deselect(item);
-      if (this._focusedItem && this._focusedItem._templateInstance[this.as] === item) {
-        this._removeFocusedItem();
-      }
-    },
-    _iterateItems: function(fn, itemSet) {
-      var pidx, vidx, rtn, i;
-      if (arguments.length === 2 && itemSet) {
-        for (i = 0; i < itemSet.length; i++) {
-          pidx = itemSet[i];
-          vidx = this._computeVidx(pidx);
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-      } else {
-        pidx = this._physicalStart;
-        vidx = this._virtualStart;
-        for (;pidx < this._physicalCount; pidx++, vidx++) {
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-        for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) {
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-      }
-    },
-    _computeVidx: function(pidx) {
-      if (pidx >= this._physicalStart) {
-        return this._virtualStart + (pidx - this._physicalStart);
-      }
-      return this._virtualStart + (this._physicalCount - this._physicalStart) + pidx;
-    },
-    _assignModels: function(itemSet) {
-      this._iterateItems(function(pidx, vidx) {
-        var el = this._physicalItems[pidx];
-        var inst = el._templateInstance;
-        var item = this.items && this.items[vidx];
-        if (item != null) {
-          inst[this.as] = item;
-          inst.__key__ = this._collection.getKey(item);
-          inst[this.selectedAs] = this.$.selector.isSelected(item);
-          inst[this.indexAs] = vidx;
-          inst.tabIndex = this._focusedIndex === vidx ? 0 : -1;
-          this._physicalIndexForKey[inst.__key__] = pidx;
-          el.removeAttribute('hidden');
-        } else {
-          inst.__key__ = null;
-          el.setAttribute('hidden', '');
-        }
-      }, itemSet);
-    },
-    _updateMetrics: function(itemSet) {
-      Polymer.dom.flush();
-      var newPhysicalSize = 0;
-      var oldPhysicalSize = 0;
-      var prevAvgCount = this._physicalAverageCount;
-      var prevPhysicalAvg = this._physicalAverage;
-      this._iterateItems(function(pidx, vidx) {
-        oldPhysicalSize += this._physicalSizes[pidx] || 0;
-        this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight;
-        newPhysicalSize += this._physicalSizes[pidx];
-        this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0;
-      }, itemSet);
-      this._viewportHeight = this._scrollTargetHeight;
-      if (this.grid) {
-        this._updateGridMetrics();
-        this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow) * this._rowHeight;
-      } else {
-        this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
-      }
-      if (this._physicalAverageCount !== prevAvgCount) {
-        this._physicalAverage = Math.round((prevPhysicalAvg * prevAvgCount + newPhysicalSize) / this._physicalAverageCount);
-      }
-    },
-    _updateGridMetrics: function() {
-      this._viewportWidth = this.$.items.offsetWidth;
-      this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoundingClientRect().width : DEFAULT_GRID_SIZE;
-      this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetHeight : DEFAULT_GRID_SIZE;
-      this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / this._itemWidth) : this._itemsPerRow;
-    },
-    _positionItems: function() {
-      this._adjustScrollPosition();
-      var y = this._physicalTop;
-      if (this.grid) {
-        var totalItemWidth = this._itemsPerRow * this._itemWidth;
-        var rowOffset = (this._viewportWidth - totalItemWidth) / 2;
-        this._iterateItems(function(pidx, vidx) {
-          var modulus = vidx % this._itemsPerRow;
-          var x = Math.floor(modulus * this._itemWidth + rowOffset);
-          this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]);
-          if (this._shouldRenderNextRow(vidx)) {
-            y += this._rowHeight;
-          }
-        });
-      } else {
-        this._iterateItems(function(pidx, vidx) {
-          this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]);
-          y += this._physicalSizes[pidx];
-        });
-      }
-    },
-    _getPhysicalSizeIncrement: function(pidx) {
-      if (!this.grid) {
-        return this._physicalSizes[pidx];
-      }
-      if (this._computeVidx(pidx) % this._itemsPerRow !== this._itemsPerRow - 1) {
-        return 0;
-      }
-      return this._rowHeight;
-    },
-    _shouldRenderNextRow: function(vidx) {
-      return vidx % this._itemsPerRow === this._itemsPerRow - 1;
-    },
-    _adjustScrollPosition: function() {
-      var deltaHeight = this._virtualStart === 0 ? this._physicalTop : Math.min(this._scrollPosition + this._physicalTop, 0);
-      if (deltaHeight) {
-        this._physicalTop = this._physicalTop - deltaHeight;
-        if (!IOS_TOUCH_SCROLLING && this._physicalTop !== 0) {
-          this._resetScrollPosition(this._scrollTop - deltaHeight);
-        }
-      }
-    },
-    _resetScrollPosition: function(pos) {
-      if (this.scrollTarget) {
-        this._scrollTop = pos;
-        this._scrollPosition = this._scrollTop;
-      }
-    },
-    _updateScrollerSize: function(forceUpdate) {
-      if (this.grid) {
-        this._estScrollHeight = this._virtualRowCount * this._rowHeight;
-      } else {
-        this._estScrollHeight = this._physicalBottom + Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage;
-      }
-      forceUpdate = forceUpdate || this._scrollHeight === 0;
-      forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
-      forceUpdate = forceUpdate || this.grid && this.$.items.style.height < this._estScrollHeight;
-      if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._optPhysicalSize) {
-        this.$.items.style.height = this._estScrollHeight + 'px';
-        this._scrollHeight = this._estScrollHeight;
-      }
-    },
-    scrollToItem: function(item) {
-      return this.scrollToIndex(this.items.indexOf(item));
-    },
-    scrollToIndex: function(idx) {
-      if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) {
-        return;
-      }
-      Polymer.dom.flush();
-      if (this._physicalCount === 0) {
-        return;
-      }
-      idx = Math.min(Math.max(idx, 0), this._virtualCount - 1);
-      if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
-        this._virtualStart = this.grid ? idx - this._itemsPerRow * 2 : idx - 1;
-      }
-      this._manageFocus();
-      this._assignModels();
-      this._updateMetrics();
-      this._physicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage;
-      var currentTopItem = this._physicalStart;
-      var currentVirtualItem = this._virtualStart;
-      var targetOffsetTop = 0;
-      var hiddenContentSize = this._hiddenContentSize;
-      while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) {
-        targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(currentTopItem);
-        currentTopItem = (currentTopItem + 1) % this._physicalCount;
-        currentVirtualItem++;
-      }
-      this._updateScrollerSize(true);
-      this._positionItems();
-      this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + targetOffsetTop);
-      this._increasePoolIfNeeded();
-      this._firstVisibleIndexVal = null;
-      this._lastVisibleIndexVal = null;
-    },
-    _resetAverage: function() {
-      this._physicalAverage = 0;
-      this._physicalAverageCount = 0;
-    },
-    _resizeHandler: function() {
-      if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100) {
-        return;
-      }
-      Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() {
-        this.updateViewportBoundaries();
-        this._render();
-        if (this._physicalCount > 0 && this._isVisible) {
-          this._resetAverage();
-          this.scrollToIndex(this.firstVisibleIndex);
-        }
-      }.bind(this), 1));
-    },
-    _getModelFromItem: function(item) {
-      var key = this._collection.getKey(item);
-      var pidx = this._physicalIndexForKey[key];
-      if (pidx != null) {
-        return this._physicalItems[pidx]._templateInstance;
-      }
-      return null;
-    },
-    _getNormalizedItem: function(item) {
-      if (this._collection.getKey(item) === undefined) {
-        if (typeof item === 'number') {
-          item = this.items[item];
-          if (!item) {
-            throw new RangeError('<item> not found');
-          }
-          return item;
-        }
-        throw new TypeError('<item> should be a valid item');
-      }
-      return item;
-    },
-    selectItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var model = this._getModelFromItem(item);
-      if (!this.multiSelection && this.selectedItem) {
-        this.deselectItem(this.selectedItem);
-      }
-      if (model) {
-        model[this.selectedAs] = true;
-      }
-      this.$.selector.select(item);
-      this.updateSizeForItem(item);
-    },
-    deselectItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var model = this._getModelFromItem(item);
-      if (model) {
-        model[this.selectedAs] = false;
-      }
-      this.$.selector.deselect(item);
-      this.updateSizeForItem(item);
-    },
-    toggleSelectionForItem: function(item) {
-      item = this._getNormalizedItem(item);
-      if (this.$.selector.isSelected(item)) {
-        this.deselectItem(item);
-      } else {
-        this.selectItem(item);
-      }
-    },
-    clearSelection: function() {
-      function unselect(item) {
-        var model = this._getModelFromItem(item);
-        if (model) {
-          model[this.selectedAs] = false;
-        }
-      }
-      if (Array.isArray(this.selectedItems)) {
-        this.selectedItems.forEach(unselect, this);
-      } else if (this.selectedItem) {
-        unselect.call(this, this.selectedItem);
-      }
-      this.$.selector.clearSelection();
-    },
-    _selectionEnabledChanged: function(selectionEnabled) {
-      var handler = selectionEnabled ? this.listen : this.unlisten;
-      handler.call(this, this, 'tap', '_selectionHandler');
-    },
-    _selectionHandler: function(e) {
-      var model = this.modelForElement(e.target);
-      if (!model) {
-        return;
-      }
-      var modelTabIndex, activeElTabIndex;
-      var target = Polymer.dom(e).path[0];
-      var activeEl = Polymer.dom(this.domHost ? this.domHost.root : document).activeElement;
-      var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];
-      if (target.localName === 'input' || target.localName === 'button' || target.localName === 'select') {
-        return;
-      }
-      modelTabIndex = model.tabIndex;
-      model.tabIndex = SECRET_TABINDEX;
-      activeElTabIndex = activeEl ? activeEl.tabIndex : -1;
-      model.tabIndex = modelTabIndex;
-      if (activeEl && physicalItem !== activeEl && physicalItem.contains(activeEl) && activeElTabIndex !== SECRET_TABINDEX) {
-        return;
-      }
-      this.toggleSelectionForItem(model[this.as]);
-    },
-    _multiSelectionChanged: function(multiSelection) {
-      this.clearSelection();
-      this.$.selector.multi = multiSelection;
-    },
-    updateSizeForItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var key = this._collection.getKey(item);
-      var pidx = this._physicalIndexForKey[key];
-      if (pidx != null) {
-        this._updateMetrics([ pidx ]);
-        this._positionItems();
-      }
-    },
-    _manageFocus: function() {
-      var fidx = this._focusedIndex;
-      if (fidx >= 0 && fidx < this._virtualCount) {
-        if (this._isIndexRendered(fidx)) {
-          this._restoreFocusedItem();
-        } else {
-          this._createFocusBackfillItem();
-        }
-      } else if (this._virtualCount > 0 && this._physicalCount > 0) {
-        this._focusedIndex = this._virtualStart;
-        this._focusedItem = this._physicalItems[this._physicalStart];
-      }
-    },
-    _isIndexRendered: function(idx) {
-      return idx >= this._virtualStart && idx <= this._virtualEnd;
-    },
-    _isIndexVisible: function(idx) {
-      return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex;
-    },
-    _getPhysicalIndex: function(idx) {
-      return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))];
-    },
-    _focusPhysicalItem: function(idx) {
-      if (idx < 0 || idx >= this._virtualCount) {
-        return;
-      }
-      this._restoreFocusedItem();
-      if (!this._isIndexRendered(idx)) {
-        this.scrollToIndex(idx);
-      }
-      var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)];
-      var model = physicalItem._templateInstance;
-      var focusable;
-      model.tabIndex = SECRET_TABINDEX;
-      if (physicalItem.tabIndex === SECRET_TABINDEX) {
-        focusable = physicalItem;
-      }
-      if (!focusable) {
-        focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECRET_TABINDEX + '"]');
-      }
-      model.tabIndex = 0;
-      this._focusedIndex = idx;
-      focusable && focusable.focus();
-    },
-    _removeFocusedItem: function() {
-      if (this._offscreenFocusedItem) {
-        Polymer.dom(this).removeChild(this._offscreenFocusedItem);
-      }
-      this._offscreenFocusedItem = null;
-      this._focusBackfillItem = null;
-      this._focusedItem = null;
-      this._focusedIndex = -1;
-    },
-    _createFocusBackfillItem: function() {
-      var pidx, fidx = this._focusedIndex;
-      if (this._offscreenFocusedItem || fidx < 0) {
-        return;
-      }
-      if (!this._focusBackfillItem) {
-        var stampedTemplate = this.stamp(null);
-        this._focusBackfillItem = stampedTemplate.root.querySelector('*');
-        Polymer.dom(this).appendChild(stampedTemplate.root);
-      }
-      pidx = this._getPhysicalIndex(fidx);
-      if (pidx != null) {
-        this._offscreenFocusedItem = this._physicalItems[pidx];
-        this._physicalItems[pidx] = this._focusBackfillItem;
-        this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
-      }
-    },
-    _restoreFocusedItem: function() {
-      var pidx, fidx = this._focusedIndex;
-      if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
-        return;
-      }
-      this._assignModels();
-      pidx = this._getPhysicalIndex(fidx);
-      if (pidx != null) {
-        this._focusBackfillItem = this._physicalItems[pidx];
-        this._physicalItems[pidx] = this._offscreenFocusedItem;
-        this._offscreenFocusedItem = null;
-        this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem);
-      }
-    },
-    _didFocus: function(e) {
-      var targetModel = this.modelForElement(e.target);
-      var focusedModel = this._focusedItem ? this._focusedItem._templateInstance : null;
-      var hasOffscreenFocusedItem = this._offscreenFocusedItem !== null;
-      var fidx = this._focusedIndex;
-      if (!targetModel || !focusedModel) {
-        return;
-      }
-      if (focusedModel === targetModel) {
-        if (!this._isIndexVisible(fidx)) {
-          this.scrollToIndex(fidx);
-        }
-      } else {
-        this._restoreFocusedItem();
-        focusedModel.tabIndex = -1;
-        targetModel.tabIndex = 0;
-        fidx = targetModel[this.indexAs];
-        this._focusedIndex = fidx;
-        this._focusedItem = this._physicalItems[this._getPhysicalIndex(fidx)];
-        if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) {
-          this._update();
-        }
-      }
-    },
-    _didMoveUp: function() {
-      this._focusPhysicalItem(this._focusedIndex - 1);
-    },
-    _didMoveDown: function(e) {
-      e.detail.keyboardEvent.preventDefault();
-      this._focusPhysicalItem(this._focusedIndex + 1);
-    },
-    _didEnter: function(e) {
-      this._focusPhysicalItem(this._focusedIndex);
-      this._selectionHandler(e.detail.keyboardEvent);
-    }
-  });
-})();
-
+}else{this._createFocusBackfillItem()}}else if(this._virtualCount>0&&this._physicalCount>0){this._focusedIndex=this._virtualStart;this._focusedItem=this._physicalItems[this._physicalStart]}},_isIndexRendered:function(idx){return idx>=this._virtualStart&&idx<=this._virtualEnd},_isIndexVisible:function(idx){return idx>=this.firstVisibleIndex&&idx<=this.lastVisibleIndex},_getPhysicalIndex:function(idx){return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))]},_focusPhysicalItem:function(idx){if(idx<0||idx>=this._virtualCount){return}this._restoreFocusedItem();if(!this._isIndexRendered(idx)){this.scrollToIndex(idx)}var physicalItem=this._physicalItems[this._getPhysicalIndex(idx)];var model=physicalItem._templateInstance;var focusable;model.tabIndex=SECRET_TABINDEX;if(physicalItem.tabIndex===SECRET_TABINDEX){focusable=physicalItem}if(!focusable){focusable=Polymer.dom(physicalItem).querySelector('[tabindex="'+SECRET_TABINDEX+'"]')}model.tabIndex=0;this._focusedIndex=idx;focusable&&focusable.focus()},_removeFocusedItem:function(){if(this._offscreenFocusedItem){Polymer.dom(this).removeChild(this._offscreenFocusedItem)}this._offscreenFocusedItem=null;this._focusBackfillItem=null;this._focusedItem=null;this._focusedIndex=-1},_createFocusBackfillItem:function(){var pidx,fidx=this._focusedIndex;if(this._offscreenFocusedItem||fidx<0){return}if(!this._focusBackfillItem){var stampedTemplate=this.stamp(null);this._focusBackfillItem=stampedTemplate.root.querySelector("*");Polymer.dom(this).appendChild(stampedTemplate.root)}pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._offscreenFocusedItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._focusBackfillItem;this.translate3d(0,HIDDEN_Y,0,this._offscreenFocusedItem)}},_restoreFocusedItem:function(){var pidx,fidx=this._focusedIndex;if(!this._offscreenFocusedItem||this._focusedIndex<0){return}this._assignModels();pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._focusBackfillItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._offscreenFocusedItem;this._offscreenFocusedItem=null;this.translate3d(0,HIDDEN_Y,0,this._focusBackfillItem)}},_didFocus:function(e){var targetModel=this.modelForElement(e.target);var focusedModel=this._focusedItem?this._focusedItem._templateInstance:null;var hasOffscreenFocusedItem=this._offscreenFocusedItem!==null;var fidx=this._focusedIndex;if(!targetModel||!focusedModel){return}if(focusedModel===targetModel){if(!this._isIndexVisible(fidx)){this.scrollToIndex(fidx)}}else{this._restoreFocusedItem();focusedModel.tabIndex=-1;targetModel.tabIndex=0;fidx=targetModel[this.indexAs];this._focusedIndex=fidx;this._focusedItem=this._physicalItems[this._getPhysicalIndex(fidx)];if(hasOffscreenFocusedItem&&!this._offscreenFocusedItem){this._update()}}},_didMoveUp:function(){this._focusPhysicalItem(this._focusedIndex-1)},_didMoveDown:function(e){e.detail.keyboardEvent.preventDefault();this._focusPhysicalItem(this._focusedIndex+1)},_didEnter:function(e){this._focusPhysicalItem(this._focusedIndex);this._selectionHandler(e.detail.keyboardEvent)}})})();
 // 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.
-cr.define('downloads', function() {
-  function chromeSendWithId(chromeSendName) {
-    return function(id) {
-      chrome.send(chromeSendName, [ id ]);
-    };
-  }
-  function ActionService() {
-    this.searchTerms_ = [];
-  }
-  function trim(s) {
-    return s.trim();
-  }
-  function truthy(value) {
-    return !!value;
-  }
-  ActionService.splitTerms = function(searchText) {
-    return searchText.split(/"([^"]*)"/).map(trim).filter(truthy);
-  };
-  ActionService.prototype = {
-    cancel: chromeSendWithId('cancel'),
-    clearAll: function() {
-      if (loadTimeData.getBoolean('allowDeletingHistory')) {
-        chrome.send('clearAll');
-        this.search('');
-      }
-    },
-    discardDangerous: chromeSendWithId('discardDangerous'),
-    download: function(url) {
-      var a = document.createElement('a');
-      a.href = url;
-      a.setAttribute('download', '');
-      a.click();
-    },
-    drag: chromeSendWithId('drag'),
-    loadMore: function() {
-      chrome.send('getDownloads', this.searchTerms_);
-    },
-    isSearching: function() {
-      return this.searchTerms_.length > 0;
-    },
-    openDownloadsFolder: chrome.send.bind(chrome, 'openDownloadsFolder'),
-    openFile: chromeSendWithId('openFile'),
-    pause: chromeSendWithId('pause'),
-    remove: chromeSendWithId('remove'),
-    resume: chromeSendWithId('resume'),
-    saveDangerous: chromeSendWithId('saveDangerous'),
-    search: function(searchText) {
-      var searchTerms = ActionService.splitTerms(searchText);
-      var sameTerms = searchTerms.length == this.searchTerms_.length;
-      for (var i = 0; sameTerms && i < searchTerms.length; ++i) {
-        if (searchTerms[i] != this.searchTerms_[i]) sameTerms = false;
-      }
-      if (sameTerms) return false;
-      this.searchTerms_ = searchTerms;
-      this.loadMore();
-      return true;
-    },
-    show: chromeSendWithId('show'),
-    undo: chrome.send.bind(chrome, 'undo')
-  };
-  cr.addSingletonGetter(ActionService);
-  return {
-    ActionService: ActionService
-  };
-});
-
+cr.define("downloads",function(){function chromeSendWithId(chromeSendName){return function(id){chrome.send(chromeSendName,[id])}}function ActionService(){this.searchTerms_=[]}function trim(s){return s.trim()}function truthy(value){return!!value}ActionService.splitTerms=function(searchText){return searchText.split(/"([^"]*)"/).map(trim).filter(truthy)};ActionService.prototype={cancel:chromeSendWithId("cancel"),clearAll:function(){if(loadTimeData.getBoolean("allowDeletingHistory")){chrome.send("clearAll");this.search("")}},discardDangerous:chromeSendWithId("discardDangerous"),download:function(url){var a=document.createElement("a");a.href=url;a.setAttribute("download","");a.click()},drag:chromeSendWithId("drag"),loadMore:function(){chrome.send("getDownloads",this.searchTerms_)},isSearching:function(){return this.searchTerms_.length>0},openDownloadsFolder:chrome.send.bind(chrome,"openDownloadsFolder"),openFile:chromeSendWithId("openFile"),pause:chromeSendWithId("pause"),remove:chromeSendWithId("remove"),resume:chromeSendWithId("resume"),saveDangerous:chromeSendWithId("saveDangerous"),search:function(searchText){var searchTerms=ActionService.splitTerms(searchText);var sameTerms=searchTerms.length==this.searchTerms_.length;for(var i=0;sameTerms&&i<searchTerms.length;++i){if(searchTerms[i]!=this.searchTerms_[i])sameTerms=false}if(sameTerms)return false;this.searchTerms_=searchTerms;this.loadMore();return true},show:chromeSendWithId("show"),undo:chrome.send.bind(chrome,"undo")};cr.addSingletonGetter(ActionService);return{ActionService:ActionService}});
 // 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.
-cr.define('downloads', function() {
-  var DangerType = {
-    NOT_DANGEROUS: 'NOT_DANGEROUS',
-    DANGEROUS_FILE: 'DANGEROUS_FILE',
-    DANGEROUS_URL: 'DANGEROUS_URL',
-    DANGEROUS_CONTENT: 'DANGEROUS_CONTENT',
-    UNCOMMON_CONTENT: 'UNCOMMON_CONTENT',
-    DANGEROUS_HOST: 'DANGEROUS_HOST',
-    POTENTIALLY_UNWANTED: 'POTENTIALLY_UNWANTED'
-  };
-  var States = {
-    IN_PROGRESS: 'IN_PROGRESS',
-    CANCELLED: 'CANCELLED',
-    COMPLETE: 'COMPLETE',
-    PAUSED: 'PAUSED',
-    DANGEROUS: 'DANGEROUS',
-    INTERRUPTED: 'INTERRUPTED'
-  };
-  return {
-    DangerType: DangerType,
-    States: States
-  };
-});
-
+cr.define("downloads",function(){var DangerType={NOT_DANGEROUS:"NOT_DANGEROUS",DANGEROUS_FILE:"DANGEROUS_FILE",DANGEROUS_URL:"DANGEROUS_URL",DANGEROUS_CONTENT:"DANGEROUS_CONTENT",UNCOMMON_CONTENT:"UNCOMMON_CONTENT",DANGEROUS_HOST:"DANGEROUS_HOST",POTENTIALLY_UNWANTED:"POTENTIALLY_UNWANTED"};var States={IN_PROGRESS:"IN_PROGRESS",CANCELLED:"CANCELLED",COMPLETE:"COMPLETE",PAUSED:"PAUSED",DANGEROUS:"DANGEROUS",INTERRUPTED:"INTERRUPTED"};return{DangerType:DangerType,States:States}});
 // 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.
-var ActionLink = document.registerElement('action-link', {
-  prototype: {
-    __proto__: HTMLAnchorElement.prototype,
-    createdCallback: function() {
-      this.tabIndex = this.disabled ? -1 : 0;
-      if (!this.hasAttribute('role')) this.setAttribute('role', 'link');
-      this.addEventListener('keydown', function(e) {
-        if (!this.disabled && e.key == 'Enter' && !this.href) {
-          window.setTimeout(this.click.bind(this), 0);
-        }
-      });
-      function preventDefault(e) {
-        e.preventDefault();
-      }
-      function removePreventDefault() {
-        document.removeEventListener('selectstart', preventDefault);
-        document.removeEventListener('mouseup', removePreventDefault);
-      }
-      this.addEventListener('mousedown', function() {
-        document.addEventListener('selectstart', preventDefault);
-        document.addEventListener('mouseup', removePreventDefault);
-        if (document.activeElement != this) this.classList.add('no-outline');
-      });
-      this.addEventListener('blur', function() {
-        this.classList.remove('no-outline');
-      });
-    },
-    set disabled(disabled) {
-      if (disabled) HTMLAnchorElement.prototype.setAttribute.call(this, 'disabled', ''); else HTMLAnchorElement.prototype.removeAttribute.call(this, 'disabled');
-      this.tabIndex = disabled ? -1 : 0;
-    },
-    get disabled() {
-      return this.hasAttribute('disabled');
-    },
-    setAttribute: function(attr, val) {
-      if (attr.toLowerCase() == 'disabled') this.disabled = true; else HTMLAnchorElement.prototype.setAttribute.apply(this, arguments);
-    },
-    removeAttribute: function(attr) {
-      if (attr.toLowerCase() == 'disabled') this.disabled = false; else HTMLAnchorElement.prototype.removeAttribute.apply(this, arguments);
-    }
-  },
-  "extends": 'a'
-});
-
-(function() {
-  var metaDatas = {};
-  var metaArrays = {};
-  var singleton = null;
-  Polymer.IronMeta = Polymer({
-    is: 'iron-meta',
-    properties: {
-      type: {
-        type: String,
-        value: 'default',
-        observer: '_typeChanged'
-      },
-      key: {
-        type: String,
-        observer: '_keyChanged'
-      },
-      value: {
-        type: Object,
-        notify: true,
-        observer: '_valueChanged'
-      },
-      self: {
-        type: Boolean,
-        observer: '_selfChanged'
-      },
-      list: {
-        type: Array,
-        notify: true
-      }
-    },
-    hostAttributes: {
-      hidden: true
-    },
-    factoryImpl: function(config) {
-      if (config) {
-        for (var n in config) {
-          switch (n) {
-           case 'type':
-           case 'key':
-           case 'value':
-            this[n] = config[n];
-            break;
-          }
-        }
-      }
-    },
-    created: function() {
-      this._metaDatas = metaDatas;
-      this._metaArrays = metaArrays;
-    },
-    _keyChanged: function(key, old) {
-      this._resetRegistration(old);
-    },
-    _valueChanged: function(value) {
-      this._resetRegistration(this.key);
-    },
-    _selfChanged: function(self) {
-      if (self) {
-        this.value = this;
-      }
-    },
-    _typeChanged: function(type) {
-      this._unregisterKey(this.key);
-      if (!metaDatas[type]) {
-        metaDatas[type] = {};
-      }
-      this._metaData = metaDatas[type];
-      if (!metaArrays[type]) {
-        metaArrays[type] = [];
-      }
-      this.list = metaArrays[type];
-      this._registerKeyValue(this.key, this.value);
-    },
-    byKey: function(key) {
-      return this._metaData && this._metaData[key];
-    },
-    _resetRegistration: function(oldKey) {
-      this._unregisterKey(oldKey);
-      this._registerKeyValue(this.key, this.value);
-    },
-    _unregisterKey: function(key) {
-      this._unregister(key, this._metaData, this.list);
-    },
-    _registerKeyValue: function(key, value) {
-      this._register(key, value, this._metaData, this.list);
-    },
-    _register: function(key, value, data, list) {
-      if (key && data && value !== undefined) {
-        data[key] = value;
-        list.push(value);
-      }
-    },
-    _unregister: function(key, data, list) {
-      if (key && data) {
-        if (key in data) {
-          var value = data[key];
-          delete data[key];
-          this.arrayDelete(list, value);
-        }
-      }
-    }
-  });
-  Polymer.IronMeta.getIronMeta = function getIronMeta() {
-    if (singleton === null) {
-      singleton = new Polymer.IronMeta();
-    }
-    return singleton;
-  };
-  Polymer.IronMetaQuery = Polymer({
-    is: 'iron-meta-query',
-    properties: {
-      type: {
-        type: String,
-        value: 'default',
-        observer: '_typeChanged'
-      },
-      key: {
-        type: String,
-        observer: '_keyChanged'
-      },
-      value: {
-        type: Object,
-        notify: true,
-        readOnly: true
-      },
-      list: {
-        type: Array,
-        notify: true
-      }
-    },
-    factoryImpl: function(config) {
-      if (config) {
-        for (var n in config) {
-          switch (n) {
-           case 'type':
-           case 'key':
-            this[n] = config[n];
-            break;
-          }
-        }
-      }
-    },
-    created: function() {
-      this._metaDatas = metaDatas;
-      this._metaArrays = metaArrays;
-    },
-    _keyChanged: function(key) {
-      this._setValue(this._metaData && this._metaData[key]);
-    },
-    _typeChanged: function(type) {
-      this._metaData = metaDatas[type];
-      this.list = metaArrays[type];
-      if (this.key) {
-        this._keyChanged(this.key);
-      }
-    },
-    byKey: function(key) {
-      return this._metaData && this._metaData[key];
-    }
-  });
-})();
-
-Polymer({
-  is: 'iron-icon',
-  properties: {
-    icon: {
-      type: String,
-      observer: '_iconChanged'
-    },
-    theme: {
-      type: String,
-      observer: '_updateIcon'
-    },
-    src: {
-      type: String,
-      observer: '_srcChanged'
-    },
-    _meta: {
-      value: Polymer.Base.create('iron-meta', {
-        type: 'iconset'
-      }),
-      observer: '_updateIcon'
-    }
-  },
-  _DEFAULT_ICONSET: 'icons',
-  _iconChanged: function(icon) {
-    var parts = (icon || '').split(':');
-    this._iconName = parts.pop();
-    this._iconsetName = parts.pop() || this._DEFAULT_ICONSET;
-    this._updateIcon();
-  },
-  _srcChanged: function(src) {
-    this._updateIcon();
-  },
-  _usesIconset: function() {
-    return this.icon || !this.src;
-  },
-  _updateIcon: function() {
-    if (this._usesIconset()) {
-      if (this._img && this._img.parentNode) {
-        Polymer.dom(this.root).removeChild(this._img);
-      }
-      if (this._iconName === "") {
-        if (this._iconset) {
-          this._iconset.removeIcon(this);
-        }
-      } else if (this._iconsetName && this._meta) {
-        this._iconset = this._meta.byKey(this._iconsetName);
-        if (this._iconset) {
-          this._iconset.applyIcon(this, this._iconName, this.theme);
-          this.unlisten(window, 'iron-iconset-added', '_updateIcon');
-        } else {
-          this.listen(window, 'iron-iconset-added', '_updateIcon');
-        }
-      }
-    } else {
-      if (this._iconset) {
-        this._iconset.removeIcon(this);
-      }
-      if (!this._img) {
-        this._img = document.createElement('img');
-        this._img.style.width = '100%';
-        this._img.style.height = '100%';
-        this._img.draggable = false;
-      }
-      this._img.src = this.src;
-      Polymer.dom(this.root).appendChild(this._img);
-    }
-  }
-});
-
-Polymer.IronControlState = {
-  properties: {
-    focused: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      readOnly: true,
-      reflectToAttribute: true
-    },
-    disabled: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: '_disabledChanged',
-      reflectToAttribute: true
-    },
-    _oldTabIndex: {
-      type: Number
-    },
-    _boundFocusBlurHandler: {
-      type: Function,
-      value: function() {
-        return this._focusBlurHandler.bind(this);
-      }
-    }
-  },
-  observers: [ '_changedControlState(focused, disabled)' ],
-  ready: function() {
-    this.addEventListener('focus', this._boundFocusBlurHandler, true);
-    this.addEventListener('blur', this._boundFocusBlurHandler, true);
-  },
-  _focusBlurHandler: function(event) {
-    if (event.target === this) {
-      this._setFocused(event.type === 'focus');
-    } else if (!this.shadowRoot) {
-      var target = Polymer.dom(event).localTarget;
-      if (!this.isLightDescendant(target)) {
-        this.fire(event.type, {
-          sourceEvent: event
-        }, {
-          node: this,
-          bubbles: event.bubbles,
-          cancelable: event.cancelable
-        });
-      }
-    }
-  },
-  _disabledChanged: function(disabled, old) {
-    this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
-    this.style.pointerEvents = disabled ? 'none' : '';
-    if (disabled) {
-      this._oldTabIndex = this.tabIndex;
-      this._setFocused(false);
-      this.tabIndex = -1;
-      this.blur();
-    } else if (this._oldTabIndex !== undefined) {
-      this.tabIndex = this._oldTabIndex;
-    }
-  },
-  _changedControlState: function() {
-    if (this._controlStateChanged) {
-      this._controlStateChanged();
-    }
-  }
-};
-
-Polymer.IronButtonStateImpl = {
-  properties: {
-    pressed: {
-      type: Boolean,
-      readOnly: true,
-      value: false,
-      reflectToAttribute: true,
-      observer: '_pressedChanged'
-    },
-    toggles: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    active: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      reflectToAttribute: true
-    },
-    pointerDown: {
-      type: Boolean,
-      readOnly: true,
-      value: false
-    },
-    receivedFocusFromKeyboard: {
-      type: Boolean,
-      readOnly: true
-    },
-    ariaActiveAttribute: {
-      type: String,
-      value: 'aria-pressed',
-      observer: '_ariaActiveAttributeChanged'
-    }
-  },
-  listeners: {
-    down: '_downHandler',
-    up: '_upHandler',
-    tap: '_tapHandler'
-  },
-  observers: [ '_detectKeyboardFocus(focused)', '_activeChanged(active, ariaActiveAttribute)' ],
-  keyBindings: {
-    'enter:keydown': '_asyncClick',
-    'space:keydown': '_spaceKeyDownHandler',
-    'space:keyup': '_spaceKeyUpHandler'
-  },
-  _mouseEventRe: /^mouse/,
-  _tapHandler: function() {
-    if (this.toggles) {
-      this._userActivate(!this.active);
-    } else {
-      this.active = false;
-    }
-  },
-  _detectKeyboardFocus: function(focused) {
-    this._setReceivedFocusFromKeyboard(!this.pointerDown && focused);
-  },
-  _userActivate: function(active) {
-    if (this.active !== active) {
-      this.active = active;
-      this.fire('change');
-    }
-  },
-  _downHandler: function(event) {
-    this._setPointerDown(true);
-    this._setPressed(true);
-    this._setReceivedFocusFromKeyboard(false);
-  },
-  _upHandler: function() {
-    this._setPointerDown(false);
-    this._setPressed(false);
-  },
-  _spaceKeyDownHandler: function(event) {
-    var keyboardEvent = event.detail.keyboardEvent;
-    var target = Polymer.dom(keyboardEvent).localTarget;
-    if (this.isLightDescendant(target)) return;
-    keyboardEvent.preventDefault();
-    keyboardEvent.stopImmediatePropagation();
-    this._setPressed(true);
-  },
-  _spaceKeyUpHandler: function(event) {
-    var keyboardEvent = event.detail.keyboardEvent;
-    var target = Polymer.dom(keyboardEvent).localTarget;
-    if (this.isLightDescendant(target)) return;
-    if (this.pressed) {
-      this._asyncClick();
-    }
-    this._setPressed(false);
-  },
-  _asyncClick: function() {
-    this.async(function() {
-      this.click();
-    }, 1);
-  },
-  _pressedChanged: function(pressed) {
-    this._changedButtonState();
-  },
-  _ariaActiveAttributeChanged: function(value, oldValue) {
-    if (oldValue && oldValue != value && this.hasAttribute(oldValue)) {
-      this.removeAttribute(oldValue);
-    }
-  },
-  _activeChanged: function(active, ariaActiveAttribute) {
-    if (this.toggles) {
-      this.setAttribute(this.ariaActiveAttribute, active ? 'true' : 'false');
-    } else {
-      this.removeAttribute(this.ariaActiveAttribute);
-    }
-    this._changedButtonState();
-  },
-  _controlStateChanged: function() {
-    if (this.disabled) {
-      this._setPressed(false);
-    } else {
-      this._changedButtonState();
-    }
-  },
-  _changedButtonState: function() {
-    if (this._buttonStateChanged) {
-      this._buttonStateChanged();
-    }
-  }
-};
-
-Polymer.IronButtonState = [ Polymer.IronA11yKeysBehavior, Polymer.IronButtonStateImpl ];
-
-(function() {
-  var Utility = {
-    distance: function(x1, y1, x2, y2) {
-      var xDelta = x1 - x2;
-      var yDelta = y1 - y2;
-      return Math.sqrt(xDelta * xDelta + yDelta * yDelta);
-    },
-    now: window.performance && window.performance.now ? window.performance.now.bind(window.performance) : Date.now
-  };
-  function ElementMetrics(element) {
-    this.element = element;
-    this.width = this.boundingRect.width;
-    this.height = this.boundingRect.height;
-    this.size = Math.max(this.width, this.height);
-  }
-  ElementMetrics.prototype = {
-    get boundingRect() {
-      return this.element.getBoundingClientRect();
-    },
-    furthestCornerDistanceFrom: function(x, y) {
-      var topLeft = Utility.distance(x, y, 0, 0);
-      var topRight = Utility.distance(x, y, this.width, 0);
-      var bottomLeft = Utility.distance(x, y, 0, this.height);
-      var bottomRight = Utility.distance(x, y, this.width, this.height);
-      return Math.max(topLeft, topRight, bottomLeft, bottomRight);
-    }
-  };
-  function Ripple(element) {
-    this.element = element;
-    this.color = window.getComputedStyle(element).color;
-    this.wave = document.createElement('div');
-    this.waveContainer = document.createElement('div');
-    this.wave.style.backgroundColor = this.color;
-    this.wave.classList.add('wave');
-    this.waveContainer.classList.add('wave-container');
-    Polymer.dom(this.waveContainer).appendChild(this.wave);
-    this.resetInteractionState();
-  }
-  Ripple.MAX_RADIUS = 300;
-  Ripple.prototype = {
-    get recenters() {
-      return this.element.recenters;
-    },
-    get center() {
-      return this.element.center;
-    },
-    get mouseDownElapsed() {
-      var elapsed;
-      if (!this.mouseDownStart) {
-        return 0;
-      }
-      elapsed = Utility.now() - this.mouseDownStart;
-      if (this.mouseUpStart) {
-        elapsed -= this.mouseUpElapsed;
-      }
-      return elapsed;
-    },
-    get mouseUpElapsed() {
-      return this.mouseUpStart ? Utility.now() - this.mouseUpStart : 0;
-    },
-    get mouseDownElapsedSeconds() {
-      return this.mouseDownElapsed / 1e3;
-    },
-    get mouseUpElapsedSeconds() {
-      return this.mouseUpElapsed / 1e3;
-    },
-    get mouseInteractionSeconds() {
-      return this.mouseDownElapsedSeconds + this.mouseUpElapsedSeconds;
-    },
-    get initialOpacity() {
-      return this.element.initialOpacity;
-    },
-    get opacityDecayVelocity() {
-      return this.element.opacityDecayVelocity;
-    },
-    get radius() {
-      var width2 = this.containerMetrics.width * this.containerMetrics.width;
-      var height2 = this.containerMetrics.height * this.containerMetrics.height;
-      var waveRadius = Math.min(Math.sqrt(width2 + height2), Ripple.MAX_RADIUS) * 1.1 + 5;
-      var duration = 1.1 - .2 * (waveRadius / Ripple.MAX_RADIUS);
-      var timeNow = this.mouseInteractionSeconds / duration;
-      var size = waveRadius * (1 - Math.pow(80, -timeNow));
-      return Math.abs(size);
-    },
-    get opacity() {
-      if (!this.mouseUpStart) {
-        return this.initialOpacity;
-      }
-      return Math.max(0, this.initialOpacity - this.mouseUpElapsedSeconds * this.opacityDecayVelocity);
-    },
-    get outerOpacity() {
-      var outerOpacity = this.mouseUpElapsedSeconds * .3;
-      var waveOpacity = this.opacity;
-      return Math.max(0, Math.min(outerOpacity, waveOpacity));
-    },
-    get isOpacityFullyDecayed() {
-      return this.opacity < .01 && this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
-    },
-    get isRestingAtMaxRadius() {
-      return this.opacity >= this.initialOpacity && this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
-    },
-    get isAnimationComplete() {
-      return this.mouseUpStart ? this.isOpacityFullyDecayed : this.isRestingAtMaxRadius;
-    },
-    get translationFraction() {
-      return Math.min(1, this.radius / this.containerMetrics.size * 2 / Math.sqrt(2));
-    },
-    get xNow() {
-      if (this.xEnd) {
-        return this.xStart + this.translationFraction * (this.xEnd - this.xStart);
-      }
-      return this.xStart;
-    },
-    get yNow() {
-      if (this.yEnd) {
-        return this.yStart + this.translationFraction * (this.yEnd - this.yStart);
-      }
-      return this.yStart;
-    },
-    get isMouseDown() {
-      return this.mouseDownStart && !this.mouseUpStart;
-    },
-    resetInteractionState: function() {
-      this.maxRadius = 0;
-      this.mouseDownStart = 0;
-      this.mouseUpStart = 0;
-      this.xStart = 0;
-      this.yStart = 0;
-      this.xEnd = 0;
-      this.yEnd = 0;
-      this.slideDistance = 0;
-      this.containerMetrics = new ElementMetrics(this.element);
-    },
-    draw: function() {
-      var scale;
-      var translateString;
-      var dx;
-      var dy;
-      this.wave.style.opacity = this.opacity;
-      scale = this.radius / (this.containerMetrics.size / 2);
-      dx = this.xNow - this.containerMetrics.width / 2;
-      dy = this.yNow - this.containerMetrics.height / 2;
-      this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy + 'px)';
-      this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + 'px, 0)';
-      this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')';
-      this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)';
-    },
-    downAction: function(event) {
-      var xCenter = this.containerMetrics.width / 2;
-      var yCenter = this.containerMetrics.height / 2;
-      this.resetInteractionState();
-      this.mouseDownStart = Utility.now();
-      if (this.center) {
-        this.xStart = xCenter;
-        this.yStart = yCenter;
-        this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEnd, this.yEnd);
-      } else {
-        this.xStart = event ? event.detail.x - this.containerMetrics.boundingRect.left : this.containerMetrics.width / 2;
-        this.yStart = event ? event.detail.y - this.containerMetrics.boundingRect.top : this.containerMetrics.height / 2;
-      }
-      if (this.recenters) {
-        this.xEnd = xCenter;
-        this.yEnd = yCenter;
-        this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEnd, this.yEnd);
-      }
-      this.maxRadius = this.containerMetrics.furthestCornerDistanceFrom(this.xStart, this.yStart);
-      this.waveContainer.style.top = (this.containerMetrics.height - this.containerMetrics.size) / 2 + 'px';
-      this.waveContainer.style.left = (this.containerMetrics.width - this.containerMetrics.size) / 2 + 'px';
-      this.waveContainer.style.width = this.containerMetrics.size + 'px';
-      this.waveContainer.style.height = this.containerMetrics.size + 'px';
-    },
-    upAction: function(event) {
-      if (!this.isMouseDown) {
-        return;
-      }
-      this.mouseUpStart = Utility.now();
-    },
-    remove: function() {
-      Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer);
-    }
-  };
-  Polymer({
-    is: 'paper-ripple',
-    behaviors: [ Polymer.IronA11yKeysBehavior ],
-    properties: {
-      initialOpacity: {
-        type: Number,
-        value: .25
-      },
-      opacityDecayVelocity: {
-        type: Number,
-        value: .8
-      },
-      recenters: {
-        type: Boolean,
-        value: false
-      },
-      center: {
-        type: Boolean,
-        value: false
-      },
-      ripples: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      animating: {
-        type: Boolean,
-        readOnly: true,
-        reflectToAttribute: true,
-        value: false
-      },
-      holdDown: {
-        type: Boolean,
-        value: false,
-        observer: '_holdDownChanged'
-      },
-      noink: {
-        type: Boolean,
-        value: false
-      },
-      _animating: {
-        type: Boolean
-      },
-      _boundAnimate: {
-        type: Function,
-        value: function() {
-          return this.animate.bind(this);
-        }
-      }
-    },
-    get target() {
-      return this.keyEventTarget;
-    },
-    keyBindings: {
-      'enter:keydown': '_onEnterKeydown',
-      'space:keydown': '_onSpaceKeydown',
-      'space:keyup': '_onSpaceKeyup'
-    },
-    attached: function() {
-      if (this.parentNode.nodeType == 11) {
-        this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host;
-      } else {
-        this.keyEventTarget = this.parentNode;
-      }
-      var keyEventTarget = this.keyEventTarget;
-      this.listen(keyEventTarget, 'up', 'uiUpAction');
-      this.listen(keyEventTarget, 'down', 'uiDownAction');
-    },
-    detached: function() {
-      this.unlisten(this.keyEventTarget, 'up', 'uiUpAction');
-      this.unlisten(this.keyEventTarget, 'down', 'uiDownAction');
-      this.keyEventTarget = null;
-    },
-    get shouldKeepAnimating() {
-      for (var index = 0; index < this.ripples.length; ++index) {
-        if (!this.ripples[index].isAnimationComplete) {
-          return true;
-        }
-      }
-      return false;
-    },
-    simulatedRipple: function() {
-      this.downAction(null);
-      this.async(function() {
-        this.upAction();
-      }, 1);
-    },
-    uiDownAction: function(event) {
-      if (!this.noink) {
-        this.downAction(event);
-      }
-    },
-    downAction: function(event) {
-      if (this.holdDown && this.ripples.length > 0) {
-        return;
-      }
-      var ripple = this.addRipple();
-      ripple.downAction(event);
-      if (!this._animating) {
-        this._animating = true;
-        this.animate();
-      }
-    },
-    uiUpAction: function(event) {
-      if (!this.noink) {
-        this.upAction(event);
-      }
-    },
-    upAction: function(event) {
-      if (this.holdDown) {
-        return;
-      }
-      this.ripples.forEach(function(ripple) {
-        ripple.upAction(event);
-      });
-      this._animating = true;
-      this.animate();
-    },
-    onAnimationComplete: function() {
-      this._animating = false;
-      this.$.background.style.backgroundColor = null;
-      this.fire('transitionend');
-    },
-    addRipple: function() {
-      var ripple = new Ripple(this);
-      Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);
-      this.$.background.style.backgroundColor = ripple.color;
-      this.ripples.push(ripple);
-      this._setAnimating(true);
-      return ripple;
-    },
-    removeRipple: function(ripple) {
-      var rippleIndex = this.ripples.indexOf(ripple);
-      if (rippleIndex < 0) {
-        return;
-      }
-      this.ripples.splice(rippleIndex, 1);
-      ripple.remove();
-      if (!this.ripples.length) {
-        this._setAnimating(false);
-      }
-    },
-    animate: function() {
-      if (!this._animating) {
-        return;
-      }
-      var index;
-      var ripple;
-      for (index = 0; index < this.ripples.length; ++index) {
-        ripple = this.ripples[index];
-        ripple.draw();
-        this.$.background.style.opacity = ripple.outerOpacity;
-        if (ripple.isOpacityFullyDecayed && !ripple.isRestingAtMaxRadius) {
-          this.removeRipple(ripple);
-        }
-      }
-      if (!this.shouldKeepAnimating && this.ripples.length === 0) {
-        this.onAnimationComplete();
-      } else {
-        window.requestAnimationFrame(this._boundAnimate);
-      }
-    },
-    _onEnterKeydown: function() {
-      this.uiDownAction();
-      this.async(this.uiUpAction, 1);
-    },
-    _onSpaceKeydown: function() {
-      this.uiDownAction();
-    },
-    _onSpaceKeyup: function() {
-      this.uiUpAction();
-    },
-    _holdDownChanged: function(newVal, oldVal) {
-      if (oldVal === undefined) {
-        return;
-      }
-      if (newVal) {
-        this.downAction();
-      } else {
-        this.upAction();
-      }
-    }
-  });
-})();
-
-Polymer.PaperRippleBehavior = {
-  properties: {
-    noink: {
-      type: Boolean,
-      observer: '_noinkChanged'
-    },
-    _rippleContainer: {
-      type: Object
-    }
-  },
-  _buttonStateChanged: function() {
-    if (this.focused) {
-      this.ensureRipple();
-    }
-  },
-  _downHandler: function(event) {
-    Polymer.IronButtonStateImpl._downHandler.call(this, event);
-    if (this.pressed) {
-      this.ensureRipple(event);
-    }
-  },
-  ensureRipple: function(optTriggeringEvent) {
-    if (!this.hasRipple()) {
-      this._ripple = this._createRipple();
-      this._ripple.noink = this.noink;
-      var rippleContainer = this._rippleContainer || this.root;
-      if (rippleContainer) {
-        Polymer.dom(rippleContainer).appendChild(this._ripple);
-      }
-      if (optTriggeringEvent) {
-        var domContainer = Polymer.dom(this._rippleContainer || this);
-        var target = Polymer.dom(optTriggeringEvent).rootTarget;
-        if (domContainer.deepContains(target)) {
-          this._ripple.uiDownAction(optTriggeringEvent);
-        }
-      }
-    }
-  },
-  getRipple: function() {
-    this.ensureRipple();
-    return this._ripple;
-  },
-  hasRipple: function() {
-    return Boolean(this._ripple);
-  },
-  _createRipple: function() {
-    return document.createElement('paper-ripple');
-  },
-  _noinkChanged: function(noink) {
-    if (this.hasRipple()) {
-      this._ripple.noink = noink;
-    }
-  }
-};
-
-Polymer.PaperButtonBehaviorImpl = {
-  properties: {
-    elevation: {
-      type: Number,
-      reflectToAttribute: true,
-      readOnly: true
-    }
-  },
-  observers: [ '_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)', '_computeKeyboardClass(receivedFocusFromKeyboard)' ],
-  hostAttributes: {
-    role: 'button',
-    tabindex: '0',
-    animated: true
-  },
-  _calculateElevation: function() {
-    var e = 1;
-    if (this.disabled) {
-      e = 0;
-    } else if (this.active || this.pressed) {
-      e = 4;
-    } else if (this.receivedFocusFromKeyboard) {
-      e = 3;
-    }
-    this._setElevation(e);
-  },
-  _computeKeyboardClass: function(receivedFocusFromKeyboard) {
-    this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
-  },
-  _spaceKeyDownHandler: function(event) {
-    Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
-    if (this.hasRipple() && this.getRipple().ripples.length < 1) {
-      this._ripple.uiDownAction();
-    }
-  },
-  _spaceKeyUpHandler: function(event) {
-    Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event);
-    if (this.hasRipple()) {
-      this._ripple.uiUpAction();
-    }
-  }
-};
-
-Polymer.PaperButtonBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperButtonBehaviorImpl ];
-
-Polymer({
-  is: 'paper-button',
-  behaviors: [ Polymer.PaperButtonBehavior ],
-  properties: {
-    raised: {
-      type: Boolean,
-      reflectToAttribute: true,
-      value: false,
-      observer: '_calculateElevation'
-    }
-  },
-  _calculateElevation: function() {
-    if (!this.raised) {
-      this._setElevation(0);
-    } else {
-      Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this);
-    }
-  }
-});
-
-Polymer({
-  is: 'paper-icon-button-light',
-  "extends": 'button',
-  behaviors: [ Polymer.PaperRippleBehavior ],
-  listeners: {
-    down: '_rippleDown',
-    up: '_rippleUp',
-    focus: '_rippleDown',
-    blur: '_rippleUp'
-  },
-  _rippleDown: function() {
-    this.getRipple().downAction();
-  },
-  _rippleUp: function() {
-    this.getRipple().upAction();
-  },
-  ensureRipple: function(var_args) {
-    var lastRipple = this._ripple;
-    Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
-    if (this._ripple && this._ripple !== lastRipple) {
-      this._ripple.center = true;
-      this._ripple.classList.add('circle');
-    }
-  }
-});
-
-Polymer.IronRangeBehavior = {
-  properties: {
-    value: {
-      type: Number,
-      value: 0,
-      notify: true,
-      reflectToAttribute: true
-    },
-    min: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    max: {
-      type: Number,
-      value: 100,
-      notify: true
-    },
-    step: {
-      type: Number,
-      value: 1,
-      notify: true
-    },
-    ratio: {
-      type: Number,
-      value: 0,
-      readOnly: true,
-      notify: true
-    }
-  },
-  observers: [ '_update(value, min, max, step)' ],
-  _calcRatio: function(value) {
-    return (this._clampValue(value) - this.min) / (this.max - this.min);
-  },
-  _clampValue: function(value) {
-    return Math.min(this.max, Math.max(this.min, this._calcStep(value)));
-  },
-  _calcStep: function(value) {
-    value = parseFloat(value);
-    if (!this.step) {
-      return value;
-    }
-    var numSteps = Math.round((value - this.min) / this.step);
-    if (this.step < 1) {
-      return numSteps / (1 / this.step) + this.min;
-    } else {
-      return numSteps * this.step + this.min;
-    }
-  },
-  _validateValue: function() {
-    var v = this._clampValue(this.value);
-    this.value = this.oldValue = isNaN(v) ? this.oldValue : v;
-    return this.value !== v;
-  },
-  _update: function() {
-    this._validateValue();
-    this._setRatio(this._calcRatio(this.value) * 100);
-  }
-};
-
-Polymer({
-  is: 'paper-progress',
-  behaviors: [ Polymer.IronRangeBehavior ],
-  properties: {
-    secondaryProgress: {
-      type: Number,
-      value: 0
-    },
-    secondaryRatio: {
-      type: Number,
-      value: 0,
-      readOnly: true
-    },
-    indeterminate: {
-      type: Boolean,
-      value: false,
-      observer: '_toggleIndeterminate'
-    },
-    disabled: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      observer: '_disabledChanged'
-    }
-  },
-  observers: [ '_progressChanged(secondaryProgress, value, min, max)' ],
-  hostAttributes: {
-    role: 'progressbar'
-  },
-  _toggleIndeterminate: function(indeterminate) {
-    this.toggleClass('indeterminate', indeterminate, this.$.primaryProgress);
-  },
-  _transformProgress: function(progress, ratio) {
-    var transform = 'scaleX(' + ratio / 100 + ')';
-    progress.style.transform = progress.style.webkitTransform = transform;
-  },
-  _mainRatioChanged: function(ratio) {
-    this._transformProgress(this.$.primaryProgress, ratio);
-  },
-  _progressChanged: function(secondaryProgress, value, min, max) {
-    secondaryProgress = this._clampValue(secondaryProgress);
-    value = this._clampValue(value);
-    var secondaryRatio = this._calcRatio(secondaryProgress) * 100;
-    var mainRatio = this._calcRatio(value) * 100;
-    this._setSecondaryRatio(secondaryRatio);
-    this._transformProgress(this.$.secondaryProgress, secondaryRatio);
-    this._transformProgress(this.$.primaryProgress, mainRatio);
-    this.secondaryProgress = secondaryProgress;
-    this.setAttribute('aria-valuenow', value);
-    this.setAttribute('aria-valuemin', min);
-    this.setAttribute('aria-valuemax', max);
-  },
-  _disabledChanged: function(disabled) {
-    this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
-  },
-  _hideSecondaryProgress: function(secondaryRatio) {
-    return secondaryRatio === 0;
-  }
-});
-
-Polymer({
-  is: 'iron-iconset-svg',
-  properties: {
-    name: {
-      type: String,
-      observer: '_nameChanged'
-    },
-    size: {
-      type: Number,
-      value: 24
-    }
-  },
-  attached: function() {
-    this.style.display = 'none';
-  },
-  getIconNames: function() {
-    this._icons = this._createIconMap();
-    return Object.keys(this._icons).map(function(n) {
-      return this.name + ':' + n;
-    }, this);
-  },
-  applyIcon: function(element, iconName) {
-    element = element.root || element;
-    this.removeIcon(element);
-    var svg = this._cloneIcon(iconName);
-    if (svg) {
-      var pde = Polymer.dom(element);
-      pde.insertBefore(svg, pde.childNodes[0]);
-      return element._svgIcon = svg;
-    }
-    return null;
-  },
-  removeIcon: function(element) {
-    if (element._svgIcon) {
-      Polymer.dom(element).removeChild(element._svgIcon);
-      element._svgIcon = null;
-    }
-  },
-  _nameChanged: function() {
-    new Polymer.IronMeta({
-      type: 'iconset',
-      key: this.name,
-      value: this
-    });
-    this.async(function() {
-      this.fire('iron-iconset-added', this, {
-        node: window
-      });
-    });
-  },
-  _createIconMap: function() {
-    var icons = Object.create(null);
-    Polymer.dom(this).querySelectorAll('[id]').forEach(function(icon) {
-      icons[icon.id] = icon;
-    });
-    return icons;
-  },
-  _cloneIcon: function(id) {
-    this._icons = this._icons || this._createIconMap();
-    return this._prepareSvgClone(this._icons[id], this.size);
-  },
-  _prepareSvgClone: function(sourceSvg, size) {
-    if (sourceSvg) {
-      var content = sourceSvg.cloneNode(true), svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), viewBox = content.getAttribute('viewBox') || '0 0 ' + size + ' ' + size;
-      svg.setAttribute('viewBox', viewBox);
-      svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
-      svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;';
-      svg.appendChild(content).removeAttribute('id');
-      return svg;
-    }
-    return null;
-  }
-});
-
+var ActionLink=document.registerElement("action-link",{prototype:{__proto__:HTMLAnchorElement.prototype,createdCallback:function(){this.tabIndex=this.disabled?-1:0;if(!this.hasAttribute("role"))this.setAttribute("role","link");this.addEventListener("keydown",function(e){if(!this.disabled&&e.key=="Enter"&&!this.href){window.setTimeout(this.click.bind(this),0)}});function preventDefault(e){e.preventDefault()}function removePreventDefault(){document.removeEventListener("selectstart",preventDefault);document.removeEventListener("mouseup",removePreventDefault)}this.addEventListener("mousedown",function(){document.addEventListener("selectstart",preventDefault);document.addEventListener("mouseup",removePreventDefault);if(document.activeElement!=this)this.classList.add("no-outline")});this.addEventListener("blur",function(){this.classList.remove("no-outline")})},set disabled(disabled){if(disabled)HTMLAnchorElement.prototype.setAttribute.call(this,"disabled","");else HTMLAnchorElement.prototype.removeAttribute.call(this,"disabled");this.tabIndex=disabled?-1:0},get disabled(){return this.hasAttribute("disabled")},setAttribute:function(attr,val){if(attr.toLowerCase()=="disabled")this.disabled=true;else HTMLAnchorElement.prototype.setAttribute.apply(this,arguments)},removeAttribute:function(attr){if(attr.toLowerCase()=="disabled")this.disabled=false;else HTMLAnchorElement.prototype.removeAttribute.apply(this,arguments)}},"extends":"a"});(function(){var metaDatas={};var metaArrays={};var singleton=null;Polymer.IronMeta=Polymer({is:"iron-meta",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,observer:"_valueChanged"},self:{type:Boolean,observer:"_selfChanged"},list:{type:Array,notify:true}},hostAttributes:{hidden:true},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":case"value":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key,old){this._resetRegistration(old)},_valueChanged:function(value){this._resetRegistration(this.key)},_selfChanged:function(self){if(self){this.value=this}},_typeChanged:function(type){this._unregisterKey(this.key);if(!metaDatas[type]){metaDatas[type]={}}this._metaData=metaDatas[type];if(!metaArrays[type]){metaArrays[type]=[]}this.list=metaArrays[type];this._registerKeyValue(this.key,this.value)},byKey:function(key){return this._metaData&&this._metaData[key]},_resetRegistration:function(oldKey){this._unregisterKey(oldKey);this._registerKeyValue(this.key,this.value)},_unregisterKey:function(key){this._unregister(key,this._metaData,this.list)},_registerKeyValue:function(key,value){this._register(key,value,this._metaData,this.list)},_register:function(key,value,data,list){if(key&&data&&value!==undefined){data[key]=value;list.push(value)}},_unregister:function(key,data,list){if(key&&data){if(key in data){var value=data[key];delete data[key];this.arrayDelete(list,value)}}}});Polymer.IronMeta.getIronMeta=function getIronMeta(){if(singleton===null){singleton=new Polymer.IronMeta}return singleton};Polymer.IronMetaQuery=Polymer({is:"iron-meta-query",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,readOnly:true},list:{type:Array,notify:true}},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key){this._setValue(this._metaData&&this._metaData[key])},_typeChanged:function(type){this._metaData=metaDatas[type];this.list=metaArrays[type];if(this.key){this._keyChanged(this.key)}},byKey:function(key){return this._metaData&&this._metaData[key]}})})();Polymer({is:"iron-icon",properties:{icon:{type:String,observer:"_iconChanged"},theme:{type:String,observer:"_updateIcon"},src:{type:String,observer:"_srcChanged"},_meta:{value:Polymer.Base.create("iron-meta",{type:"iconset"}),observer:"_updateIcon"}},_DEFAULT_ICONSET:"icons",_iconChanged:function(icon){var parts=(icon||"").split(":");this._iconName=parts.pop();this._iconsetName=parts.pop()||this._DEFAULT_ICONSET;this._updateIcon()},_srcChanged:function(src){this._updateIcon()},_usesIconset:function(){return this.icon||!this.src},_updateIcon:function(){if(this._usesIconset()){if(this._img&&this._img.parentNode){Polymer.dom(this.root).removeChild(this._img)}if(this._iconName===""){if(this._iconset){this._iconset.removeIcon(this)}}else if(this._iconsetName&&this._meta){this._iconset=this._meta.byKey(this._iconsetName);if(this._iconset){this._iconset.applyIcon(this,this._iconName,this.theme);this.unlisten(window,"iron-iconset-added","_updateIcon")}else{this.listen(window,"iron-iconset-added","_updateIcon")}}}else{if(this._iconset){this._iconset.removeIcon(this)}if(!this._img){this._img=document.createElement("img");this._img.style.width="100%";this._img.style.height="100%";this._img.draggable=false}this._img.src=this.src;Polymer.dom(this.root).appendChild(this._img)}}});Polymer.IronControlState={properties:{focused:{type:Boolean,value:false,notify:true,readOnly:true,reflectToAttribute:true},disabled:{type:Boolean,value:false,notify:true,observer:"_disabledChanged",reflectToAttribute:true},_oldTabIndex:{type:Number},_boundFocusBlurHandler:{type:Function,value:function(){return this._focusBlurHandler.bind(this)}}},observers:["_changedControlState(focused, disabled)"],ready:function(){this.addEventListener("focus",this._boundFocusBlurHandler,true);this.addEventListener("blur",this._boundFocusBlurHandler,true)},_focusBlurHandler:function(event){if(event.target===this){this._setFocused(event.type==="focus")}else if(!this.shadowRoot){var target=Polymer.dom(event).localTarget;if(!this.isLightDescendant(target)){this.fire(event.type,{sourceEvent:event},{node:this,bubbles:event.bubbles,cancelable:event.cancelable})}}},_disabledChanged:function(disabled,old){this.setAttribute("aria-disabled",disabled?"true":"false");this.style.pointerEvents=disabled?"none":"";if(disabled){this._oldTabIndex=this.tabIndex;this._setFocused(false);this.tabIndex=-1;this.blur()}else if(this._oldTabIndex!==undefined){this.tabIndex=this._oldTabIndex}},_changedControlState:function(){if(this._controlStateChanged){this._controlStateChanged()}}};Polymer.IronButtonStateImpl={properties:{pressed:{type:Boolean,readOnly:true,value:false,reflectToAttribute:true,observer:"_pressedChanged"},toggles:{type:Boolean,value:false,reflectToAttribute:true},active:{type:Boolean,value:false,notify:true,reflectToAttribute:true},pointerDown:{type:Boolean,readOnly:true,value:false},receivedFocusFromKeyboard:{type:Boolean,readOnly:true},ariaActiveAttribute:{type:String,value:"aria-pressed",observer:"_ariaActiveAttributeChanged"}},listeners:{down:"_downHandler",up:"_upHandler",tap:"_tapHandler"},observers:["_detectKeyboardFocus(focused)","_activeChanged(active, ariaActiveAttribute)"],keyBindings:{"enter:keydown":"_asyncClick","space:keydown":"_spaceKeyDownHandler","space:keyup":"_spaceKeyUpHandler"},_mouseEventRe:/^mouse/,_tapHandler:function(){if(this.toggles){this._userActivate(!this.active)}else{this.active=false}},_detectKeyboardFocus:function(focused){this._setReceivedFocusFromKeyboard(!this.pointerDown&&focused)},_userActivate:function(active){if(this.active!==active){this.active=active;this.fire("change")}},_downHandler:function(event){this._setPointerDown(true);this._setPressed(true);this._setReceivedFocusFromKeyboard(false)},_upHandler:function(){this._setPointerDown(false);this._setPressed(false)},_spaceKeyDownHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;keyboardEvent.preventDefault();keyboardEvent.stopImmediatePropagation();this._setPressed(true)},_spaceKeyUpHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;if(this.pressed){this._asyncClick()}this._setPressed(false)},_asyncClick:function(){this.async(function(){this.click()},1)},_pressedChanged:function(pressed){this._changedButtonState()},_ariaActiveAttributeChanged:function(value,oldValue){if(oldValue&&oldValue!=value&&this.hasAttribute(oldValue)){this.removeAttribute(oldValue)}},_activeChanged:function(active,ariaActiveAttribute){if(this.toggles){this.setAttribute(this.ariaActiveAttribute,active?"true":"false")}else{this.removeAttribute(this.ariaActiveAttribute)}this._changedButtonState()},_controlStateChanged:function(){if(this.disabled){this._setPressed(false)}else{this._changedButtonState()}},_changedButtonState:function(){if(this._buttonStateChanged){this._buttonStateChanged()}}};Polymer.IronButtonState=[Polymer.IronA11yKeysBehavior,Polymer.IronButtonStateImpl];(function(){var Utility={distance:function(x1,y1,x2,y2){var xDelta=x1-x2;var yDelta=y1-y2;return Math.sqrt(xDelta*xDelta+yDelta*yDelta)},now:window.performance&&window.performance.now?window.performance.now.bind(window.performance):Date.now};function ElementMetrics(element){this.element=element;this.width=this.boundingRect.width;this.height=this.boundingRect.height;this.size=Math.max(this.width,this.height)}ElementMetrics.prototype={get boundingRect(){return this.element.getBoundingClientRect()},furthestCornerDistanceFrom:function(x,y){var topLeft=Utility.distance(x,y,0,0);var topRight=Utility.distance(x,y,this.width,0);var bottomLeft=Utility.distance(x,y,0,this.height);var bottomRight=Utility.distance(x,y,this.width,this.height);return Math.max(topLeft,topRight,bottomLeft,bottomRight)}};function Ripple(element){this.element=element;this.color=window.getComputedStyle(element).color;this.wave=document.createElement("div");this.waveContainer=document.createElement("div");this.wave.style.backgroundColor=this.color;this.wave.classList.add("wave");this.waveContainer.classList.add("wave-container");Polymer.dom(this.waveContainer).appendChild(this.wave);this.resetInteractionState()}Ripple.MAX_RADIUS=300;Ripple.prototype={get recenters(){return this.element.recenters},get center(){return this.element.center},get mouseDownElapsed(){var elapsed;if(!this.mouseDownStart){return 0}elapsed=Utility.now()-this.mouseDownStart;if(this.mouseUpStart){elapsed-=this.mouseUpElapsed}return elapsed},get mouseUpElapsed(){return this.mouseUpStart?Utility.now()-this.mouseUpStart:0},get mouseDownElapsedSeconds(){return this.mouseDownElapsed/1e3},get mouseUpElapsedSeconds(){return this.mouseUpElapsed/1e3},get mouseInteractionSeconds(){return this.mouseDownElapsedSeconds+this.mouseUpElapsedSeconds},get initialOpacity(){return this.element.initialOpacity},get opacityDecayVelocity(){return this.element.opacityDecayVelocity},get radius(){var width2=this.containerMetrics.width*this.containerMetrics.width;var height2=this.containerMetrics.height*this.containerMetrics.height;var waveRadius=Math.min(Math.sqrt(width2+height2),Ripple.MAX_RADIUS)*1.1+5;var duration=1.1-.2*(waveRadius/Ripple.MAX_RADIUS);var timeNow=this.mouseInteractionSeconds/duration;var size=waveRadius*(1-Math.pow(80,-timeNow));return Math.abs(size)},get opacity(){if(!this.mouseUpStart){return this.initialOpacity}return Math.max(0,this.initialOpacity-this.mouseUpElapsedSeconds*this.opacityDecayVelocity)},get outerOpacity(){var outerOpacity=this.mouseUpElapsedSeconds*.3;var waveOpacity=this.opacity;return Math.max(0,Math.min(outerOpacity,waveOpacity))},get isOpacityFullyDecayed(){return this.opacity<.01&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isRestingAtMaxRadius(){return this.opacity>=this.initialOpacity&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isAnimationComplete(){return this.mouseUpStart?this.isOpacityFullyDecayed:this.isRestingAtMaxRadius},get translationFraction(){return Math.min(1,this.radius/this.containerMetrics.size*2/Math.sqrt(2))},get xNow(){if(this.xEnd){return this.xStart+this.translationFraction*(this.xEnd-this.xStart)}return this.xStart},get yNow(){if(this.yEnd){return this.yStart+this.translationFraction*(this.yEnd-this.yStart)}return this.yStart},get isMouseDown(){return this.mouseDownStart&&!this.mouseUpStart},resetInteractionState:function(){this.maxRadius=0;this.mouseDownStart=0;this.mouseUpStart=0;this.xStart=0;this.yStart=0;this.xEnd=0;this.yEnd=0;this.slideDistance=0;this.containerMetrics=new ElementMetrics(this.element)},draw:function(){var scale;var translateString;var dx;var dy;this.wave.style.opacity=this.opacity;scale=this.radius/(this.containerMetrics.size/2);dx=this.xNow-this.containerMetrics.width/2;dy=this.yNow-this.containerMetrics.height/2;this.waveContainer.style.webkitTransform="translate("+dx+"px, "+dy+"px)";this.waveContainer.style.transform="translate3d("+dx+"px, "+dy+"px, 0)";this.wave.style.webkitTransform="scale("+scale+","+scale+")";this.wave.style.transform="scale3d("+scale+","+scale+",1)"},downAction:function(event){var xCenter=this.containerMetrics.width/2;var yCenter=this.containerMetrics.height/2;this.resetInteractionState();this.mouseDownStart=Utility.now();if(this.center){this.xStart=xCenter;this.yStart=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}else{this.xStart=event?event.detail.x-this.containerMetrics.boundingRect.left:this.containerMetrics.width/2;this.yStart=event?event.detail.y-this.containerMetrics.boundingRect.top:this.containerMetrics.height/2}if(this.recenters){this.xEnd=xCenter;this.yEnd=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}this.maxRadius=this.containerMetrics.furthestCornerDistanceFrom(this.xStart,this.yStart);this.waveContainer.style.top=(this.containerMetrics.height-this.containerMetrics.size)/2+"px";this.waveContainer.style.left=(this.containerMetrics.width-this.containerMetrics.size)/2+"px";this.waveContainer.style.width=this.containerMetrics.size+"px";this.waveContainer.style.height=this.containerMetrics.size+"px"},upAction:function(event){if(!this.isMouseDown){return}this.mouseUpStart=Utility.now()},remove:function(){Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)}};Polymer({is:"paper-ripple",behaviors:[Polymer.IronA11yKeysBehavior],properties:{initialOpacity:{type:Number,value:.25},opacityDecayVelocity:{type:Number,value:.8},recenters:{type:Boolean,value:false},center:{type:Boolean,value:false},ripples:{type:Array,value:function(){return[]}},animating:{type:Boolean,readOnly:true,reflectToAttribute:true,value:false},holdDown:{type:Boolean,value:false,observer:"_holdDownChanged"},noink:{type:Boolean,value:false},_animating:{type:Boolean},_boundAnimate:{type:Function,value:function(){return this.animate.bind(this)}}},get target(){return this.keyEventTarget},keyBindings:{"enter:keydown":"_onEnterKeydown","space:keydown":"_onSpaceKeydown","space:keyup":"_onSpaceKeyup"},attached:function(){if(this.parentNode.nodeType==11){this.keyEventTarget=Polymer.dom(this).getOwnerRoot().host}else{this.keyEventTarget=this.parentNode}var keyEventTarget=this.keyEventTarget;this.listen(keyEventTarget,"up","uiUpAction");this.listen(keyEventTarget,"down","uiDownAction")},detached:function(){this.unlisten(this.keyEventTarget,"up","uiUpAction");this.unlisten(this.keyEventTarget,"down","uiDownAction");this.keyEventTarget=null},get shouldKeepAnimating(){for(var index=0;index<this.ripples.length;++index){if(!this.ripples[index].isAnimationComplete){return true}}return false},simulatedRipple:function(){this.downAction(null);this.async(function(){this.upAction()},1)},uiDownAction:function(event){if(!this.noink){this.downAction(event)}},downAction:function(event){if(this.holdDown&&this.ripples.length>0){return}var ripple=this.addRipple();ripple.downAction(event);if(!this._animating){this._animating=true;this.animate()}},uiUpAction:function(event){if(!this.noink){this.upAction(event)}},upAction:function(event){if(this.holdDown){return}this.ripples.forEach(function(ripple){ripple.upAction(event)});this._animating=true;this.animate()},onAnimationComplete:function(){this._animating=false;this.$.background.style.backgroundColor=null;this.fire("transitionend")},addRipple:function(){var ripple=new Ripple(this);Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);this.$.background.style.backgroundColor=ripple.color;this.ripples.push(ripple);this._setAnimating(true);return ripple},removeRipple:function(ripple){var rippleIndex=this.ripples.indexOf(ripple);if(rippleIndex<0){return}this.ripples.splice(rippleIndex,1);ripple.remove();if(!this.ripples.length){this._setAnimating(false)}},animate:function(){if(!this._animating){return}var index;var ripple;for(index=0;index<this.ripples.length;++index){ripple=this.ripples[index];ripple.draw();this.$.background.style.opacity=ripple.outerOpacity;if(ripple.isOpacityFullyDecayed&&!ripple.isRestingAtMaxRadius){this.removeRipple(ripple)}}if(!this.shouldKeepAnimating&&this.ripples.length===0){this.onAnimationComplete()}else{window.requestAnimationFrame(this._boundAnimate)}},_onEnterKeydown:function(){this.uiDownAction();this.async(this.uiUpAction,1)},_onSpaceKeydown:function(){this.uiDownAction()},_onSpaceKeyup:function(){this.uiUpAction()},_holdDownChanged:function(newVal,oldVal){if(oldVal===undefined){return}if(newVal){this.downAction()}else{this.upAction()}}})})();Polymer.PaperRippleBehavior={properties:{noink:{type:Boolean,observer:"_noinkChanged"},_rippleContainer:{type:Object}},_buttonStateChanged:function(){if(this.focused){this.ensureRipple()}},_downHandler:function(event){Polymer.IronButtonStateImpl._downHandler.call(this,event);if(this.pressed){this.ensureRipple(event)}},ensureRipple:function(optTriggeringEvent){if(!this.hasRipple()){this._ripple=this._createRipple();this._ripple.noink=this.noink;var rippleContainer=this._rippleContainer||this.root;if(rippleContainer){Polymer.dom(rippleContainer).appendChild(this._ripple)}if(optTriggeringEvent){var domContainer=Polymer.dom(this._rippleContainer||this);var target=Polymer.dom(optTriggeringEvent).rootTarget;if(domContainer.deepContains(target)){this._ripple.uiDownAction(optTriggeringEvent)}}}},getRipple:function(){this.ensureRipple();return this._ripple},hasRipple:function(){return Boolean(this._ripple)},_createRipple:function(){return document.createElement("paper-ripple")},_noinkChanged:function(noink){if(this.hasRipple()){this._ripple.noink=noink}}};Polymer.PaperButtonBehaviorImpl={properties:{elevation:{type:Number,reflectToAttribute:true,readOnly:true}},observers:["_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)","_computeKeyboardClass(receivedFocusFromKeyboard)"],hostAttributes:{role:"button",tabindex:"0",animated:true},_calculateElevation:function(){var e=1;if(this.disabled){e=0}else if(this.active||this.pressed){e=4}else if(this.receivedFocusFromKeyboard){e=3}this._setElevation(e)},_computeKeyboardClass:function(receivedFocusFromKeyboard){this.toggleClass("keyboard-focus",receivedFocusFromKeyboard)},_spaceKeyDownHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this,event);if(this.hasRipple()&&this.getRipple().ripples.length<1){this._ripple.uiDownAction()}},_spaceKeyUpHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this,event);if(this.hasRipple()){this._ripple.uiUpAction()}}};Polymer.PaperButtonBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperButtonBehaviorImpl];Polymer({is:"paper-button",behaviors:[Polymer.PaperButtonBehavior],properties:{raised:{type:Boolean,reflectToAttribute:true,value:false,observer:"_calculateElevation"}},_calculateElevation:function(){if(!this.raised){this._setElevation(0)}else{Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this)}}});Polymer({is:"paper-icon-button-light","extends":"button",behaviors:[Polymer.PaperRippleBehavior],listeners:{down:"_rippleDown",up:"_rippleUp",focus:"_rippleDown",blur:"_rippleUp"},_rippleDown:function(){this.getRipple().downAction()},_rippleUp:function(){this.getRipple().upAction()},ensureRipple:function(var_args){var lastRipple=this._ripple;Polymer.PaperRippleBehavior.ensureRipple.apply(this,arguments);if(this._ripple&&this._ripple!==lastRipple){this._ripple.center=true;this._ripple.classList.add("circle")}}});Polymer.IronRangeBehavior={properties:{value:{type:Number,value:0,notify:true,reflectToAttribute:true},min:{type:Number,value:0,notify:true},max:{type:Number,value:100,notify:true},step:{type:Number,value:1,notify:true},ratio:{type:Number,value:0,readOnly:true,notify:true}},observers:["_update(value, min, max, step)"],_calcRatio:function(value){return(this._clampValue(value)-this.min)/(this.max-this.min)},_clampValue:function(value){return Math.min(this.max,Math.max(this.min,this._calcStep(value)))},_calcStep:function(value){value=parseFloat(value);if(!this.step){return value}var numSteps=Math.round((value-this.min)/this.step);if(this.step<1){return numSteps/(1/this.step)+this.min}else{return numSteps*this.step+this.min}},_validateValue:function(){var v=this._clampValue(this.value);this.value=this.oldValue=isNaN(v)?this.oldValue:v;return this.value!==v},_update:function(){this._validateValue();this._setRatio(this._calcRatio(this.value)*100)}};Polymer({is:"paper-progress",behaviors:[Polymer.IronRangeBehavior],properties:{secondaryProgress:{type:Number,value:0},secondaryRatio:{type:Number,value:0,readOnly:true},indeterminate:{type:Boolean,value:false,observer:"_toggleIndeterminate"},disabled:{type:Boolean,value:false,reflectToAttribute:true,observer:"_disabledChanged"}},observers:["_progressChanged(secondaryProgress, value, min, max)"],hostAttributes:{role:"progressbar"},_toggleIndeterminate:function(indeterminate){this.toggleClass("indeterminate",indeterminate,this.$.primaryProgress)},_transformProgress:function(progress,ratio){var transform="scaleX("+ratio/100+")";progress.style.transform=progress.style.webkitTransform=transform},_mainRatioChanged:function(ratio){this._transformProgress(this.$.primaryProgress,ratio)},_progressChanged:function(secondaryProgress,value,min,max){secondaryProgress=this._clampValue(secondaryProgress);value=this._clampValue(value);var secondaryRatio=this._calcRatio(secondaryProgress)*100;var mainRatio=this._calcRatio(value)*100;this._setSecondaryRatio(secondaryRatio);this._transformProgress(this.$.secondaryProgress,secondaryRatio);this._transformProgress(this.$.primaryProgress,mainRatio);this.secondaryProgress=secondaryProgress;this.setAttribute("aria-valuenow",value);this.setAttribute("aria-valuemin",min);this.setAttribute("aria-valuemax",max)},_disabledChanged:function(disabled){this.setAttribute("aria-disabled",disabled?"true":"false")},_hideSecondaryProgress:function(secondaryRatio){return secondaryRatio===0}});Polymer({is:"iron-iconset-svg",properties:{name:{type:String,observer:"_nameChanged"},size:{type:Number,value:24}},attached:function(){this.style.display="none"},getIconNames:function(){this._icons=this._createIconMap();return Object.keys(this._icons).map(function(n){return this.name+":"+n},this)},applyIcon:function(element,iconName){element=element.root||element;this.removeIcon(element);var svg=this._cloneIcon(iconName);if(svg){var pde=Polymer.dom(element);pde.insertBefore(svg,pde.childNodes[0]);return element._svgIcon=svg}return null},removeIcon:function(element){if(element._svgIcon){Polymer.dom(element).removeChild(element._svgIcon);element._svgIcon=null}},_nameChanged:function(){new Polymer.IronMeta({type:"iconset",key:this.name,value:this});this.async(function(){this.fire("iron-iconset-added",this,{node:window})})},_createIconMap:function(){var icons=Object.create(null);Polymer.dom(this).querySelectorAll("[id]").forEach(function(icon){icons[icon.id]=icon});return icons},_cloneIcon:function(id){this._icons=this._icons||this._createIconMap();return this._prepareSvgClone(this._icons[id],this.size)},_prepareSvgClone:function(sourceSvg,size){if(sourceSvg){var content=sourceSvg.cloneNode(true),svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),viewBox=content.getAttribute("viewBox")||"0 0 "+size+" "+size;svg.setAttribute("viewBox",viewBox);svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.cssText="pointer-events: none; display: block; width: 100%; height: 100%;";svg.appendChild(content).removeAttribute("id");return svg}return null}});
 // 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.
-cr.define('downloads', function() {
-  var Item = Polymer({
-    is: 'downloads-item',
-    properties: {
-      data: {
-        type: Object
-      },
-      completelyOnDisk_: {
-        computed: 'computeCompletelyOnDisk_(' + 'data.state, data.file_externally_removed)',
-        type: Boolean,
-        value: true
-      },
-      controlledBy_: {
-        computed: 'computeControlledBy_(data.by_ext_id, data.by_ext_name)',
-        type: String,
-        value: ''
-      },
-      isActive_: {
-        computed: 'computeIsActive_(' + 'data.state, data.file_externally_removed)',
-        type: Boolean,
-        value: true
-      },
-      isDangerous_: {
-        computed: 'computeIsDangerous_(data.state)',
-        type: Boolean,
-        value: false
-      },
-      isMalware_: {
-        computed: 'computeIsMalware_(isDangerous_, data.danger_type)',
-        type: Boolean,
-        value: false
-      },
-      isInProgress_: {
-        computed: 'computeIsInProgress_(data.state)',
-        type: Boolean,
-        value: false
-      },
-      pauseOrResumeText_: {
-        computed: 'computePauseOrResumeText_(isInProgress_, data.resume)',
-        type: String
-      },
-      showCancel_: {
-        computed: 'computeShowCancel_(data.state)',
-        type: Boolean,
-        value: false
-      },
-      showProgress_: {
-        computed: 'computeShowProgress_(showCancel_, data.percent)',
-        type: Boolean,
-        value: false
-      }
-    },
-    observers: [ 'observeControlledBy_(controlledBy_)', 'observeIsDangerous_(isDangerous_, data)' ],
-    ready: function() {
-      this.content = this.$.content;
-    },
-    computeClass_: function() {
-      var classes = [];
-      if (this.isActive_) classes.push('is-active');
-      if (this.isDangerous_) classes.push('dangerous');
-      if (this.showProgress_) classes.push('show-progress');
-      return classes.join(' ');
-    },
-    computeCompletelyOnDisk_: function() {
-      return this.data.state == downloads.States.COMPLETE && !this.data.file_externally_removed;
-    },
-    computeControlledBy_: function() {
-      if (!this.data.by_ext_id || !this.data.by_ext_name) return '';
-      var url = 'chrome://extensions#' + this.data.by_ext_id;
-      var name = this.data.by_ext_name;
-      return loadTimeData.getStringF('controlledByUrl', url, name);
-    },
-    computeDangerIcon_: function() {
-      if (!this.isDangerous_) return '';
-      switch (this.data.danger_type) {
-       case downloads.DangerType.DANGEROUS_CONTENT:
-       case downloads.DangerType.DANGEROUS_HOST:
-       case downloads.DangerType.DANGEROUS_URL:
-       case downloads.DangerType.POTENTIALLY_UNWANTED:
-       case downloads.DangerType.UNCOMMON_CONTENT:
-        return 'downloads:remove-circle';
-
-       default:
-        return 'cr:warning';
-      }
-    },
-    computeDate_: function() {
-      assert(typeof this.data.hideDate == 'boolean');
-      if (this.data.hideDate) return '';
-      return assert(this.data.since_string || this.data.date_string);
-    },
-    computeDescription_: function() {
-      var data = this.data;
-      switch (data.state) {
-       case downloads.States.DANGEROUS:
-        var fileName = data.file_name;
-        switch (data.danger_type) {
-         case downloads.DangerType.DANGEROUS_FILE:
-          return loadTimeData.getString('dangerFileDesc');
-
-         case downloads.DangerType.DANGEROUS_URL:
-         case downloads.DangerType.DANGEROUS_CONTENT:
-         case downloads.DangerType.DANGEROUS_HOST:
-          return loadTimeData.getString('dangerDownloadDesc');
-
-         case downloads.DangerType.UNCOMMON_CONTENT:
-          return loadTimeData.getString('dangerUncommonDesc');
-
-         case downloads.DangerType.POTENTIALLY_UNWANTED:
-          return loadTimeData.getString('dangerSettingsDesc');
-        }
-        break;
-
-       case downloads.States.IN_PROGRESS:
-       case downloads.States.PAUSED:
-        return data.progress_status_text;
-      }
-      return '';
-    },
-    computeIsActive_: function() {
-      return this.data.state != downloads.States.CANCELLED && this.data.state != downloads.States.INTERRUPTED && !this.data.file_externally_removed;
-    },
-    computeIsDangerous_: function() {
-      return this.data.state == downloads.States.DANGEROUS;
-    },
-    computeIsInProgress_: function() {
-      return this.data.state == downloads.States.IN_PROGRESS;
-    },
-    computeIsMalware_: function() {
-      return this.isDangerous_ && (this.data.danger_type == downloads.DangerType.DANGEROUS_CONTENT || this.data.danger_type == downloads.DangerType.DANGEROUS_HOST || this.data.danger_type == downloads.DangerType.DANGEROUS_URL || this.data.danger_type == downloads.DangerType.POTENTIALLY_UNWANTED);
-    },
-    computePauseOrResumeText_: function() {
-      if (this.isInProgress_) return loadTimeData.getString('controlPause');
-      if (this.data.resume) return loadTimeData.getString('controlResume');
-      return '';
-    },
-    computeRemoveStyle_: function() {
-      var canDelete = loadTimeData.getBoolean('allowDeletingHistory');
-      var hideRemove = this.isDangerous_ || this.showCancel_ || !canDelete;
-      return hideRemove ? 'visibility: hidden' : '';
-    },
-    computeShowCancel_: function() {
-      return this.data.state == downloads.States.IN_PROGRESS || this.data.state == downloads.States.PAUSED;
-    },
-    computeShowProgress_: function() {
-      return this.showCancel_ && this.data.percent >= -1;
-    },
-    computeTag_: function() {
-      switch (this.data.state) {
-       case downloads.States.CANCELLED:
-        return loadTimeData.getString('statusCancelled');
-
-       case downloads.States.INTERRUPTED:
-        return this.data.last_reason_text;
-
-       case downloads.States.COMPLETE:
-        return this.data.file_externally_removed ? loadTimeData.getString('statusRemoved') : '';
-      }
-      return '';
-    },
-    isIndeterminate_: function() {
-      return this.data.percent == -1;
-    },
-    observeControlledBy_: function() {
-      this.$['controlled-by'].innerHTML = this.controlledBy_;
-    },
-    observeIsDangerous_: function() {
-      if (!this.data) return;
-      if (this.isDangerous_) {
-        this.$.url.removeAttribute('href');
-      } else {
-        this.$.url.href = assert(this.data.url);
-        var filePath = encodeURIComponent(this.data.file_path);
-        var scaleFactor = '?scale=' + window.devicePixelRatio + 'x';
-        this.$['file-icon'].src = 'chrome://fileicon/' + filePath + scaleFactor;
-      }
-    },
-    onCancelTap_: function() {
-      downloads.ActionService.getInstance().cancel(this.data.id);
-    },
-    onDiscardDangerousTap_: function() {
-      downloads.ActionService.getInstance().discardDangerous(this.data.id);
-    },
-    onDragStart_: function(e) {
-      e.preventDefault();
-      downloads.ActionService.getInstance().drag(this.data.id);
-    },
-    onFileLinkTap_: function(e) {
-      e.preventDefault();
-      downloads.ActionService.getInstance().openFile(this.data.id);
-    },
-    onPauseOrResumeTap_: function() {
-      if (this.isInProgress_) downloads.ActionService.getInstance().pause(this.data.id); else downloads.ActionService.getInstance().resume(this.data.id);
-    },
-    onRemoveTap_: function() {
-      downloads.ActionService.getInstance().remove(this.data.id);
-    },
-    onRetryTap_: function() {
-      downloads.ActionService.getInstance().download(this.data.url);
-    },
-    onSaveDangerousTap_: function() {
-      downloads.ActionService.getInstance().saveDangerous(this.data.id);
-    },
-    onShowTap_: function() {
-      downloads.ActionService.getInstance().show(this.data.id);
-    }
-  });
-  return {
-    Item: Item
-  };
-});
-
-Polymer.PaperItemBehaviorImpl = {
-  hostAttributes: {
-    role: 'option',
-    tabindex: '0'
-  }
-};
-
-Polymer.PaperItemBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperItemBehaviorImpl ];
-
-Polymer({
-  is: 'paper-item',
-  behaviors: [ Polymer.PaperItemBehavior ]
-});
-
-Polymer.IronSelection = function(selectCallback) {
-  this.selection = [];
-  this.selectCallback = selectCallback;
-};
-
-Polymer.IronSelection.prototype = {
-  get: function() {
-    return this.multi ? this.selection.slice() : this.selection[0];
-  },
-  clear: function(excludes) {
-    this.selection.slice().forEach(function(item) {
-      if (!excludes || excludes.indexOf(item) < 0) {
-        this.setItemSelected(item, false);
-      }
-    }, this);
-  },
-  isSelected: function(item) {
-    return this.selection.indexOf(item) >= 0;
-  },
-  setItemSelected: function(item, isSelected) {
-    if (item != null) {
-      if (isSelected !== this.isSelected(item)) {
-        if (isSelected) {
-          this.selection.push(item);
-        } else {
-          var i = this.selection.indexOf(item);
-          if (i >= 0) {
-            this.selection.splice(i, 1);
-          }
-        }
-        if (this.selectCallback) {
-          this.selectCallback(item, isSelected);
-        }
-      }
-    }
-  },
-  select: function(item) {
-    if (this.multi) {
-      this.toggle(item);
-    } else if (this.get() !== item) {
-      this.setItemSelected(this.get(), false);
-      this.setItemSelected(item, true);
-    }
-  },
-  toggle: function(item) {
-    this.setItemSelected(item, !this.isSelected(item));
-  }
-};
-
-Polymer.IronSelectableBehavior = {
-  properties: {
-    attrForSelected: {
-      type: String,
-      value: null
-    },
-    selected: {
-      type: String,
-      notify: true
-    },
-    selectedItem: {
-      type: Object,
-      readOnly: true,
-      notify: true
-    },
-    activateEvent: {
-      type: String,
-      value: 'tap',
-      observer: '_activateEventChanged'
-    },
-    selectable: String,
-    selectedClass: {
-      type: String,
-      value: 'iron-selected'
-    },
-    selectedAttribute: {
-      type: String,
-      value: null
-    },
-    fallbackSelection: {
-      type: String,
-      value: null
-    },
-    items: {
-      type: Array,
-      readOnly: true,
-      notify: true,
-      value: function() {
-        return [];
-      }
-    },
-    _excludedLocalNames: {
-      type: Object,
-      value: function() {
-        return {
-          template: 1
-        };
-      }
-    }
-  },
-  observers: [ '_updateAttrForSelected(attrForSelected)', '_updateSelected(selected)', '_checkFallback(fallbackSelection)' ],
-  created: function() {
-    this._bindFilterItem = this._filterItem.bind(this);
-    this._selection = new Polymer.IronSelection(this._applySelection.bind(this));
-  },
-  attached: function() {
-    this._observer = this._observeItems(this);
-    this._updateItems();
-    if (!this._shouldUpdateSelection) {
-      this._updateSelected();
-    }
-    this._addListener(this.activateEvent);
-  },
-  detached: function() {
-    if (this._observer) {
-      Polymer.dom(this).unobserveNodes(this._observer);
-    }
-    this._removeListener(this.activateEvent);
-  },
-  indexOf: function(item) {
-    return this.items.indexOf(item);
-  },
-  select: function(value) {
-    this.selected = value;
-  },
-  selectPrevious: function() {
-    var length = this.items.length;
-    var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % length;
-    this.selected = this._indexToValue(index);
-  },
-  selectNext: function() {
-    var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.length;
-    this.selected = this._indexToValue(index);
-  },
-  selectIndex: function(index) {
-    this.select(this._indexToValue(index));
-  },
-  forceSynchronousItemUpdate: function() {
-    this._updateItems();
-  },
-  get _shouldUpdateSelection() {
-    return this.selected != null;
-  },
-  _checkFallback: function() {
-    if (this._shouldUpdateSelection) {
-      this._updateSelected();
-    }
-  },
-  _addListener: function(eventName) {
-    this.listen(this, eventName, '_activateHandler');
-  },
-  _removeListener: function(eventName) {
-    this.unlisten(this, eventName, '_activateHandler');
-  },
-  _activateEventChanged: function(eventName, old) {
-    this._removeListener(old);
-    this._addListener(eventName);
-  },
-  _updateItems: function() {
-    var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
-    nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
-    this._setItems(nodes);
-  },
-  _updateAttrForSelected: function() {
-    if (this._shouldUpdateSelection) {
-      this.selected = this._indexToValue(this.indexOf(this.selectedItem));
-    }
-  },
-  _updateSelected: function() {
-    this._selectSelected(this.selected);
-  },
-  _selectSelected: function(selected) {
-    this._selection.select(this._valueToItem(this.selected));
-    if (this.fallbackSelection && this.items.length && this._selection.get() === undefined) {
-      this.selected = this.fallbackSelection;
-    }
-  },
-  _filterItem: function(node) {
-    return !this._excludedLocalNames[node.localName];
-  },
-  _valueToItem: function(value) {
-    return value == null ? null : this.items[this._valueToIndex(value)];
-  },
-  _valueToIndex: function(value) {
-    if (this.attrForSelected) {
-      for (var i = 0, item; item = this.items[i]; i++) {
-        if (this._valueForItem(item) == value) {
-          return i;
-        }
-      }
-    } else {
-      return Number(value);
-    }
-  },
-  _indexToValue: function(index) {
-    if (this.attrForSelected) {
-      var item = this.items[index];
-      if (item) {
-        return this._valueForItem(item);
-      }
-    } else {
-      return index;
-    }
-  },
-  _valueForItem: function(item) {
-    var propValue = item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];
-    return propValue != undefined ? propValue : item.getAttribute(this.attrForSelected);
-  },
-  _applySelection: function(item, isSelected) {
-    if (this.selectedClass) {
-      this.toggleClass(this.selectedClass, isSelected, item);
-    }
-    if (this.selectedAttribute) {
-      this.toggleAttribute(this.selectedAttribute, isSelected, item);
-    }
-    this._selectionChange();
-    this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {
-      item: item
-    });
-  },
-  _selectionChange: function() {
-    this._setSelectedItem(this._selection.get());
-  },
-  _observeItems: function(node) {
-    return Polymer.dom(node).observeNodes(function(mutation) {
-      this._updateItems();
-      if (this._shouldUpdateSelection) {
-        this._updateSelected();
-      }
-      this.fire('iron-items-changed', mutation, {
-        bubbles: false,
-        cancelable: false
-      });
-    });
-  },
-  _activateHandler: function(e) {
-    var t = e.target;
-    var items = this.items;
-    while (t && t != this) {
-      var i = items.indexOf(t);
-      if (i >= 0) {
-        var value = this._indexToValue(i);
-        this._itemActivate(value, t);
-        return;
-      }
-      t = t.parentNode;
-    }
-  },
-  _itemActivate: function(value, item) {
-    if (!this.fire('iron-activate', {
-      selected: value,
-      item: item
-    }, {
-      cancelable: true
-    }).defaultPrevented) {
-      this.select(value);
-    }
-  }
-};
-
-Polymer.IronMultiSelectableBehaviorImpl = {
-  properties: {
-    multi: {
-      type: Boolean,
-      value: false,
-      observer: 'multiChanged'
-    },
-    selectedValues: {
-      type: Array,
-      notify: true
-    },
-    selectedItems: {
-      type: Array,
-      readOnly: true,
-      notify: true
-    }
-  },
-  observers: [ '_updateSelected(selectedValues.splices)' ],
-  select: function(value) {
-    if (this.multi) {
-      if (this.selectedValues) {
-        this._toggleSelected(value);
-      } else {
-        this.selectedValues = [ value ];
-      }
-    } else {
-      this.selected = value;
-    }
-  },
-  multiChanged: function(multi) {
-    this._selection.multi = multi;
-  },
-  get _shouldUpdateSelection() {
-    return this.selected != null || this.selectedValues != null && this.selectedValues.length;
-  },
-  _updateAttrForSelected: function() {
-    if (!this.multi) {
-      Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
-    } else if (this._shouldUpdateSelection) {
-      this.selectedValues = this.selectedItems.map(function(selectedItem) {
-        return this._indexToValue(this.indexOf(selectedItem));
-      }, this).filter(function(unfilteredValue) {
-        return unfilteredValue != null;
-      }, this);
-    }
-  },
-  _updateSelected: function() {
-    if (this.multi) {
-      this._selectMulti(this.selectedValues);
-    } else {
-      this._selectSelected(this.selected);
-    }
-  },
-  _selectMulti: function(values) {
-    if (values) {
-      var selectedItems = this._valuesToItems(values);
-      this._selection.clear(selectedItems);
-      for (var i = 0; i < selectedItems.length; i++) {
-        this._selection.setItemSelected(selectedItems[i], true);
-      }
-      if (this.fallbackSelection && this.items.length && !this._selection.get().length) {
-        var fallback = this._valueToItem(this.fallbackSelection);
-        if (fallback) {
-          this.selectedValues = [ this.fallbackSelection ];
-        }
-      }
-    } else {
-      this._selection.clear();
-    }
-  },
-  _selectionChange: function() {
-    var s = this._selection.get();
-    if (this.multi) {
-      this._setSelectedItems(s);
-    } else {
-      this._setSelectedItems([ s ]);
-      this._setSelectedItem(s);
-    }
-  },
-  _toggleSelected: function(value) {
-    var i = this.selectedValues.indexOf(value);
-    var unselected = i < 0;
-    if (unselected) {
-      this.push('selectedValues', value);
-    } else {
-      this.splice('selectedValues', i, 1);
-    }
-  },
-  _valuesToItems: function(values) {
-    return values == null ? null : values.map(function(value) {
-      return this._valueToItem(value);
-    }, this);
-  }
-};
-
-Polymer.IronMultiSelectableBehavior = [ Polymer.IronSelectableBehavior, Polymer.IronMultiSelectableBehaviorImpl ];
-
-Polymer.IronMenuBehaviorImpl = {
-  properties: {
-    focusedItem: {
-      observer: '_focusedItemChanged',
-      readOnly: true,
-      type: Object
-    },
-    attrForItemTitle: {
-      type: String
-    }
-  },
-  hostAttributes: {
-    role: 'menu',
-    tabindex: '0'
-  },
-  observers: [ '_updateMultiselectable(multi)' ],
-  listeners: {
-    focus: '_onFocus',
-    keydown: '_onKeydown',
-    'iron-items-changed': '_onIronItemsChanged'
-  },
-  keyBindings: {
-    up: '_onUpKey',
-    down: '_onDownKey',
-    esc: '_onEscKey',
-    'shift+tab:keydown': '_onShiftTabDown'
-  },
-  attached: function() {
-    this._resetTabindices();
-  },
-  select: function(value) {
-    if (this._defaultFocusAsync) {
-      this.cancelAsync(this._defaultFocusAsync);
-      this._defaultFocusAsync = null;
-    }
-    var item = this._valueToItem(value);
-    if (item && item.hasAttribute('disabled')) return;
-    this._setFocusedItem(item);
-    Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
-  },
-  _resetTabindices: function() {
-    var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
-    this.items.forEach(function(item) {
-      item.setAttribute('tabindex', item === selectedItem ? '0' : '-1');
-    }, this);
-  },
-  _updateMultiselectable: function(multi) {
-    if (multi) {
-      this.setAttribute('aria-multiselectable', 'true');
-    } else {
-      this.removeAttribute('aria-multiselectable');
-    }
-  },
-  _focusWithKeyboardEvent: function(event) {
-    for (var i = 0, item; item = this.items[i]; i++) {
-      var attr = this.attrForItemTitle || 'textContent';
-      var title = item[attr] || item.getAttribute(attr);
-      if (!item.hasAttribute('disabled') && title && title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) {
-        this._setFocusedItem(item);
-        break;
-      }
-    }
-  },
-  _focusPrevious: function() {
-    var length = this.items.length;
-    var curFocusIndex = Number(this.indexOf(this.focusedItem));
-    for (var i = 1; i < length + 1; i++) {
-      var item = this.items[(curFocusIndex - i + length) % length];
-      if (!item.hasAttribute('disabled')) {
-        var owner = Polymer.dom(item).getOwnerRoot() || document;
-        this._setFocusedItem(item);
-        if (Polymer.dom(owner).activeElement == item) {
-          return;
-        }
-      }
-    }
-  },
-  _focusNext: function() {
-    var length = this.items.length;
-    var curFocusIndex = Number(this.indexOf(this.focusedItem));
-    for (var i = 1; i < length + 1; i++) {
-      var item = this.items[(curFocusIndex + i) % length];
-      if (!item.hasAttribute('disabled')) {
-        var owner = Polymer.dom(item).getOwnerRoot() || document;
-        this._setFocusedItem(item);
-        if (Polymer.dom(owner).activeElement == item) {
-          return;
-        }
-      }
-    }
-  },
-  _applySelection: function(item, isSelected) {
-    if (isSelected) {
-      item.setAttribute('aria-selected', 'true');
-    } else {
-      item.removeAttribute('aria-selected');
-    }
-    Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
-  },
-  _focusedItemChanged: function(focusedItem, old) {
-    old && old.setAttribute('tabindex', '-1');
-    if (focusedItem) {
-      focusedItem.setAttribute('tabindex', '0');
-      focusedItem.focus();
-    }
-  },
-  _onIronItemsChanged: function(event) {
-    if (event.detail.addedNodes.length) {
-      this._resetTabindices();
-    }
-  },
-  _onShiftTabDown: function(event) {
-    var oldTabIndex = this.getAttribute('tabindex');
-    Polymer.IronMenuBehaviorImpl._shiftTabPressed = true;
-    this._setFocusedItem(null);
-    this.setAttribute('tabindex', '-1');
-    this.async(function() {
-      this.setAttribute('tabindex', oldTabIndex);
-      Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
-    }, 1);
-  },
-  _onFocus: function(event) {
-    if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
-      return;
-    }
-    var rootTarget = Polymer.dom(event).rootTarget;
-    if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
-      return;
-    }
-    this._defaultFocusAsync = this.async(function() {
-      var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
-      this._setFocusedItem(null);
-      if (selectedItem) {
-        this._setFocusedItem(selectedItem);
-      } else if (this.items[0]) {
-        this._focusNext();
-      }
-    });
-  },
-  _onUpKey: function(event) {
-    this._focusPrevious();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onDownKey: function(event) {
-    this._focusNext();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onEscKey: function(event) {
-    this.focusedItem.blur();
-  },
-  _onKeydown: function(event) {
-    if (!this.keyboardEventMatchesKeys(event, 'up down esc')) {
-      this._focusWithKeyboardEvent(event);
-    }
-    event.stopPropagation();
-  },
-  _activateHandler: function(event) {
-    Polymer.IronSelectableBehavior._activateHandler.call(this, event);
-    event.stopPropagation();
-  }
-};
-
-Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
-
-Polymer.IronMenuBehavior = [ Polymer.IronMultiSelectableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronMenuBehaviorImpl ];
-
-(function() {
-  Polymer({
-    is: 'paper-menu',
-    behaviors: [ Polymer.IronMenuBehavior ]
-  });
-})();
-
-Polymer.IronFitBehavior = {
-  properties: {
-    sizingTarget: {
-      type: Object,
-      value: function() {
-        return this;
-      }
-    },
-    fitInto: {
-      type: Object,
-      value: window
-    },
-    noOverlap: {
-      type: Boolean
-    },
-    positionTarget: {
-      type: Element
-    },
-    horizontalAlign: {
-      type: String
-    },
-    verticalAlign: {
-      type: String
-    },
-    dynamicAlign: {
-      type: Boolean
-    },
-    horizontalOffset: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    verticalOffset: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    autoFitOnAttach: {
-      type: Boolean,
-      value: false
-    },
-    _fitInfo: {
-      type: Object
-    }
-  },
-  get _fitWidth() {
-    var fitWidth;
-    if (this.fitInto === window) {
-      fitWidth = this.fitInto.innerWidth;
-    } else {
-      fitWidth = this.fitInto.getBoundingClientRect().width;
-    }
-    return fitWidth;
-  },
-  get _fitHeight() {
-    var fitHeight;
-    if (this.fitInto === window) {
-      fitHeight = this.fitInto.innerHeight;
-    } else {
-      fitHeight = this.fitInto.getBoundingClientRect().height;
-    }
-    return fitHeight;
-  },
-  get _fitLeft() {
-    var fitLeft;
-    if (this.fitInto === window) {
-      fitLeft = 0;
-    } else {
-      fitLeft = this.fitInto.getBoundingClientRect().left;
-    }
-    return fitLeft;
-  },
-  get _fitTop() {
-    var fitTop;
-    if (this.fitInto === window) {
-      fitTop = 0;
-    } else {
-      fitTop = this.fitInto.getBoundingClientRect().top;
-    }
-    return fitTop;
-  },
-  get _defaultPositionTarget() {
-    var parent = Polymer.dom(this).parentNode;
-    if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-      parent = parent.host;
-    }
-    return parent;
-  },
-  get _localeHorizontalAlign() {
-    if (this._isRTL) {
-      if (this.horizontalAlign === 'right') {
-        return 'left';
-      }
-      if (this.horizontalAlign === 'left') {
-        return 'right';
-      }
-    }
-    return this.horizontalAlign;
-  },
-  attached: function() {
-    this._isRTL = window.getComputedStyle(this).direction == 'rtl';
-    this.positionTarget = this.positionTarget || this._defaultPositionTarget;
-    if (this.autoFitOnAttach) {
-      if (window.getComputedStyle(this).display === 'none') {
-        setTimeout(function() {
-          this.fit();
-        }.bind(this));
-      } else {
-        this.fit();
-      }
-    }
-  },
-  fit: function() {
-    this.position();
-    this.constrain();
-    this.center();
-  },
-  _discoverInfo: function() {
-    if (this._fitInfo) {
-      return;
-    }
-    var target = window.getComputedStyle(this);
-    var sizer = window.getComputedStyle(this.sizingTarget);
-    this._fitInfo = {
-      inlineStyle: {
-        top: this.style.top || '',
-        left: this.style.left || '',
-        position: this.style.position || ''
-      },
-      sizerInlineStyle: {
-        maxWidth: this.sizingTarget.style.maxWidth || '',
-        maxHeight: this.sizingTarget.style.maxHeight || '',
-        boxSizing: this.sizingTarget.style.boxSizing || ''
-      },
-      positionedBy: {
-        vertically: target.top !== 'auto' ? 'top' : target.bottom !== 'auto' ? 'bottom' : null,
-        horizontally: target.left !== 'auto' ? 'left' : target.right !== 'auto' ? 'right' : null
-      },
-      sizedBy: {
-        height: sizer.maxHeight !== 'none',
-        width: sizer.maxWidth !== 'none',
-        minWidth: parseInt(sizer.minWidth, 10) || 0,
-        minHeight: parseInt(sizer.minHeight, 10) || 0
-      },
-      margin: {
-        top: parseInt(target.marginTop, 10) || 0,
-        right: parseInt(target.marginRight, 10) || 0,
-        bottom: parseInt(target.marginBottom, 10) || 0,
-        left: parseInt(target.marginLeft, 10) || 0
-      }
-    };
-    if (this.verticalOffset) {
-      this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffset;
-      this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
-      this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || '';
-      this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px';
-    }
-    if (this.horizontalOffset) {
-      this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOffset;
-      this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || '';
-      this._fitInfo.inlineStyle.marginRight = this.style.marginRight || '';
-      this.style.marginLeft = this.style.marginRight = this.horizontalOffset + 'px';
-    }
-  },
-  resetFit: function() {
-    var info = this._fitInfo || {};
-    for (var property in info.sizerInlineStyle) {
-      this.sizingTarget.style[property] = info.sizerInlineStyle[property];
-    }
-    for (var property in info.inlineStyle) {
-      this.style[property] = info.inlineStyle[property];
-    }
-    this._fitInfo = null;
-  },
-  refit: function() {
-    var scrollLeft = this.sizingTarget.scrollLeft;
-    var scrollTop = this.sizingTarget.scrollTop;
-    this.resetFit();
-    this.fit();
-    this.sizingTarget.scrollLeft = scrollLeft;
-    this.sizingTarget.scrollTop = scrollTop;
-  },
-  position: function() {
-    if (!this.horizontalAlign && !this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    this.style.position = 'fixed';
-    this.sizingTarget.style.boxSizing = 'border-box';
-    this.style.left = '0px';
-    this.style.top = '0px';
-    var rect = this.getBoundingClientRect();
-    var positionRect = this.__getNormalizedRect(this.positionTarget);
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    var margin = this._fitInfo.margin;
-    var size = {
-      width: rect.width + margin.left + margin.right,
-      height: rect.height + margin.top + margin.bottom
-    };
-    var position = this.__getPosition(this._localeHorizontalAlign, this.verticalAlign, size, positionRect, fitRect);
-    var left = position.left + margin.left;
-    var top = position.top + margin.top;
-    var right = Math.min(fitRect.right - margin.right, left + rect.width);
-    var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
-    var minWidth = this._fitInfo.sizedBy.minWidth;
-    var minHeight = this._fitInfo.sizedBy.minHeight;
-    if (left < margin.left) {
-      left = margin.left;
-      if (right - left < minWidth) {
-        left = right - minWidth;
-      }
-    }
-    if (top < margin.top) {
-      top = margin.top;
-      if (bottom - top < minHeight) {
-        top = bottom - minHeight;
-      }
-    }
-    this.sizingTarget.style.maxWidth = right - left + 'px';
-    this.sizingTarget.style.maxHeight = bottom - top + 'px';
-    this.style.left = left - rect.left + 'px';
-    this.style.top = top - rect.top + 'px';
-  },
-  constrain: function() {
-    if (this.horizontalAlign || this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    var info = this._fitInfo;
-    if (!info.positionedBy.vertically) {
-      this.style.position = 'fixed';
-      this.style.top = '0px';
-    }
-    if (!info.positionedBy.horizontally) {
-      this.style.position = 'fixed';
-      this.style.left = '0px';
-    }
-    this.sizingTarget.style.boxSizing = 'border-box';
-    var rect = this.getBoundingClientRect();
-    if (!info.sizedBy.height) {
-      this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
-    }
-    if (!info.sizedBy.width) {
-      this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right', 'Width');
-    }
-  },
-  _sizeDimension: function(rect, positionedBy, start, end, extent) {
-    this.__sizeDimension(rect, positionedBy, start, end, extent);
-  },
-  __sizeDimension: function(rect, positionedBy, start, end, extent) {
-    var info = this._fitInfo;
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    var max = extent === 'Width' ? fitRect.width : fitRect.height;
-    var flip = positionedBy === end;
-    var offset = flip ? max - rect[end] : rect[start];
-    var margin = info.margin[flip ? start : end];
-    var offsetExtent = 'offset' + extent;
-    var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent];
-    this.sizingTarget.style['max' + extent] = max - margin - offset - sizingOffset + 'px';
-  },
-  center: function() {
-    if (this.horizontalAlign || this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    var positionedBy = this._fitInfo.positionedBy;
-    if (positionedBy.vertically && positionedBy.horizontally) {
-      return;
-    }
-    this.style.position = 'fixed';
-    if (!positionedBy.vertically) {
-      this.style.top = '0px';
-    }
-    if (!positionedBy.horizontally) {
-      this.style.left = '0px';
-    }
-    var rect = this.getBoundingClientRect();
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    if (!positionedBy.vertically) {
-      var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2;
-      this.style.top = top + 'px';
-    }
-    if (!positionedBy.horizontally) {
-      var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2;
-      this.style.left = left + 'px';
-    }
-  },
-  __getNormalizedRect: function(target) {
-    if (target === document.documentElement || target === window) {
-      return {
-        top: 0,
-        left: 0,
-        width: window.innerWidth,
-        height: window.innerHeight,
-        right: window.innerWidth,
-        bottom: window.innerHeight
-      };
-    }
-    return target.getBoundingClientRect();
-  },
-  __getCroppedArea: function(position, size, fitRect) {
-    var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom - (position.top + size.height));
-    var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right - (position.left + size.width));
-    return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size.height;
-  },
-  __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
-    var positions = [ {
-      verticalAlign: 'top',
-      horizontalAlign: 'left',
-      top: positionRect.top,
-      left: positionRect.left
-    }, {
-      verticalAlign: 'top',
-      horizontalAlign: 'right',
-      top: positionRect.top,
-      left: positionRect.right - size.width
-    }, {
-      verticalAlign: 'bottom',
-      horizontalAlign: 'left',
-      top: positionRect.bottom - size.height,
-      left: positionRect.left
-    }, {
-      verticalAlign: 'bottom',
-      horizontalAlign: 'right',
-      top: positionRect.bottom - size.height,
-      left: positionRect.right - size.width
-    } ];
-    if (this.noOverlap) {
-      for (var i = 0, l = positions.length; i < l; i++) {
-        var copy = {};
-        for (var key in positions[i]) {
-          copy[key] = positions[i][key];
-        }
-        positions.push(copy);
-      }
-      positions[0].top = positions[1].top += positionRect.height;
-      positions[2].top = positions[3].top -= positionRect.height;
-      positions[4].left = positions[6].left += positionRect.width;
-      positions[5].left = positions[7].left -= positionRect.width;
-    }
-    vAlign = vAlign === 'auto' ? null : vAlign;
-    hAlign = hAlign === 'auto' ? null : hAlign;
-    var position;
-    for (var i = 0; i < positions.length; i++) {
-      var pos = positions[i];
-      if (!this.dynamicAlign && !this.noOverlap && pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
-        position = pos;
-        break;
-      }
-      var alignOk = (!vAlign || pos.verticalAlign === vAlign) && (!hAlign || pos.horizontalAlign === hAlign);
-      if (!this.dynamicAlign && !alignOk) {
-        continue;
-      }
-      position = position || pos;
-      pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
-      var diff = pos.croppedArea - position.croppedArea;
-      if (diff < 0 || diff === 0 && alignOk) {
-        position = pos;
-      }
-      if (position.croppedArea === 0 && alignOk) {
-        break;
-      }
-    }
-    return position;
-  }
-};
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-overlay-backdrop',
-    properties: {
-      opened: {
-        reflectToAttribute: true,
-        type: Boolean,
-        value: false,
-        observer: '_openedChanged'
-      }
-    },
-    listeners: {
-      transitionend: '_onTransitionend'
-    },
-    created: function() {
-      this.__openedRaf = null;
-    },
-    attached: function() {
-      this.opened && this._openedChanged(this.opened);
-    },
-    prepare: function() {
-      if (this.opened && !this.parentNode) {
-        Polymer.dom(document.body).appendChild(this);
-      }
-    },
-    open: function() {
-      this.opened = true;
-    },
-    close: function() {
-      this.opened = false;
-    },
-    complete: function() {
-      if (!this.opened && this.parentNode === document.body) {
-        Polymer.dom(this.parentNode).removeChild(this);
-      }
-    },
-    _onTransitionend: function(event) {
-      if (event && event.target === this) {
-        this.complete();
-      }
-    },
-    _openedChanged: function(opened) {
-      if (opened) {
-        this.prepare();
-      } else {
-        var cs = window.getComputedStyle(this);
-        if (cs.transitionDuration === '0s' || cs.opacity == 0) {
-          this.complete();
-        }
-      }
-      if (!this.isAttached) {
-        return;
-      }
-      if (this.__openedRaf) {
-        window.cancelAnimationFrame(this.__openedRaf);
-        this.__openedRaf = null;
-      }
-      this.scrollTop = this.scrollTop;
-      this.__openedRaf = window.requestAnimationFrame(function() {
-        this.__openedRaf = null;
-        this.toggleClass('opened', this.opened);
-      }.bind(this));
-    }
-  });
-})();
-
-Polymer.IronOverlayManagerClass = function() {
-  this._overlays = [];
-  this._minimumZ = 101;
-  this._backdropElement = null;
-  Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this));
-  document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
-  document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
-};
-
-Polymer.IronOverlayManagerClass.prototype = {
-  constructor: Polymer.IronOverlayManagerClass,
-  get backdropElement() {
-    if (!this._backdropElement) {
-      this._backdropElement = document.createElement('iron-overlay-backdrop');
-    }
-    return this._backdropElement;
-  },
-  get deepActiveElement() {
-    var active = document.activeElement || document.body;
-    while (active.root && Polymer.dom(active.root).activeElement) {
-      active = Polymer.dom(active.root).activeElement;
-    }
-    return active;
-  },
-  _bringOverlayAtIndexToFront: function(i) {
-    var overlay = this._overlays[i];
-    if (!overlay) {
-      return;
-    }
-    var lastI = this._overlays.length - 1;
-    var currentOverlay = this._overlays[lastI];
-    if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
-      lastI--;
-    }
-    if (i >= lastI) {
-      return;
-    }
-    var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
-    if (this._getZ(overlay) <= minimumZ) {
-      this._applyOverlayZ(overlay, minimumZ);
-    }
-    while (i < lastI) {
-      this._overlays[i] = this._overlays[i + 1];
-      i++;
-    }
-    this._overlays[lastI] = overlay;
-  },
-  addOrRemoveOverlay: function(overlay) {
-    if (overlay.opened) {
-      this.addOverlay(overlay);
-    } else {
-      this.removeOverlay(overlay);
-    }
-  },
-  addOverlay: function(overlay) {
-    var i = this._overlays.indexOf(overlay);
-    if (i >= 0) {
-      this._bringOverlayAtIndexToFront(i);
-      this.trackBackdrop();
-      return;
-    }
-    var insertionIndex = this._overlays.length;
-    var currentOverlay = this._overlays[insertionIndex - 1];
-    var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
-    var newZ = this._getZ(overlay);
-    if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
-      this._applyOverlayZ(currentOverlay, minimumZ);
-      insertionIndex--;
-      var previousOverlay = this._overlays[insertionIndex - 1];
-      minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
-    }
-    if (newZ <= minimumZ) {
-      this._applyOverlayZ(overlay, minimumZ);
-    }
-    this._overlays.splice(insertionIndex, 0, overlay);
-    this.trackBackdrop();
-  },
-  removeOverlay: function(overlay) {
-    var i = this._overlays.indexOf(overlay);
-    if (i === -1) {
-      return;
-    }
-    this._overlays.splice(i, 1);
-    this.trackBackdrop();
-  },
-  currentOverlay: function() {
-    var i = this._overlays.length - 1;
-    return this._overlays[i];
-  },
-  currentOverlayZ: function() {
-    return this._getZ(this.currentOverlay());
-  },
-  ensureMinimumZ: function(minimumZ) {
-    this._minimumZ = Math.max(this._minimumZ, minimumZ);
-  },
-  focusOverlay: function() {
-    var current = this.currentOverlay();
-    if (current) {
-      current._applyFocus();
-    }
-  },
-  trackBackdrop: function() {
-    var overlay = this._overlayWithBackdrop();
-    if (!overlay && !this._backdropElement) {
-      return;
-    }
-    this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
-    this.backdropElement.opened = !!overlay;
-  },
-  getBackdrops: function() {
-    var backdrops = [];
-    for (var i = 0; i < this._overlays.length; i++) {
-      if (this._overlays[i].withBackdrop) {
-        backdrops.push(this._overlays[i]);
-      }
-    }
-    return backdrops;
-  },
-  backdropZ: function() {
-    return this._getZ(this._overlayWithBackdrop()) - 1;
-  },
-  _overlayWithBackdrop: function() {
-    for (var i = 0; i < this._overlays.length; i++) {
-      if (this._overlays[i].withBackdrop) {
-        return this._overlays[i];
-      }
-    }
-  },
-  _getZ: function(overlay) {
-    var z = this._minimumZ;
-    if (overlay) {
-      var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex);
-      if (z1 === z1) {
-        z = z1;
-      }
-    }
-    return z;
-  },
-  _setZ: function(element, z) {
-    element.style.zIndex = z;
-  },
-  _applyOverlayZ: function(overlay, aboveZ) {
-    this._setZ(overlay, aboveZ + 2);
-  },
-  _overlayInPath: function(path) {
-    path = path || [];
-    for (var i = 0; i < path.length; i++) {
-      if (path[i]._manager === this) {
-        return path[i];
-      }
-    }
-  },
-  _onCaptureClick: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
-      overlay._onCaptureClick(event);
-    }
-  },
-  _onCaptureFocus: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay) {
-      overlay._onCaptureFocus(event);
-    }
-  },
-  _onCaptureKeyDown: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay) {
-      if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
-        overlay._onCaptureEsc(event);
-      } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
-        overlay._onCaptureTab(event);
-      }
-    }
-  },
-  _shouldBeBehindOverlay: function(overlay1, overlay2) {
-    return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
-  }
-};
-
-Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
-
-(function() {
-  'use strict';
-  Polymer.IronOverlayBehaviorImpl = {
-    properties: {
-      opened: {
-        observer: '_openedChanged',
-        type: Boolean,
-        value: false,
-        notify: true
-      },
-      canceled: {
-        observer: '_canceledChanged',
-        readOnly: true,
-        type: Boolean,
-        value: false
-      },
-      withBackdrop: {
-        observer: '_withBackdropChanged',
-        type: Boolean
-      },
-      noAutoFocus: {
-        type: Boolean,
-        value: false
-      },
-      noCancelOnEscKey: {
-        type: Boolean,
-        value: false
-      },
-      noCancelOnOutsideClick: {
-        type: Boolean,
-        value: false
-      },
-      closingReason: {
-        type: Object
-      },
-      restoreFocusOnClose: {
-        type: Boolean,
-        value: false
-      },
-      alwaysOnTop: {
-        type: Boolean
-      },
-      _manager: {
-        type: Object,
-        value: Polymer.IronOverlayManager
-      },
-      _focusedChild: {
-        type: Object
-      }
-    },
-    listeners: {
-      'iron-resize': '_onIronResize'
-    },
-    get backdropElement() {
-      return this._manager.backdropElement;
-    },
-    get _focusNode() {
-      return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
-    },
-    get _focusableNodes() {
-      var FOCUSABLE_WITH_DISABLED = [ 'a[href]', 'area[href]', 'iframe', '[tabindex]', '[contentEditable=true]' ];
-      var FOCUSABLE_WITHOUT_DISABLED = [ 'input', 'select', 'textarea', 'button' ];
-      var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') + ':not([tabindex="-1"]),' + FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),') + ':not([disabled]):not([tabindex="-1"])';
-      var focusables = Polymer.dom(this).querySelectorAll(selector);
-      if (this.tabIndex >= 0) {
-        focusables.splice(0, 0, this);
-      }
-      return focusables.sort(function(a, b) {
-        if (a.tabIndex === b.tabIndex) {
-          return 0;
-        }
-        if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
-          return 1;
-        }
-        return -1;
-      });
-    },
-    ready: function() {
-      this.__isAnimating = false;
-      this.__shouldRemoveTabIndex = false;
-      this.__firstFocusableNode = this.__lastFocusableNode = null;
-      this.__raf = null;
-      this.__restoreFocusNode = null;
-      this._ensureSetup();
-    },
-    attached: function() {
-      if (this.opened) {
-        this._openedChanged(this.opened);
-      }
-      this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
-    },
-    detached: function() {
-      Polymer.dom(this).unobserveNodes(this._observer);
-      this._observer = null;
-      if (this.__raf) {
-        window.cancelAnimationFrame(this.__raf);
-        this.__raf = null;
-      }
-      this._manager.removeOverlay(this);
-    },
-    toggle: function() {
-      this._setCanceled(false);
-      this.opened = !this.opened;
-    },
-    open: function() {
-      this._setCanceled(false);
-      this.opened = true;
-    },
-    close: function() {
-      this._setCanceled(false);
-      this.opened = false;
-    },
-    cancel: function(event) {
-      var cancelEvent = this.fire('iron-overlay-canceled', event, {
-        cancelable: true
-      });
-      if (cancelEvent.defaultPrevented) {
-        return;
-      }
-      this._setCanceled(true);
-      this.opened = false;
-    },
-    _ensureSetup: function() {
-      if (this._overlaySetup) {
-        return;
-      }
-      this._overlaySetup = true;
-      this.style.outline = 'none';
-      this.style.display = 'none';
-    },
-    _openedChanged: function(opened) {
-      if (opened) {
-        this.removeAttribute('aria-hidden');
-      } else {
-        this.setAttribute('aria-hidden', 'true');
-      }
-      if (!this.isAttached) {
-        return;
-      }
-      this.__isAnimating = true;
-      this.__onNextAnimationFrame(this.__openedChanged);
-    },
-    _canceledChanged: function() {
-      this.closingReason = this.closingReason || {};
-      this.closingReason.canceled = this.canceled;
-    },
-    _withBackdropChanged: function() {
-      if (this.withBackdrop && !this.hasAttribute('tabindex')) {
-        this.setAttribute('tabindex', '-1');
-        this.__shouldRemoveTabIndex = true;
-      } else if (this.__shouldRemoveTabIndex) {
-        this.removeAttribute('tabindex');
-        this.__shouldRemoveTabIndex = false;
-      }
-      if (this.opened && this.isAttached) {
-        this._manager.trackBackdrop();
-      }
-    },
-    _prepareRenderOpened: function() {
-      this.__restoreFocusNode = this._manager.deepActiveElement;
-      this._preparePositioning();
-      this.refit();
-      this._finishPositioning();
-      if (this.noAutoFocus && document.activeElement === this._focusNode) {
-        this._focusNode.blur();
-        this.__restoreFocusNode.focus();
-      }
-    },
-    _renderOpened: function() {
-      this._finishRenderOpened();
-    },
-    _renderClosed: function() {
-      this._finishRenderClosed();
-    },
-    _finishRenderOpened: function() {
-      this.notifyResize();
-      this.__isAnimating = false;
-      var focusableNodes = this._focusableNodes;
-      this.__firstFocusableNode = focusableNodes[0];
-      this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
-      this.fire('iron-overlay-opened');
-    },
-    _finishRenderClosed: function() {
-      this.style.display = 'none';
-      this.style.zIndex = '';
-      this.notifyResize();
-      this.__isAnimating = false;
-      this.fire('iron-overlay-closed', this.closingReason);
-    },
-    _preparePositioning: function() {
-      this.style.transition = this.style.webkitTransition = 'none';
-      this.style.transform = this.style.webkitTransform = 'none';
-      this.style.display = '';
-    },
-    _finishPositioning: function() {
-      this.style.display = 'none';
-      this.scrollTop = this.scrollTop;
-      this.style.transition = this.style.webkitTransition = '';
-      this.style.transform = this.style.webkitTransform = '';
-      this.style.display = '';
-      this.scrollTop = this.scrollTop;
-    },
-    _applyFocus: function() {
-      if (this.opened) {
-        if (!this.noAutoFocus) {
-          this._focusNode.focus();
-        }
-      } else {
-        this._focusNode.blur();
-        this._focusedChild = null;
-        if (this.restoreFocusOnClose && this.__restoreFocusNode) {
-          this.__restoreFocusNode.focus();
-        }
-        this.__restoreFocusNode = null;
-        var currentOverlay = this._manager.currentOverlay();
-        if (currentOverlay && this !== currentOverlay) {
-          currentOverlay._applyFocus();
-        }
-      }
-    },
-    _onCaptureClick: function(event) {
-      if (!this.noCancelOnOutsideClick) {
-        this.cancel(event);
-      }
-    },
-    _onCaptureFocus: function(event) {
-      if (!this.withBackdrop) {
-        return;
-      }
-      var path = Polymer.dom(event).path;
-      if (path.indexOf(this) === -1) {
-        event.stopPropagation();
-        this._applyFocus();
-      } else {
-        this._focusedChild = path[0];
-      }
-    },
-    _onCaptureEsc: function(event) {
-      if (!this.noCancelOnEscKey) {
-        this.cancel(event);
-      }
-    },
-    _onCaptureTab: function(event) {
-      if (!this.withBackdrop) {
-        return;
-      }
-      var shift = event.shiftKey;
-      var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
-      var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
-      var shouldWrap = false;
-      if (nodeToCheck === nodeToSet) {
-        shouldWrap = true;
-      } else {
-        var focusedNode = this._manager.deepActiveElement;
-        shouldWrap = focusedNode === nodeToCheck || focusedNode === this;
-      }
-      if (shouldWrap) {
-        event.preventDefault();
-        this._focusedChild = nodeToSet;
-        this._applyFocus();
-      }
-    },
-    _onIronResize: function() {
-      if (this.opened && !this.__isAnimating) {
-        this.__onNextAnimationFrame(this.refit);
-      }
-    },
-    _onNodesChange: function() {
-      if (this.opened && !this.__isAnimating) {
-        this.notifyResize();
-      }
-    },
-    __openedChanged: function() {
-      if (this.opened) {
-        this._prepareRenderOpened();
-        this._manager.addOverlay(this);
-        this._applyFocus();
-        this._renderOpened();
-      } else {
-        this._manager.removeOverlay(this);
-        this._applyFocus();
-        this._renderClosed();
-      }
-    },
-    __onNextAnimationFrame: function(callback) {
-      if (this.__raf) {
-        window.cancelAnimationFrame(this.__raf);
-      }
-      var self = this;
-      this.__raf = window.requestAnimationFrame(function nextAnimationFrame() {
-        self.__raf = null;
-        callback.call(self);
-      });
-    }
-  };
-  Polymer.IronOverlayBehavior = [ Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl ];
-})();
-
-Polymer.NeonAnimatableBehavior = {
-  properties: {
-    animationConfig: {
-      type: Object
-    },
-    entryAnimation: {
-      observer: '_entryAnimationChanged',
-      type: String
-    },
-    exitAnimation: {
-      observer: '_exitAnimationChanged',
-      type: String
-    }
-  },
-  _entryAnimationChanged: function() {
-    this.animationConfig = this.animationConfig || {};
-    this.animationConfig['entry'] = [ {
-      name: this.entryAnimation,
-      node: this
-    } ];
-  },
-  _exitAnimationChanged: function() {
-    this.animationConfig = this.animationConfig || {};
-    this.animationConfig['exit'] = [ {
-      name: this.exitAnimation,
-      node: this
-    } ];
-  },
-  _copyProperties: function(config1, config2) {
-    for (var property in config2) {
-      config1[property] = config2[property];
-    }
-  },
-  _cloneConfig: function(config) {
-    var clone = {
-      isClone: true
-    };
-    this._copyProperties(clone, config);
-    return clone;
-  },
-  _getAnimationConfigRecursive: function(type, map, allConfigs) {
-    if (!this.animationConfig) {
-      return;
-    }
-    if (this.animationConfig.value && typeof this.animationConfig.value === 'function') {
-      this._warn(this._logf('playAnimation', "Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));
-      return;
-    }
-    var thisConfig;
-    if (type) {
-      thisConfig = this.animationConfig[type];
-    } else {
-      thisConfig = this.animationConfig;
-    }
-    if (!Array.isArray(thisConfig)) {
-      thisConfig = [ thisConfig ];
-    }
-    if (thisConfig) {
-      for (var config, index = 0; config = thisConfig[index]; index++) {
-        if (config.animatable) {
-          config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs);
-        } else {
-          if (config.id) {
-            var cachedConfig = map[config.id];
-            if (cachedConfig) {
-              if (!cachedConfig.isClone) {
-                map[config.id] = this._cloneConfig(cachedConfig);
-                cachedConfig = map[config.id];
-              }
-              this._copyProperties(cachedConfig, config);
-            } else {
-              map[config.id] = config;
-            }
-          } else {
-            allConfigs.push(config);
-          }
-        }
-      }
-    }
-  },
-  getAnimationConfig: function(type) {
-    var map = {};
-    var allConfigs = [];
-    this._getAnimationConfigRecursive(type, map, allConfigs);
-    for (var key in map) {
-      allConfigs.push(map[key]);
-    }
-    return allConfigs;
-  }
-};
-
-Polymer.NeonAnimationRunnerBehaviorImpl = {
-  _configureAnimations: function(configs) {
-    var results = [];
-    if (configs.length > 0) {
-      for (var config, index = 0; config = configs[index]; index++) {
-        var neonAnimation = document.createElement(config.name);
-        if (neonAnimation.isNeonAnimation) {
-          var result = null;
-          try {
-            result = neonAnimation.configure(config);
-            if (typeof result.cancel != 'function') {
-              result = document.timeline.play(result);
-            }
-          } catch (e) {
-            result = null;
-            console.warn('Couldnt play', '(', config.name, ').', e);
-          }
-          if (result) {
-            results.push({
-              neonAnimation: neonAnimation,
-              config: config,
-              animation: result
-            });
-          }
-        } else {
-          console.warn(this.is + ':', config.name, 'not found!');
-        }
-      }
-    }
-    return results;
-  },
-  _shouldComplete: function(activeEntries) {
-    var finished = true;
-    for (var i = 0; i < activeEntries.length; i++) {
-      if (activeEntries[i].animation.playState != 'finished') {
-        finished = false;
-        break;
-      }
-    }
-    return finished;
-  },
-  _complete: function(activeEntries) {
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].neonAnimation.complete(activeEntries[i].config);
-    }
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].animation.cancel();
-    }
-  },
-  playAnimation: function(type, cookie) {
-    var configs = this.getAnimationConfig(type);
-    if (!configs) {
-      return;
-    }
-    this._active = this._active || {};
-    if (this._active[type]) {
-      this._complete(this._active[type]);
-      delete this._active[type];
-    }
-    var activeEntries = this._configureAnimations(configs);
-    if (activeEntries.length == 0) {
-      this.fire('neon-animation-finish', cookie, {
-        bubbles: false
-      });
-      return;
-    }
-    this._active[type] = activeEntries;
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].animation.onfinish = function() {
-        if (this._shouldComplete(activeEntries)) {
-          this._complete(activeEntries);
-          delete this._active[type];
-          this.fire('neon-animation-finish', cookie, {
-            bubbles: false
-          });
-        }
-      }.bind(this);
-    }
-  },
-  cancelAnimation: function() {
-    for (var k in this._animations) {
-      this._animations[k].cancel();
-    }
-    this._animations = {};
-  }
-};
-
-Polymer.NeonAnimationRunnerBehavior = [ Polymer.NeonAnimatableBehavior, Polymer.NeonAnimationRunnerBehaviorImpl ];
-
-Polymer.NeonAnimationBehavior = {
-  properties: {
-    animationTiming: {
-      type: Object,
-      value: function() {
-        return {
-          duration: 500,
-          easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
-          fill: 'both'
-        };
-      }
-    }
-  },
-  isNeonAnimation: true,
-  timingFromConfig: function(config) {
-    if (config.timing) {
-      for (var property in config.timing) {
-        this.animationTiming[property] = config.timing[property];
-      }
-    }
-    return this.animationTiming;
-  },
-  setPrefixedProperty: function(node, property, value) {
-    var map = {
-      transform: [ 'webkitTransform' ],
-      transformOrigin: [ 'mozTransformOrigin', 'webkitTransformOrigin' ]
-    };
-    var prefixes = map[property];
-    for (var prefix, index = 0; prefix = prefixes[index]; index++) {
-      node.style[prefix] = value;
-    }
-    node.style[property] = value;
-  },
-  complete: function() {}
-};
-
-Polymer({
-  is: 'opaque-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '1'
-    }, {
-      opacity: '1'
-    } ], this.timingFromConfig(config));
-    node.style.opacity = '0';
-    return this._effect;
-  },
-  complete: function(config) {
-    config.node.style.opacity = '';
-  }
-});
-
-(function() {
-  'use strict';
-  var LAST_TOUCH_POSITION = {
-    pageX: 0,
-    pageY: 0
-  };
-  var ROOT_TARGET = null;
-  var SCROLLABLE_NODES = [];
-  Polymer.IronDropdownScrollManager = {
-    get currentLockingElement() {
-      return this._lockingElements[this._lockingElements.length - 1];
-    },
-    elementIsScrollLocked: function(element) {
-      var currentLockingElement = this.currentLockingElement;
-      if (currentLockingElement === undefined) return false;
-      var scrollLocked;
-      if (this._hasCachedLockedElement(element)) {
-        return true;
-      }
-      if (this._hasCachedUnlockedElement(element)) {
-        return false;
-      }
-      scrollLocked = !!currentLockingElement && currentLockingElement !== element && !this._composedTreeContains(currentLockingElement, element);
-      if (scrollLocked) {
-        this._lockedElementCache.push(element);
-      } else {
-        this._unlockedElementCache.push(element);
-      }
-      return scrollLocked;
-    },
-    pushScrollLock: function(element) {
-      if (this._lockingElements.indexOf(element) >= 0) {
-        return;
-      }
-      if (this._lockingElements.length === 0) {
-        this._lockScrollInteractions();
-      }
-      this._lockingElements.push(element);
-      this._lockedElementCache = [];
-      this._unlockedElementCache = [];
-    },
-    removeScrollLock: function(element) {
-      var index = this._lockingElements.indexOf(element);
-      if (index === -1) {
-        return;
-      }
-      this._lockingElements.splice(index, 1);
-      this._lockedElementCache = [];
-      this._unlockedElementCache = [];
-      if (this._lockingElements.length === 0) {
-        this._unlockScrollInteractions();
-      }
-    },
-    _lockingElements: [],
-    _lockedElementCache: null,
-    _unlockedElementCache: null,
-    _hasCachedLockedElement: function(element) {
-      return this._lockedElementCache.indexOf(element) > -1;
-    },
-    _hasCachedUnlockedElement: function(element) {
-      return this._unlockedElementCache.indexOf(element) > -1;
-    },
-    _composedTreeContains: function(element, child) {
-      var contentElements;
-      var distributedNodes;
-      var contentIndex;
-      var nodeIndex;
-      if (element.contains(child)) {
-        return true;
-      }
-      contentElements = Polymer.dom(element).querySelectorAll('content');
-      for (contentIndex = 0; contentIndex < contentElements.length; ++contentIndex) {
-        distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistributedNodes();
-        for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
-          if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
-            return true;
-          }
-        }
-      }
-      return false;
-    },
-    _scrollInteractionHandler: function(event) {
-      if (event.cancelable && this._shouldPreventScrolling(event)) {
-        event.preventDefault();
-      }
-      if (event.targetTouches) {
-        var touch = event.targetTouches[0];
-        LAST_TOUCH_POSITION.pageX = touch.pageX;
-        LAST_TOUCH_POSITION.pageY = touch.pageY;
-      }
-    },
-    _lockScrollInteractions: function() {
-      this._boundScrollHandler = this._boundScrollHandler || this._scrollInteractionHandler.bind(this);
-      document.addEventListener('wheel', this._boundScrollHandler, true);
-      document.addEventListener('mousewheel', this._boundScrollHandler, true);
-      document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true);
-      document.addEventListener('touchstart', this._boundScrollHandler, true);
-      document.addEventListener('touchmove', this._boundScrollHandler, true);
-    },
-    _unlockScrollInteractions: function() {
-      document.removeEventListener('wheel', this._boundScrollHandler, true);
-      document.removeEventListener('mousewheel', this._boundScrollHandler, true);
-      document.removeEventListener('DOMMouseScroll', this._boundScrollHandler, true);
-      document.removeEventListener('touchstart', this._boundScrollHandler, true);
-      document.removeEventListener('touchmove', this._boundScrollHandler, true);
-    },
-    _shouldPreventScrolling: function(event) {
-      var target = Polymer.dom(event).rootTarget;
-      if (event.type !== 'touchmove' && ROOT_TARGET !== target) {
-        ROOT_TARGET = target;
-        SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path);
-      }
-      if (!SCROLLABLE_NODES.length) {
-        return true;
-      }
-      if (event.type === 'touchstart') {
-        return false;
-      }
-      var info = this._getScrollInfo(event);
-      return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY);
-    },
-    _getScrollableNodes: function(nodes) {
-      var scrollables = [];
-      var lockingIndex = nodes.indexOf(this.currentLockingElement);
-      for (var i = 0; i <= lockingIndex; i++) {
-        var node = nodes[i];
-        if (node.nodeType === 11) {
-          continue;
-        }
-        var style = node.style;
-        if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
-          style = window.getComputedStyle(node);
-        }
-        if (style.overflow === 'scroll' || style.overflow === 'auto') {
-          scrollables.push(node);
-        }
-      }
-      return scrollables;
-    },
-    _getScrollingNode: function(nodes, deltaX, deltaY) {
-      if (!deltaX && !deltaY) {
-        return;
-      }
-      var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
-      for (var i = 0; i < nodes.length; i++) {
-        var node = nodes[i];
-        var canScroll = false;
-        if (verticalScroll) {
-          canScroll = deltaY < 0 ? node.scrollTop > 0 : node.scrollTop < node.scrollHeight - node.clientHeight;
-        } else {
-          canScroll = deltaX < 0 ? node.scrollLeft > 0 : node.scrollLeft < node.scrollWidth - node.clientWidth;
-        }
-        if (canScroll) {
-          return node;
-        }
-      }
-    },
-    _getScrollInfo: function(event) {
-      var info = {
-        deltaX: event.deltaX,
-        deltaY: event.deltaY
-      };
-      if ('deltaX' in event) {} else if ('wheelDeltaX' in event) {
-        info.deltaX = -event.wheelDeltaX;
-        info.deltaY = -event.wheelDeltaY;
-      } else if ('axis' in event) {
-        info.deltaX = event.axis === 1 ? event.detail : 0;
-        info.deltaY = event.axis === 2 ? event.detail : 0;
-      } else if (event.targetTouches) {
-        var touch = event.targetTouches[0];
-        info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX;
-        info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY;
-      }
-      return info;
-    }
-  };
-})();
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-dropdown',
-    behaviors: [ Polymer.IronControlState, Polymer.IronA11yKeysBehavior, Polymer.IronOverlayBehavior, Polymer.NeonAnimationRunnerBehavior ],
-    properties: {
-      horizontalAlign: {
-        type: String,
-        value: 'left',
-        reflectToAttribute: true
-      },
-      verticalAlign: {
-        type: String,
-        value: 'top',
-        reflectToAttribute: true
-      },
-      openAnimationConfig: {
-        type: Object
-      },
-      closeAnimationConfig: {
-        type: Object
-      },
-      focusTarget: {
-        type: Object
-      },
-      noAnimations: {
-        type: Boolean,
-        value: false
-      },
-      allowOutsideScroll: {
-        type: Boolean,
-        value: false
-      },
-      _boundOnCaptureScroll: {
-        type: Function,
-        value: function() {
-          return this._onCaptureScroll.bind(this);
-        }
-      }
-    },
-    listeners: {
-      'neon-animation-finish': '_onNeonAnimationFinish'
-    },
-    observers: [ '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)' ],
-    get containedElement() {
-      return Polymer.dom(this.$.content).getDistributedNodes()[0];
-    },
-    get _focusTarget() {
-      return this.focusTarget || this.containedElement;
-    },
-    ready: function() {
-      this._scrollTop = 0;
-      this._scrollLeft = 0;
-      this._refitOnScrollRAF = null;
-    },
-    attached: function() {
-      if (!this.sizingTarget || this.sizingTarget === this) {
-        this.sizingTarget = this.containedElement;
-      }
-    },
-    detached: function() {
-      this.cancelAnimation();
-      document.removeEventListener('scroll', this._boundOnCaptureScroll);
-      Polymer.IronDropdownScrollManager.removeScrollLock(this);
-    },
-    _openedChanged: function() {
-      if (this.opened && this.disabled) {
-        this.cancel();
-      } else {
-        this.cancelAnimation();
-        this._updateAnimationConfig();
-        this._saveScrollPosition();
-        if (this.opened) {
-          document.addEventListener('scroll', this._boundOnCaptureScroll);
-          !this.allowOutsideScroll && Polymer.IronDropdownScrollManager.pushScrollLock(this);
-        } else {
-          document.removeEventListener('scroll', this._boundOnCaptureScroll);
-          Polymer.IronDropdownScrollManager.removeScrollLock(this);
-        }
-        Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
-      }
-    },
-    _renderOpened: function() {
-      if (!this.noAnimations && this.animationConfig.open) {
-        this.$.contentWrapper.classList.add('animating');
-        this.playAnimation('open');
-      } else {
-        Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments);
-      }
-    },
-    _renderClosed: function() {
-      if (!this.noAnimations && this.animationConfig.close) {
-        this.$.contentWrapper.classList.add('animating');
-        this.playAnimation('close');
-      } else {
-        Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments);
-      }
-    },
-    _onNeonAnimationFinish: function() {
-      this.$.contentWrapper.classList.remove('animating');
-      if (this.opened) {
-        this._finishRenderOpened();
-      } else {
-        this._finishRenderClosed();
-      }
-    },
-    _onCaptureScroll: function() {
-      if (!this.allowOutsideScroll) {
-        this._restoreScrollPosition();
-      } else {
-        this._refitOnScrollRAF && window.cancelAnimationFrame(this._refitOnScrollRAF);
-        this._refitOnScrollRAF = window.requestAnimationFrame(this.refit.bind(this));
-      }
-    },
-    _saveScrollPosition: function() {
-      if (document.scrollingElement) {
-        this._scrollTop = document.scrollingElement.scrollTop;
-        this._scrollLeft = document.scrollingElement.scrollLeft;
-      } else {
-        this._scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
-        this._scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
-      }
-    },
-    _restoreScrollPosition: function() {
-      if (document.scrollingElement) {
-        document.scrollingElement.scrollTop = this._scrollTop;
-        document.scrollingElement.scrollLeft = this._scrollLeft;
-      } else {
-        document.documentElement.scrollTop = this._scrollTop;
-        document.documentElement.scrollLeft = this._scrollLeft;
-        document.body.scrollTop = this._scrollTop;
-        document.body.scrollLeft = this._scrollLeft;
-      }
-    },
-    _updateAnimationConfig: function() {
-      var animations = (this.openAnimationConfig || []).concat(this.closeAnimationConfig || []);
-      for (var i = 0; i < animations.length; i++) {
-        animations[i].node = this.containedElement;
-      }
-      this.animationConfig = {
-        open: this.openAnimationConfig,
-        close: this.closeAnimationConfig
-      };
-    },
-    _updateOverlayPosition: function() {
-      if (this.isAttached) {
-        this.notifyResize();
-      }
-    },
-    _applyFocus: function() {
-      var focusTarget = this.focusTarget || this.containedElement;
-      if (focusTarget && this.opened && !this.noAutoFocus) {
-        focusTarget.focus();
-      } else {
-        Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
-      }
-    }
-  });
-})();
-
-Polymer({
-  is: 'fade-in-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '0'
-    }, {
-      opacity: '1'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'fade-out-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '1'
-    }, {
-      opacity: '0'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-grow-height-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var height = rect.height;
-    this._effect = new KeyframeEffect(node, [ {
-      height: height / 2 + 'px'
-    }, {
-      height: height + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-grow-width-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var width = rect.width;
-    this._effect = new KeyframeEffect(node, [ {
-      width: width / 2 + 'px'
-    }, {
-      width: width + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-shrink-width-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var width = rect.width;
-    this._effect = new KeyframeEffect(node, [ {
-      width: width + 'px'
-    }, {
-      width: width - width / 20 + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-shrink-height-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var height = rect.height;
-    var top = rect.top;
-    this.setPrefixedProperty(node, 'transformOrigin', '0 0');
-    this._effect = new KeyframeEffect(node, [ {
-      height: height + 'px',
-      transform: 'translateY(0)'
-    }, {
-      height: height / 2 + 'px',
-      transform: 'translateY(-20px)'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-(function() {
-  'use strict';
-  var config = {
-    ANIMATION_CUBIC_BEZIER: 'cubic-bezier(.3,.95,.5,1)',
-    MAX_ANIMATION_TIME_MS: 400
-  };
-  var PaperMenuButton = Polymer({
-    is: 'paper-menu-button',
-    behaviors: [ Polymer.IronA11yKeysBehavior, Polymer.IronControlState ],
-    properties: {
-      opened: {
-        type: Boolean,
-        value: false,
-        notify: true,
-        observer: '_openedChanged'
-      },
-      horizontalAlign: {
-        type: String,
-        value: 'left',
-        reflectToAttribute: true
-      },
-      verticalAlign: {
-        type: String,
-        value: 'top',
-        reflectToAttribute: true
-      },
-      dynamicAlign: {
-        type: Boolean
-      },
-      horizontalOffset: {
-        type: Number,
-        value: 0,
-        notify: true
-      },
-      verticalOffset: {
-        type: Number,
-        value: 0,
-        notify: true
-      },
-      noOverlap: {
-        type: Boolean
-      },
-      noAnimations: {
-        type: Boolean,
-        value: false
-      },
-      ignoreSelect: {
-        type: Boolean,
-        value: false
-      },
-      closeOnActivate: {
-        type: Boolean,
-        value: false
-      },
-      openAnimationConfig: {
-        type: Object,
-        value: function() {
-          return [ {
-            name: 'fade-in-animation',
-            timing: {
-              delay: 100,
-              duration: 200
-            }
-          }, {
-            name: 'paper-menu-grow-width-animation',
-            timing: {
-              delay: 100,
-              duration: 150,
-              easing: config.ANIMATION_CUBIC_BEZIER
-            }
-          }, {
-            name: 'paper-menu-grow-height-animation',
-            timing: {
-              delay: 100,
-              duration: 275,
-              easing: config.ANIMATION_CUBIC_BEZIER
-            }
-          } ];
-        }
-      },
-      closeAnimationConfig: {
-        type: Object,
-        value: function() {
-          return [ {
-            name: 'fade-out-animation',
-            timing: {
-              duration: 150
-            }
-          }, {
-            name: 'paper-menu-shrink-width-animation',
-            timing: {
-              delay: 100,
-              duration: 50,
-              easing: config.ANIMATION_CUBIC_BEZIER
-            }
-          }, {
-            name: 'paper-menu-shrink-height-animation',
-            timing: {
-              duration: 200,
-              easing: 'ease-in'
-            }
-          } ];
-        }
-      },
-      allowOutsideScroll: {
-        type: Boolean,
-        value: false
-      },
-      restoreFocusOnClose: {
-        type: Boolean,
-        value: true
-      },
-      _dropdownContent: {
-        type: Object
-      }
-    },
-    hostAttributes: {
-      role: 'group',
-      'aria-haspopup': 'true'
-    },
-    listeners: {
-      'iron-activate': '_onIronActivate',
-      'iron-select': '_onIronSelect'
-    },
-    get contentElement() {
-      return Polymer.dom(this.$.content).getDistributedNodes()[0];
-    },
-    toggle: function() {
-      if (this.opened) {
-        this.close();
-      } else {
-        this.open();
-      }
-    },
-    open: function() {
-      if (this.disabled) {
-        return;
-      }
-      this.$.dropdown.open();
-    },
-    close: function() {
-      this.$.dropdown.close();
-    },
-    _onIronSelect: function(event) {
-      if (!this.ignoreSelect) {
-        this.close();
-      }
-    },
-    _onIronActivate: function(event) {
-      if (this.closeOnActivate) {
-        this.close();
-      }
-    },
-    _openedChanged: function(opened, oldOpened) {
-      if (opened) {
-        this._dropdownContent = this.contentElement;
-        this.fire('paper-dropdown-open');
-      } else if (oldOpened != null) {
-        this.fire('paper-dropdown-close');
-      }
-    },
-    _disabledChanged: function(disabled) {
-      Polymer.IronControlState._disabledChanged.apply(this, arguments);
-      if (disabled && this.opened) {
-        this.close();
-      }
-    },
-    __onIronOverlayCanceled: function(event) {
-      var uiEvent = event.detail;
-      var target = Polymer.dom(uiEvent).rootTarget;
-      var trigger = this.$.trigger;
-      var path = Polymer.dom(uiEvent).path;
-      if (path.indexOf(trigger) > -1) {
-        event.preventDefault();
-      }
-    }
-  });
-  Object.keys(config).forEach(function(key) {
-    PaperMenuButton[key] = config[key];
-  });
-  Polymer.PaperMenuButton = PaperMenuButton;
-})();
-
-Polymer.PaperInkyFocusBehaviorImpl = {
-  observers: [ '_focusedChanged(receivedFocusFromKeyboard)' ],
-  _focusedChanged: function(receivedFocusFromKeyboard) {
-    if (receivedFocusFromKeyboard) {
-      this.ensureRipple();
-    }
-    if (this.hasRipple()) {
-      this._ripple.holdDown = receivedFocusFromKeyboard;
-    }
-  },
-  _createRipple: function() {
-    var ripple = Polymer.PaperRippleBehavior._createRipple();
-    ripple.id = 'ink';
-    ripple.setAttribute('center', '');
-    ripple.classList.add('circle');
-    return ripple;
-  }
-};
-
-Polymer.PaperInkyFocusBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperInkyFocusBehaviorImpl ];
-
-Polymer({
-  is: 'paper-icon-button',
-  hostAttributes: {
-    role: 'button',
-    tabindex: '0'
-  },
-  behaviors: [ Polymer.PaperInkyFocusBehavior ],
-  properties: {
-    src: {
-      type: String
-    },
-    icon: {
-      type: String
-    },
-    alt: {
-      type: String,
-      observer: "_altChanged"
-    }
-  },
-  _altChanged: function(newValue, oldValue) {
-    var label = this.getAttribute('aria-label');
-    if (!label || oldValue == label) {
-      this.setAttribute('aria-label', newValue);
-    }
-  }
-});
-
-Polymer({
-  is: 'iron-media-query',
-  properties: {
-    queryMatches: {
-      type: Boolean,
-      value: false,
-      readOnly: true,
-      notify: true
-    },
-    query: {
-      type: String,
-      observer: 'queryChanged'
-    },
-    full: {
-      type: Boolean,
-      value: false
-    },
-    _boundMQHandler: {
-      value: function() {
-        return this.queryHandler.bind(this);
-      }
-    },
-    _mq: {
-      value: null
-    }
-  },
-  attached: function() {
-    this.style.display = 'none';
-    this.queryChanged();
-  },
-  detached: function() {
-    this._remove();
-  },
-  _add: function() {
-    if (this._mq) {
-      this._mq.addListener(this._boundMQHandler);
-    }
-  },
-  _remove: function() {
-    if (this._mq) {
-      this._mq.removeListener(this._boundMQHandler);
-    }
-    this._mq = null;
-  },
-  queryChanged: function() {
-    this._remove();
-    var query = this.query;
-    if (!query) {
-      return;
-    }
-    if (!this.full && query[0] !== '(') {
-      query = '(' + query + ')';
-    }
-    this._mq = window.matchMedia(query);
-    this._add();
-    this.queryHandler(this._mq);
-  },
-  queryHandler: function(mq) {
-    this._setQueryMatches(mq.matches);
-  }
-});
-
-(function() {
-  'use strict';
-  Polymer.IronA11yAnnouncer = Polymer({
-    is: 'iron-a11y-announcer',
-    properties: {
-      mode: {
-        type: String,
-        value: 'polite'
-      },
-      _text: {
-        type: String,
-        value: ''
-      }
-    },
-    created: function() {
-      if (!Polymer.IronA11yAnnouncer.instance) {
-        Polymer.IronA11yAnnouncer.instance = this;
-      }
-      document.body.addEventListener('iron-announce', this._onIronAnnounce.bind(this));
-    },
-    announce: function(text) {
-      this._text = '';
-      this.async(function() {
-        this._text = text;
-      }, 100);
-    },
-    _onIronAnnounce: function(event) {
-      if (event.detail && event.detail.text) {
-        this.announce(event.detail.text);
-      }
-    }
-  });
-  Polymer.IronA11yAnnouncer.instance = null;
-  Polymer.IronA11yAnnouncer.requestAvailability = function() {
-    if (!Polymer.IronA11yAnnouncer.instance) {
-      Polymer.IronA11yAnnouncer.instance = document.createElement('iron-a11y-announcer');
-    }
-    document.body.appendChild(Polymer.IronA11yAnnouncer.instance);
-  };
-})();
-
-Polymer.IronValidatableBehaviorMeta = null;
-
-Polymer.IronValidatableBehavior = {
-  properties: {
-    validator: {
-      type: String
-    },
-    invalid: {
-      notify: true,
-      reflectToAttribute: true,
-      type: Boolean,
-      value: false
-    },
-    _validatorMeta: {
-      type: Object
-    },
-    validatorType: {
-      type: String,
-      value: 'validator'
-    },
-    _validator: {
-      type: Object,
-      computed: '__computeValidator(validator)'
-    }
-  },
-  observers: [ '_invalidChanged(invalid)' ],
-  registered: function() {
-    Polymer.IronValidatableBehaviorMeta = new Polymer.IronMeta({
-      type: 'validator'
-    });
-  },
-  _invalidChanged: function() {
-    if (this.invalid) {
-      this.setAttribute('aria-invalid', 'true');
-    } else {
-      this.removeAttribute('aria-invalid');
-    }
-  },
-  hasValidator: function() {
-    return this._validator != null;
-  },
-  validate: function(value) {
-    this.invalid = !this._getValidity(value);
-    return !this.invalid;
-  },
-  _getValidity: function(value) {
-    if (this.hasValidator()) {
-      return this._validator.validate(value);
-    }
-    return true;
-  },
-  __computeValidator: function() {
-    return Polymer.IronValidatableBehaviorMeta && Polymer.IronValidatableBehaviorMeta.byKey(this.validator);
-  }
-};
-
-Polymer({
-  is: 'iron-input',
-  "extends": 'input',
-  behaviors: [ Polymer.IronValidatableBehavior ],
-  properties: {
-    bindValue: {
-      observer: '_bindValueChanged',
-      type: String
-    },
-    preventInvalidInput: {
-      type: Boolean
-    },
-    allowedPattern: {
-      type: String,
-      observer: "_allowedPatternChanged"
-    },
-    _previousValidInput: {
-      type: String,
-      value: ''
-    },
-    _patternAlreadyChecked: {
-      type: Boolean,
-      value: false
-    }
-  },
-  listeners: {
-    input: '_onInput',
-    keypress: '_onKeypress'
-  },
-  registered: function() {
-    if (!this._canDispatchEventOnDisabled()) {
-      this._origDispatchEvent = this.dispatchEvent;
-      this.dispatchEvent = this._dispatchEventFirefoxIE;
-    }
-  },
-  created: function() {
-    Polymer.IronA11yAnnouncer.requestAvailability();
-  },
-  _canDispatchEventOnDisabled: function() {
-    var input = document.createElement('input');
-    var canDispatch = false;
-    input.disabled = true;
-    input.addEventListener('feature-check-dispatch-event', function() {
-      canDispatch = true;
-    });
-    try {
-      input.dispatchEvent(new Event('feature-check-dispatch-event'));
-    } catch (e) {}
-    return canDispatch;
-  },
-  _dispatchEventFirefoxIE: function() {
-    var disabled = this.disabled;
-    this.disabled = false;
-    this._origDispatchEvent.apply(this, arguments);
-    this.disabled = disabled;
-  },
-  get _patternRegExp() {
-    var pattern;
-    if (this.allowedPattern) {
-      pattern = new RegExp(this.allowedPattern);
-    } else {
-      switch (this.type) {
-       case 'number':
-        pattern = /[0-9.,e-]/;
-        break;
-      }
-    }
-    return pattern;
-  },
-  ready: function() {
-    this.bindValue = this.value;
-  },
-  _bindValueChanged: function() {
-    if (this.value !== this.bindValue) {
-      this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
-    }
-    this.fire('bind-value-changed', {
-      value: this.bindValue
-    });
-  },
-  _allowedPatternChanged: function() {
-    this.preventInvalidInput = this.allowedPattern ? true : false;
-  },
-  _onInput: function() {
-    if (this.preventInvalidInput && !this._patternAlreadyChecked) {
-      var valid = this._checkPatternValidity();
-      if (!valid) {
-        this._announceInvalidCharacter('Invalid string of characters not entered.');
-        this.value = this._previousValidInput;
-      }
-    }
-    this.bindValue = this.value;
-    this._previousValidInput = this.value;
-    this._patternAlreadyChecked = false;
-  },
-  _isPrintable: function(event) {
-    var anyNonPrintable = event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 13 || event.keyCode == 27;
-    var mozNonPrintable = event.keyCode == 19 || event.keyCode == 20 || event.keyCode == 45 || event.keyCode == 46 || event.keyCode == 144 || event.keyCode == 145 || event.keyCode > 32 && event.keyCode < 41 || event.keyCode > 111 && event.keyCode < 124;
-    return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable);
-  },
-  _onKeypress: function(event) {
-    if (!this.preventInvalidInput && this.type !== 'number') {
-      return;
-    }
-    var regexp = this._patternRegExp;
-    if (!regexp) {
-      return;
-    }
-    if (event.metaKey || event.ctrlKey || event.altKey) return;
-    this._patternAlreadyChecked = true;
-    var thisChar = String.fromCharCode(event.charCode);
-    if (this._isPrintable(event) && !regexp.test(thisChar)) {
-      event.preventDefault();
-      this._announceInvalidCharacter('Invalid character ' + thisChar + ' not entered.');
-    }
-  },
-  _checkPatternValidity: function() {
-    var regexp = this._patternRegExp;
-    if (!regexp) {
-      return true;
-    }
-    for (var i = 0; i < this.value.length; i++) {
-      if (!regexp.test(this.value[i])) {
-        return false;
-      }
-    }
-    return true;
-  },
-  validate: function() {
-    var valid = this.checkValidity();
-    if (valid) {
-      if (this.required && this.value === '') {
-        valid = false;
-      } else if (this.hasValidator()) {
-        valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
-      }
-    }
-    this.invalid = !valid;
-    this.fire('iron-input-validate');
-    return valid;
-  },
-  _announceInvalidCharacter: function(message) {
-    this.fire('iron-announce', {
-      text: message
-    });
-  }
-});
-
-Polymer({
-  is: 'paper-input-container',
-  properties: {
-    noLabelFloat: {
-      type: Boolean,
-      value: false
-    },
-    alwaysFloatLabel: {
-      type: Boolean,
-      value: false
-    },
-    attrForValue: {
-      type: String,
-      value: 'bind-value'
-    },
-    autoValidate: {
-      type: Boolean,
-      value: false
-    },
-    invalid: {
-      observer: '_invalidChanged',
-      type: Boolean,
-      value: false
-    },
-    focused: {
-      readOnly: true,
-      type: Boolean,
-      value: false,
-      notify: true
-    },
-    _addons: {
-      type: Array
-    },
-    _inputHasContent: {
-      type: Boolean,
-      value: false
-    },
-    _inputSelector: {
-      type: String,
-      value: 'input,textarea,.paper-input-input'
-    },
-    _boundOnFocus: {
-      type: Function,
-      value: function() {
-        return this._onFocus.bind(this);
-      }
-    },
-    _boundOnBlur: {
-      type: Function,
-      value: function() {
-        return this._onBlur.bind(this);
-      }
-    },
-    _boundOnInput: {
-      type: Function,
-      value: function() {
-        return this._onInput.bind(this);
-      }
-    },
-    _boundValueChanged: {
-      type: Function,
-      value: function() {
-        return this._onValueChanged.bind(this);
-      }
-    }
-  },
-  listeners: {
-    'addon-attached': '_onAddonAttached',
-    'iron-input-validate': '_onIronInputValidate'
-  },
-  get _valueChangedEvent() {
-    return this.attrForValue + '-changed';
-  },
-  get _propertyForValue() {
-    return Polymer.CaseMap.dashToCamelCase(this.attrForValue);
-  },
-  get _inputElement() {
-    return Polymer.dom(this).querySelector(this._inputSelector);
-  },
-  get _inputElementValue() {
-    return this._inputElement[this._propertyForValue] || this._inputElement.value;
-  },
-  ready: function() {
-    if (!this._addons) {
-      this._addons = [];
-    }
-    this.addEventListener('focus', this._boundOnFocus, true);
-    this.addEventListener('blur', this._boundOnBlur, true);
-  },
-  attached: function() {
-    if (this.attrForValue) {
-      this._inputElement.addEventListener(this._valueChangedEvent, this._boundValueChanged);
-    } else {
-      this.addEventListener('input', this._onInput);
-    }
-    if (this._inputElementValue != '') {
-      this._handleValueAndAutoValidate(this._inputElement);
-    } else {
-      this._handleValue(this._inputElement);
-    }
-  },
-  _onAddonAttached: function(event) {
-    if (!this._addons) {
-      this._addons = [];
-    }
-    var target = event.target;
-    if (this._addons.indexOf(target) === -1) {
-      this._addons.push(target);
-      if (this.isAttached) {
-        this._handleValue(this._inputElement);
-      }
-    }
-  },
-  _onFocus: function() {
-    this._setFocused(true);
-  },
-  _onBlur: function() {
-    this._setFocused(false);
-    this._handleValueAndAutoValidate(this._inputElement);
-  },
-  _onInput: function(event) {
-    this._handleValueAndAutoValidate(event.target);
-  },
-  _onValueChanged: function(event) {
-    this._handleValueAndAutoValidate(event.target);
-  },
-  _handleValue: function(inputElement) {
-    var value = this._inputElementValue;
-    if (value || value === 0 || inputElement.type === 'number' && !inputElement.checkValidity()) {
-      this._inputHasContent = true;
-    } else {
-      this._inputHasContent = false;
-    }
-    this.updateAddons({
-      inputElement: inputElement,
-      value: value,
-      invalid: this.invalid
-    });
-  },
-  _handleValueAndAutoValidate: function(inputElement) {
-    if (this.autoValidate) {
-      var valid;
-      if (inputElement.validate) {
-        valid = inputElement.validate(this._inputElementValue);
-      } else {
-        valid = inputElement.checkValidity();
-      }
-      this.invalid = !valid;
-    }
-    this._handleValue(inputElement);
-  },
-  _onIronInputValidate: function(event) {
-    this.invalid = this._inputElement.invalid;
-  },
-  _invalidChanged: function() {
-    if (this._addons) {
-      this.updateAddons({
-        invalid: this.invalid
-      });
-    }
-  },
-  updateAddons: function(state) {
-    for (var addon, index = 0; addon = this._addons[index]; index++) {
-      addon.update(state);
-    }
-  },
-  _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid, _inputHasContent) {
-    var cls = 'input-content';
-    if (!noLabelFloat) {
-      var label = this.querySelector('label');
-      if (alwaysFloatLabel || _inputHasContent) {
-        cls += ' label-is-floating';
-        this.$.labelAndInputContainer.style.position = 'static';
-        if (invalid) {
-          cls += ' is-invalid';
-        } else if (focused) {
-          cls += " label-is-highlighted";
-        }
-      } else {
-        if (label) {
-          this.$.labelAndInputContainer.style.position = 'relative';
-        }
-      }
-    } else {
-      if (_inputHasContent) {
-        cls += ' label-is-hidden';
-      }
-    }
-    return cls;
-  },
-  _computeUnderlineClass: function(focused, invalid) {
-    var cls = 'underline';
-    if (invalid) {
-      cls += ' is-invalid';
-    } else if (focused) {
-      cls += ' is-highlighted';
-    }
-    return cls;
-  },
-  _computeAddOnContentClass: function(focused, invalid) {
-    var cls = 'add-on-content';
-    if (invalid) {
-      cls += ' is-invalid';
-    } else if (focused) {
-      cls += ' is-highlighted';
-    }
-    return cls;
-  }
-});
-
-Polymer.PaperSpinnerBehavior = {
-  listeners: {
-    animationend: '__reset',
-    webkitAnimationEnd: '__reset'
-  },
-  properties: {
-    active: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      observer: '__activeChanged'
-    },
-    alt: {
-      type: String,
-      value: 'loading',
-      observer: '__altChanged'
-    },
-    __coolingDown: {
-      type: Boolean,
-      value: false
-    }
-  },
-  __computeContainerClasses: function(active, coolingDown) {
-    return [ active || coolingDown ? 'active' : '', coolingDown ? 'cooldown' : '' ].join(' ');
-  },
-  __activeChanged: function(active, old) {
-    this.__setAriaHidden(!active);
-    this.__coolingDown = !active && old;
-  },
-  __altChanged: function(alt) {
-    if (alt === this.getPropertyInfo('alt').value) {
-      this.alt = this.getAttribute('aria-label') || alt;
-    } else {
-      this.__setAriaHidden(alt === '');
-      this.setAttribute('aria-label', alt);
-    }
-  },
-  __setAriaHidden: function(hidden) {
-    var attr = 'aria-hidden';
-    if (hidden) {
-      this.setAttribute(attr, 'true');
-    } else {
-      this.removeAttribute(attr);
-    }
-  },
-  __reset: function() {
-    this.active = false;
-    this.__coolingDown = false;
-  }
-};
-
-Polymer({
-  is: 'paper-spinner-lite',
-  behaviors: [ Polymer.PaperSpinnerBehavior ]
-});
-
+cr.define("downloads",function(){var Item=Polymer({is:"downloads-item",properties:{data:{type:Object},completelyOnDisk_:{computed:"computeCompletelyOnDisk_("+"data.state, data.file_externally_removed)",type:Boolean,value:true},controlledBy_:{computed:"computeControlledBy_(data.by_ext_id, data.by_ext_name)",type:String,value:""},isActive_:{computed:"computeIsActive_("+"data.state, data.file_externally_removed)",type:Boolean,value:true},isDangerous_:{computed:"computeIsDangerous_(data.state)",type:Boolean,value:false},isMalware_:{computed:"computeIsMalware_(isDangerous_, data.danger_type)",type:Boolean,value:false},isInProgress_:{computed:"computeIsInProgress_(data.state)",type:Boolean,value:false},pauseOrResumeText_:{computed:"computePauseOrResumeText_(isInProgress_, data.resume)",type:String},showCancel_:{computed:"computeShowCancel_(data.state)",type:Boolean,value:false},showProgress_:{computed:"computeShowProgress_(showCancel_, data.percent)",type:Boolean,value:false}},observers:["observeControlledBy_(controlledBy_)","observeIsDangerous_(isDangerous_, data)"],ready:function(){this.content=this.$.content},computeClass_:function(){var classes=[];if(this.isActive_)classes.push("is-active");if(this.isDangerous_)classes.push("dangerous");if(this.showProgress_)classes.push("show-progress");return classes.join(" ")},computeCompletelyOnDisk_:function(){return this.data.state==downloads.States.COMPLETE&&!this.data.file_externally_removed},computeControlledBy_:function(){if(!this.data.by_ext_id||!this.data.by_ext_name)return"";var url="chrome://extensions#"+this.data.by_ext_id;var name=this.data.by_ext_name;return loadTimeData.getStringF("controlledByUrl",url,name)},computeDangerIcon_:function(){if(!this.isDangerous_)return"";switch(this.data.danger_type){case downloads.DangerType.DANGEROUS_CONTENT:case downloads.DangerType.DANGEROUS_HOST:case downloads.DangerType.DANGEROUS_URL:case downloads.DangerType.POTENTIALLY_UNWANTED:case downloads.DangerType.UNCOMMON_CONTENT:return"downloads:remove-circle";default:return"cr:warning"}},computeDate_:function(){assert(typeof this.data.hideDate=="boolean");if(this.data.hideDate)return"";return assert(this.data.since_string||this.data.date_string)},computeDescription_:function(){var data=this.data;switch(data.state){case downloads.States.DANGEROUS:var fileName=data.file_name;switch(data.danger_type){case downloads.DangerType.DANGEROUS_FILE:return loadTimeData.getString("dangerFileDesc");case downloads.DangerType.DANGEROUS_URL:case downloads.DangerType.DANGEROUS_CONTENT:case downloads.DangerType.DANGEROUS_HOST:return loadTimeData.getString("dangerDownloadDesc");case downloads.DangerType.UNCOMMON_CONTENT:return loadTimeData.getString("dangerUncommonDesc");case downloads.DangerType.POTENTIALLY_UNWANTED:return loadTimeData.getString("dangerSettingsDesc")}break;case downloads.States.IN_PROGRESS:case downloads.States.PAUSED:return data.progress_status_text}return""},computeIsActive_:function(){return this.data.state!=downloads.States.CANCELLED&&this.data.state!=downloads.States.INTERRUPTED&&!this.data.file_externally_removed},computeIsDangerous_:function(){return this.data.state==downloads.States.DANGEROUS},computeIsInProgress_:function(){return this.data.state==downloads.States.IN_PROGRESS},computeIsMalware_:function(){return this.isDangerous_&&(this.data.danger_type==downloads.DangerType.DANGEROUS_CONTENT||this.data.danger_type==downloads.DangerType.DANGEROUS_HOST||this.data.danger_type==downloads.DangerType.DANGEROUS_URL||this.data.danger_type==downloads.DangerType.POTENTIALLY_UNWANTED)},computePauseOrResumeText_:function(){if(this.isInProgress_)return loadTimeData.getString("controlPause");if(this.data.resume)return loadTimeData.getString("controlResume");return""},computeRemoveStyle_:function(){var canDelete=loadTimeData.getBoolean("allowDeletingHistory");var hideRemove=this.isDangerous_||this.showCancel_||!canDelete;return hideRemove?"visibility: hidden":""},computeShowCancel_:function(){return this.data.state==downloads.States.IN_PROGRESS||this.data.state==downloads.States.PAUSED},computeShowProgress_:function(){return this.showCancel_&&this.data.percent>=-1},computeTag_:function(){switch(this.data.state){case downloads.States.CANCELLED:return loadTimeData.getString("statusCancelled");case downloads.States.INTERRUPTED:return this.data.last_reason_text;case downloads.States.COMPLETE:return this.data.file_externally_removed?loadTimeData.getString("statusRemoved"):""}return""},isIndeterminate_:function(){return this.data.percent==-1},observeControlledBy_:function(){this.$["controlled-by"].innerHTML=this.controlledBy_},observeIsDangerous_:function(){if(!this.data)return;if(this.isDangerous_){this.$.url.removeAttribute("href")}else{this.$.url.href=assert(this.data.url);var filePath=encodeURIComponent(this.data.file_path);var scaleFactor="?scale="+window.devicePixelRatio+"x";this.$["file-icon"].src="chrome://fileicon/"+filePath+scaleFactor}},onCancelTap_:function(){downloads.ActionService.getInstance().cancel(this.data.id)},onDiscardDangerousTap_:function(){downloads.ActionService.getInstance().discardDangerous(this.data.id)},onDragStart_:function(e){e.preventDefault();downloads.ActionService.getInstance().drag(this.data.id)},onFileLinkTap_:function(e){e.preventDefault();downloads.ActionService.getInstance().openFile(this.data.id)},onPauseOrResumeTap_:function(){if(this.isInProgress_)downloads.ActionService.getInstance().pause(this.data.id);else downloads.ActionService.getInstance().resume(this.data.id)},onRemoveTap_:function(){downloads.ActionService.getInstance().remove(this.data.id)},onRetryTap_:function(){downloads.ActionService.getInstance().download(this.data.url)},onSaveDangerousTap_:function(){downloads.ActionService.getInstance().saveDangerous(this.data.id)},onShowTap_:function(){downloads.ActionService.getInstance().show(this.data.id)}});return{Item:Item}});Polymer.PaperItemBehaviorImpl={hostAttributes:{role:"option",tabindex:"0"}};Polymer.PaperItemBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperItemBehaviorImpl];Polymer({is:"paper-item",behaviors:[Polymer.PaperItemBehavior]});Polymer.IronSelection=function(selectCallback){this.selection=[];this.selectCallback=selectCallback};Polymer.IronSelection.prototype={get:function(){return this.multi?this.selection.slice():this.selection[0]},clear:function(excludes){this.selection.slice().forEach(function(item){if(!excludes||excludes.indexOf(item)<0){this.setItemSelected(item,false)}},this)},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!=null){if(isSelected!==this.isSelected(item)){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}if(this.selectCallback){this.selectCallback(item,isSelected)}}}},select:function(item){if(this.multi){this.toggle(item)}else if(this.get()!==item){this.setItemSelected(this.get(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}};Polymer.IronSelectableBehavior={properties:{attrForSelected:{type:String,value:null},selected:{type:String,notify:true},selectedItem:{type:Object,readOnly:true,notify:true},activateEvent:{type:String,value:"tap",observer:"_activateEventChanged"},selectable:String,selectedClass:{type:String,value:"iron-selected"},selectedAttribute:{type:String,value:null},fallbackSelection:{type:String,value:null},items:{type:Array,readOnly:true,notify:true,value:function(){return[]}},_excludedLocalNames:{type:Object,value:function(){return{template:1}}}},observers:["_updateAttrForSelected(attrForSelected)","_updateSelected(selected)","_checkFallback(fallbackSelection)"],created:function(){this._bindFilterItem=this._filterItem.bind(this);this._selection=new Polymer.IronSelection(this._applySelection.bind(this))},attached:function(){this._observer=this._observeItems(this);this._updateItems();if(!this._shouldUpdateSelection){this._updateSelected()}this._addListener(this.activateEvent)},detached:function(){if(this._observer){Polymer.dom(this).unobserveNodes(this._observer)}this._removeListener(this.activateEvent)},indexOf:function(item){return this.items.indexOf(item)},select:function(value){this.selected=value},selectPrevious:function(){var length=this.items.length;var index=(Number(this._valueToIndex(this.selected))-1+length)%length;this.selected=this._indexToValue(index)},selectNext:function(){var index=(Number(this._valueToIndex(this.selected))+1)%this.items.length;this.selected=this._indexToValue(index)},selectIndex:function(index){this.select(this._indexToValue(index))},forceSynchronousItemUpdate:function(){this._updateItems()},get _shouldUpdateSelection(){return this.selected!=null},_checkFallback:function(){if(this._shouldUpdateSelection){this._updateSelected()}},_addListener:function(eventName){this.listen(this,eventName,"_activateHandler")},_removeListener:function(eventName){this.unlisten(this,eventName,"_activateHandler")},_activateEventChanged:function(eventName,old){this._removeListener(old);this._addListener(eventName)},_updateItems:function(){var nodes=Polymer.dom(this).queryDistributedElements(this.selectable||"*");nodes=Array.prototype.filter.call(nodes,this._bindFilterItem);this._setItems(nodes)},_updateAttrForSelected:function(){if(this._shouldUpdateSelection){this.selected=this._indexToValue(this.indexOf(this.selectedItem))}},_updateSelected:function(){this._selectSelected(this.selected)},_selectSelected:function(selected){this._selection.select(this._valueToItem(this.selected));if(this.fallbackSelection&&this.items.length&&this._selection.get()===undefined){this.selected=this.fallbackSelection}},_filterItem:function(node){return!this._excludedLocalNames[node.localName]},_valueToItem:function(value){return value==null?null:this.items[this._valueToIndex(value)]},_valueToIndex:function(value){if(this.attrForSelected){for(var i=0,item;item=this.items[i];i++){if(this._valueForItem(item)==value){return i}}}else{return Number(value)}},_indexToValue:function(index){if(this.attrForSelected){var item=this.items[index];if(item){return this._valueForItem(item)}}else{return index}},_valueForItem:function(item){var propValue=item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];return propValue!=undefined?propValue:item.getAttribute(this.attrForSelected)},_applySelection:function(item,isSelected){if(this.selectedClass){this.toggleClass(this.selectedClass,isSelected,item)}if(this.selectedAttribute){this.toggleAttribute(this.selectedAttribute,isSelected,item)}this._selectionChange();this.fire("iron-"+(isSelected?"select":"deselect"),{item:item})},_selectionChange:function(){this._setSelectedItem(this._selection.get())},_observeItems:function(node){return Polymer.dom(node).observeNodes(function(mutation){this._updateItems();if(this._shouldUpdateSelection){this._updateSelected()}this.fire("iron-items-changed",mutation,{bubbles:false,cancelable:false})})},_activateHandler:function(e){var t=e.target;var items=this.items;while(t&&t!=this){var i=items.indexOf(t);if(i>=0){var value=this._indexToValue(i);this._itemActivate(value,t);return}t=t.parentNode}},_itemActivate:function(value,item){if(!this.fire("iron-activate",{selected:value,item:item},{cancelable:true}).defaultPrevented){this.select(value)}}};Polymer.IronMultiSelectableBehaviorImpl={properties:{multi:{type:Boolean,value:false,observer:"multiChanged"},selectedValues:{type:Array,notify:true},selectedItems:{type:Array,readOnly:true,notify:true}},observers:["_updateSelected(selectedValues.splices)"],select:function(value){if(this.multi){if(this.selectedValues){this._toggleSelected(value)}else{this.selectedValues=[value]}}else{this.selected=value}},multiChanged:function(multi){this._selection.multi=multi},get _shouldUpdateSelection(){return this.selected!=null||this.selectedValues!=null&&this.selectedValues.length},_updateAttrForSelected:function(){if(!this.multi){Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this)}else if(this._shouldUpdateSelection){this.selectedValues=this.selectedItems.map(function(selectedItem){return this._indexToValue(this.indexOf(selectedItem))},this).filter(function(unfilteredValue){return unfilteredValue!=null},this)}},_updateSelected:function(){if(this.multi){this._selectMulti(this.selectedValues)}else{this._selectSelected(this.selected)}},_selectMulti:function(values){if(values){var selectedItems=this._valuesToItems(values);this._selection.clear(selectedItems);for(var i=0;i<selectedItems.length;i++){this._selection.setItemSelected(selectedItems[i],true)}if(this.fallbackSelection&&this.items.length&&!this._selection.get().length){var fallback=this._valueToItem(this.fallbackSelection);if(fallback){this.selectedValues=[this.fallbackSelection]}}}else{this._selection.clear()}},_selectionChange:function(){var s=this._selection.get();if(this.multi){this._setSelectedItems(s)}else{this._setSelectedItems([s]);this._setSelectedItem(s)}},_toggleSelected:function(value){var i=this.selectedValues.indexOf(value);var unselected=i<0;if(unselected){this.push("selectedValues",value)}else{this.splice("selectedValues",i,1)}},_valuesToItems:function(values){return values==null?null:values.map(function(value){return this._valueToItem(value)},this)}};Polymer.IronMultiSelectableBehavior=[Polymer.IronSelectableBehavior,Polymer.IronMultiSelectableBehaviorImpl];Polymer.IronMenuBehaviorImpl={properties:{focusedItem:{observer:"_focusedItemChanged",readOnly:true,type:Object},attrForItemTitle:{type:String}},hostAttributes:{role:"menu",tabindex:"0"},observers:["_updateMultiselectable(multi)"],listeners:{focus:"_onFocus",keydown:"_onKeydown","iron-items-changed":"_onIronItemsChanged"},keyBindings:{up:"_onUpKey",down:"_onDownKey",esc:"_onEscKey","shift+tab:keydown":"_onShiftTabDown"},attached:function(){this._resetTabindices()},select:function(value){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}var item=this._valueToItem(value);if(item&&item.hasAttribute("disabled"))return;this._setFocusedItem(item);Polymer.IronMultiSelectableBehaviorImpl.select.apply(this,arguments)},_resetTabindices:function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this.items.forEach(function(item){item.setAttribute("tabindex",item===selectedItem?"0":"-1")},this)},_updateMultiselectable:function(multi){if(multi){this.setAttribute("aria-multiselectable","true")}else{this.removeAttribute("aria-multiselectable")}},_focusWithKeyboardEvent:function(event){for(var i=0,item;item=this.items[i];i++){var attr=this.attrForItemTitle||"textContent";var title=item[attr]||item.getAttribute(attr);if(!item.hasAttribute("disabled")&&title&&title.trim().charAt(0).toLowerCase()===String.fromCharCode(event.keyCode).toLowerCase()){this._setFocusedItem(item);break}}},_focusPrevious:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex-i+length)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_focusNext:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex+i)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_applySelection:function(item,isSelected){if(isSelected){item.setAttribute("aria-selected","true")}else{item.removeAttribute("aria-selected")}Polymer.IronSelectableBehavior._applySelection.apply(this,arguments)},_focusedItemChanged:function(focusedItem,old){old&&old.setAttribute("tabindex","-1");if(focusedItem){focusedItem.setAttribute("tabindex","0");focusedItem.focus()}},_onIronItemsChanged:function(event){if(event.detail.addedNodes.length){this._resetTabindices()}},_onShiftTabDown:function(event){var oldTabIndex=this.getAttribute("tabindex");Polymer.IronMenuBehaviorImpl._shiftTabPressed=true;this._setFocusedItem(null);this.setAttribute("tabindex","-1");this.async(function(){this.setAttribute("tabindex",oldTabIndex);Polymer.IronMenuBehaviorImpl._shiftTabPressed=false},1)},_onFocus:function(event){if(Polymer.IronMenuBehaviorImpl._shiftTabPressed){return}var rootTarget=Polymer.dom(event).rootTarget;if(rootTarget!==this&&typeof rootTarget.tabIndex!=="undefined"&&!this.isLightDescendant(rootTarget)){return}this._defaultFocusAsync=this.async(function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this._setFocusedItem(null);if(selectedItem){this._setFocusedItem(selectedItem)}else if(this.items[0]){this._focusNext()}})},_onUpKey:function(event){this._focusPrevious();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this._focusNext();event.detail.keyboardEvent.preventDefault()},_onEscKey:function(event){this.focusedItem.blur()},_onKeydown:function(event){if(!this.keyboardEventMatchesKeys(event,"up down esc")){this._focusWithKeyboardEvent(event)}event.stopPropagation()},_activateHandler:function(event){Polymer.IronSelectableBehavior._activateHandler.call(this,event);event.stopPropagation()}};Polymer.IronMenuBehaviorImpl._shiftTabPressed=false;Polymer.IronMenuBehavior=[Polymer.IronMultiSelectableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronMenuBehaviorImpl];(function(){Polymer({is:"paper-menu",behaviors:[Polymer.IronMenuBehavior]})})();Polymer.IronFitBehavior={properties:{sizingTarget:{type:Object,value:function(){return this}},fitInto:{type:Object,value:window},noOverlap:{type:Boolean},positionTarget:{type:Element},horizontalAlign:{type:String},verticalAlign:{type:String},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},autoFitOnAttach:{type:Boolean,value:false},_fitInfo:{type:Object}},get _fitWidth(){var fitWidth;if(this.fitInto===window){fitWidth=this.fitInto.innerWidth}else{fitWidth=this.fitInto.getBoundingClientRect().width}return fitWidth},get _fitHeight(){var fitHeight;if(this.fitInto===window){fitHeight=this.fitInto.innerHeight}else{fitHeight=this.fitInto.getBoundingClientRect().height}return fitHeight},get _fitLeft(){var fitLeft;if(this.fitInto===window){fitLeft=0}else{fitLeft=this.fitInto.getBoundingClientRect().left}return fitLeft},get _fitTop(){var fitTop;if(this.fitInto===window){fitTop=0}else{fitTop=this.fitInto.getBoundingClientRect().top}return fitTop},get _defaultPositionTarget(){var parent=Polymer.dom(this).parentNode;if(parent&&parent.nodeType===Node.DOCUMENT_FRAGMENT_NODE){parent=parent.host}return parent},get _localeHorizontalAlign(){if(this._isRTL){if(this.horizontalAlign==="right"){return"left"}if(this.horizontalAlign==="left"){return"right"}}return this.horizontalAlign},attached:function(){this._isRTL=window.getComputedStyle(this).direction=="rtl";this.positionTarget=this.positionTarget||this._defaultPositionTarget;if(this.autoFitOnAttach){if(window.getComputedStyle(this).display==="none"){setTimeout(function(){this.fit()}.bind(this))}else{this.fit()}}},fit:function(){this.position();this.constrain();this.center()},_discoverInfo:function(){if(this._fitInfo){return}var target=window.getComputedStyle(this);var sizer=window.getComputedStyle(this.sizingTarget);this._fitInfo={inlineStyle:{top:this.style.top||"",left:this.style.left||"",position:this.style.position||""},sizerInlineStyle:{maxWidth:this.sizingTarget.style.maxWidth||"",maxHeight:this.sizingTarget.style.maxHeight||"",boxSizing:this.sizingTarget.style.boxSizing||""},positionedBy:{vertically:target.top!=="auto"?"top":target.bottom!=="auto"?"bottom":null,horizontally:target.left!=="auto"?"left":target.right!=="auto"?"right":null},sizedBy:{height:sizer.maxHeight!=="none",width:sizer.maxWidth!=="none",minWidth:parseInt(sizer.minWidth,10)||0,minHeight:parseInt(sizer.minHeight,10)||0},margin:{top:parseInt(target.marginTop,10)||0,right:parseInt(target.marginRight,10)||0,bottom:parseInt(target.marginBottom,10)||0,left:parseInt(target.marginLeft,10)||0}};if(this.verticalOffset){this._fitInfo.margin.top=this._fitInfo.margin.bottom=this.verticalOffset;this._fitInfo.inlineStyle.marginTop=this.style.marginTop||"";this._fitInfo.inlineStyle.marginBottom=this.style.marginBottom||"";this.style.marginTop=this.style.marginBottom=this.verticalOffset+"px"}if(this.horizontalOffset){this._fitInfo.margin.left=this._fitInfo.margin.right=this.horizontalOffset;this._fitInfo.inlineStyle.marginLeft=this.style.marginLeft||"";this._fitInfo.inlineStyle.marginRight=this.style.marginRight||"";this.style.marginLeft=this.style.marginRight=this.horizontalOffset+"px"}},resetFit:function(){var info=this._fitInfo||{};for(var property in info.sizerInlineStyle){this.sizingTarget.style[property]=info.sizerInlineStyle[property]}for(var property in info.inlineStyle){this.style[property]=info.inlineStyle[property]}this._fitInfo=null},refit:function(){var scrollLeft=this.sizingTarget.scrollLeft;var scrollTop=this.sizingTarget.scrollTop;this.resetFit();this.fit();this.sizingTarget.scrollLeft=scrollLeft;this.sizingTarget.scrollTop=scrollTop},position:function(){if(!this.horizontalAlign&&!this.verticalAlign){return}this._discoverInfo();this.style.position="fixed";this.sizingTarget.style.boxSizing="border-box";this.style.left="0px";this.style.top="0px";var rect=this.getBoundingClientRect();var positionRect=this.__getNormalizedRect(this.positionTarget);var fitRect=this.__getNormalizedRect(this.fitInto);var margin=this._fitInfo.margin;var size={width:rect.width+margin.left+margin.right,height:rect.height+margin.top+margin.bottom};var position=this.__getPosition(this._localeHorizontalAlign,this.verticalAlign,size,positionRect,fitRect);var left=position.left+margin.left;var top=position.top+margin.top;var right=Math.min(fitRect.right-margin.right,left+rect.width);var bottom=Math.min(fitRect.bottom-margin.bottom,top+rect.height);var minWidth=this._fitInfo.sizedBy.minWidth;var minHeight=this._fitInfo.sizedBy.minHeight;if(left<margin.left){left=margin.left;if(right-left<minWidth){left=right-minWidth}}if(top<margin.top){top=margin.top;if(bottom-top<minHeight){top=bottom-minHeight}}this.sizingTarget.style.maxWidth=right-left+"px";this.sizingTarget.style.maxHeight=bottom-top+"px";this.style.left=left-rect.left+"px";this.style.top=top-rect.top+"px"},constrain:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var info=this._fitInfo;if(!info.positionedBy.vertically){this.style.position="fixed";this.style.top="0px"}if(!info.positionedBy.horizontally){this.style.position="fixed";this.style.left="0px"}this.sizingTarget.style.boxSizing="border-box";var rect=this.getBoundingClientRect();if(!info.sizedBy.height){this.__sizeDimension(rect,info.positionedBy.vertically,"top","bottom","Height")}if(!info.sizedBy.width){this.__sizeDimension(rect,info.positionedBy.horizontally,"left","right","Width")}},_sizeDimension:function(rect,positionedBy,start,end,extent){this.__sizeDimension(rect,positionedBy,start,end,extent)},__sizeDimension:function(rect,positionedBy,start,end,extent){var info=this._fitInfo;var fitRect=this.__getNormalizedRect(this.fitInto);var max=extent==="Width"?fitRect.width:fitRect.height;var flip=positionedBy===end;var offset=flip?max-rect[end]:rect[start];var margin=info.margin[flip?start:end];var offsetExtent="offset"+extent;var sizingOffset=this[offsetExtent]-this.sizingTarget[offsetExtent];this.sizingTarget.style["max"+extent]=max-margin-offset-sizingOffset+"px"},center:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var positionedBy=this._fitInfo.positionedBy;if(positionedBy.vertically&&positionedBy.horizontally){return}this.style.position="fixed";if(!positionedBy.vertically){this.style.top="0px"}if(!positionedBy.horizontally){this.style.left="0px"}var rect=this.getBoundingClientRect();var fitRect=this.__getNormalizedRect(this.fitInto);if(!positionedBy.vertically){var top=fitRect.top-rect.top+(fitRect.height-rect.height)/2;this.style.top=top+"px"}if(!positionedBy.horizontally){var left=fitRect.left-rect.left+(fitRect.width-rect.width)/2;this.style.left=left+"px"}},__getNormalizedRect:function(target){if(target===document.documentElement||target===window){return{top:0,left:0,width:window.innerWidth,height:window.innerHeight,right:window.innerWidth,bottom:window.innerHeight}}return target.getBoundingClientRect()},__getCroppedArea:function(position,size,fitRect){var verticalCrop=Math.min(0,position.top)+Math.min(0,fitRect.bottom-(position.top+size.height));var horizontalCrop=Math.min(0,position.left)+Math.min(0,fitRect.right-(position.left+size.width));return Math.abs(verticalCrop)*size.width+Math.abs(horizontalCrop)*size.height},__getPosition:function(hAlign,vAlign,size,positionRect,fitRect){var positions=[{verticalAlign:"top",horizontalAlign:"left",top:positionRect.top,left:positionRect.left},{verticalAlign:"top",horizontalAlign:"right",top:positionRect.top,left:positionRect.right-size.width},{verticalAlign:"bottom",horizontalAlign:"left",top:positionRect.bottom-size.height,left:positionRect.left},{verticalAlign:"bottom",horizontalAlign:"right",top:positionRect.bottom-size.height,left:positionRect.right-size.width}];if(this.noOverlap){for(var i=0,l=positions.length;i<l;i++){var copy={};for(var key in positions[i]){copy[key]=positions[i][key]}positions.push(copy)}positions[0].top=positions[1].top+=positionRect.height;positions[2].top=positions[3].top-=positionRect.height;positions[4].left=positions[6].left+=positionRect.width;positions[5].left=positions[7].left-=positionRect.width}vAlign=vAlign==="auto"?null:vAlign;hAlign=hAlign==="auto"?null:hAlign;var position;for(var i=0;i<positions.length;i++){var pos=positions[i];if(!this.dynamicAlign&&!this.noOverlap&&pos.verticalAlign===vAlign&&pos.horizontalAlign===hAlign){position=pos;break}var alignOk=(!vAlign||pos.verticalAlign===vAlign)&&(!hAlign||pos.horizontalAlign===hAlign);if(!this.dynamicAlign&&!alignOk){continue}position=position||pos;pos.croppedArea=this.__getCroppedArea(pos,size,fitRect);var diff=pos.croppedArea-position.croppedArea;if(diff<0||diff===0&&alignOk){position=pos}if(position.croppedArea===0&&alignOk){break}}return position}};(function(){"use strict";Polymer({is:"iron-overlay-backdrop",properties:{opened:{reflectToAttribute:true,type:Boolean,value:false,observer:"_openedChanged"}},listeners:{transitionend:"_onTransitionend"},created:function(){this.__openedRaf=null},attached:function(){this.opened&&this._openedChanged(this.opened)},prepare:function(){if(this.opened&&!this.parentNode){Polymer.dom(document.body).appendChild(this)}},open:function(){this.opened=true},close:function(){this.opened=false},complete:function(){if(!this.opened&&this.parentNode===document.body){Polymer.dom(this.parentNode).removeChild(this)}},_onTransitionend:function(event){if(event&&event.target===this){this.complete()}},_openedChanged:function(opened){if(opened){this.prepare()}else{var cs=window.getComputedStyle(this);if(cs.transitionDuration==="0s"||cs.opacity==0){this.complete()}}if(!this.isAttached){return}if(this.__openedRaf){window.cancelAnimationFrame(this.__openedRaf);this.__openedRaf=null}this.scrollTop=this.scrollTop;this.__openedRaf=window.requestAnimationFrame(function(){this.__openedRaf=null;this.toggleClass("opened",this.opened)}.bind(this))}})})();Polymer.IronOverlayManagerClass=function(){this._overlays=[];this._minimumZ=101;this._backdropElement=null;Polymer.Gestures.add(document,"tap",this._onCaptureClick.bind(this));document.addEventListener("focus",this._onCaptureFocus.bind(this),true);document.addEventListener("keydown",this._onCaptureKeyDown.bind(this),true)};Polymer.IronOverlayManagerClass.prototype={constructor:Polymer.IronOverlayManagerClass,get backdropElement(){if(!this._backdropElement){this._backdropElement=document.createElement("iron-overlay-backdrop")}return this._backdropElement},get deepActiveElement(){var active=document.activeElement||document.body;while(active.root&&Polymer.dom(active.root).activeElement){active=Polymer.dom(active.root).activeElement}return active},_bringOverlayAtIndexToFront:function(i){var overlay=this._overlays[i];if(!overlay){return}var lastI=this._overlays.length-1;var currentOverlay=this._overlays[lastI];if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){lastI--}if(i>=lastI){return}var minimumZ=Math.max(this.currentOverlayZ(),this._minimumZ);if(this._getZ(overlay)<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}while(i<lastI){this._overlays[i]=this._overlays[i+1];i++}this._overlays[lastI]=overlay},addOrRemoveOverlay:function(overlay){if(overlay.opened){this.addOverlay(overlay)}else{this.removeOverlay(overlay)}},addOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i>=0){this._bringOverlayAtIndexToFront(i);this.trackBackdrop();return}var insertionIndex=this._overlays.length;var currentOverlay=this._overlays[insertionIndex-1];var minimumZ=Math.max(this._getZ(currentOverlay),this._minimumZ);var newZ=this._getZ(overlay);if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){this._applyOverlayZ(currentOverlay,minimumZ);insertionIndex--;var previousOverlay=this._overlays[insertionIndex-1];minimumZ=Math.max(this._getZ(previousOverlay),this._minimumZ)}if(newZ<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}this._overlays.splice(insertionIndex,0,overlay);this.trackBackdrop()},removeOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i===-1){return}this._overlays.splice(i,1);this.trackBackdrop()},currentOverlay:function(){var i=this._overlays.length-1;return this._overlays[i]},currentOverlayZ:function(){return this._getZ(this.currentOverlay())},ensureMinimumZ:function(minimumZ){this._minimumZ=Math.max(this._minimumZ,minimumZ)},focusOverlay:function(){var current=this.currentOverlay();if(current){current._applyFocus()}},trackBackdrop:function(){var overlay=this._overlayWithBackdrop();if(!overlay&&!this._backdropElement){return}this.backdropElement.style.zIndex=this._getZ(overlay)-1;this.backdropElement.opened=!!overlay},getBackdrops:function(){var backdrops=[];for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){backdrops.push(this._overlays[i])}}return backdrops},backdropZ:function(){return this._getZ(this._overlayWithBackdrop())-1},_overlayWithBackdrop:function(){for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){return this._overlays[i]}}},_getZ:function(overlay){var z=this._minimumZ;if(overlay){var z1=Number(overlay.style.zIndex||window.getComputedStyle(overlay).zIndex);if(z1===z1){z=z1}}return z},_setZ:function(element,z){element.style.zIndex=z},_applyOverlayZ:function(overlay,aboveZ){this._setZ(overlay,aboveZ+2)},_overlayInPath:function(path){path=path||[];for(var i=0;i<path.length;i++){if(path[i]._manager===this){return path[i]}}},_onCaptureClick:function(event){var overlay=this.currentOverlay();if(overlay&&this._overlayInPath(Polymer.dom(event).path)!==overlay){overlay._onCaptureClick(event)}},_onCaptureFocus:function(event){var overlay=this.currentOverlay();if(overlay){overlay._onCaptureFocus(event)}},_onCaptureKeyDown:function(event){var overlay=this.currentOverlay();if(overlay){if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"esc")){overlay._onCaptureEsc(event)}else if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"tab")){overlay._onCaptureTab(event)}}},_shouldBeBehindOverlay:function(overlay1,overlay2){return!overlay1.alwaysOnTop&&overlay2.alwaysOnTop}};Polymer.IronOverlayManager=new Polymer.IronOverlayManagerClass;(function(){"use strict";Polymer.IronOverlayBehaviorImpl={properties:{opened:{observer:"_openedChanged",type:Boolean,value:false,notify:true},canceled:{observer:"_canceledChanged",readOnly:true,
+type:Boolean,value:false},withBackdrop:{observer:"_withBackdropChanged",type:Boolean},noAutoFocus:{type:Boolean,value:false},noCancelOnEscKey:{type:Boolean,value:false},noCancelOnOutsideClick:{type:Boolean,value:false},closingReason:{type:Object},restoreFocusOnClose:{type:Boolean,value:false},alwaysOnTop:{type:Boolean},_manager:{type:Object,value:Polymer.IronOverlayManager},_focusedChild:{type:Object}},listeners:{"iron-resize":"_onIronResize"},get backdropElement(){return this._manager.backdropElement},get _focusNode(){return this._focusedChild||Polymer.dom(this).querySelector("[autofocus]")||this},get _focusableNodes(){var FOCUSABLE_WITH_DISABLED=["a[href]","area[href]","iframe","[tabindex]","[contentEditable=true]"];var FOCUSABLE_WITHOUT_DISABLED=["input","select","textarea","button"];var selector=FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),')+':not([tabindex="-1"]),'+FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),')+':not([disabled]):not([tabindex="-1"])';var focusables=Polymer.dom(this).querySelectorAll(selector);if(this.tabIndex>=0){focusables.splice(0,0,this)}return focusables.sort(function(a,b){if(a.tabIndex===b.tabIndex){return 0}if(a.tabIndex===0||a.tabIndex>b.tabIndex){return 1}return-1})},ready:function(){this.__isAnimating=false;this.__shouldRemoveTabIndex=false;this.__firstFocusableNode=this.__lastFocusableNode=null;this.__raf=null;this.__restoreFocusNode=null;this._ensureSetup()},attached:function(){if(this.opened){this._openedChanged(this.opened)}this._observer=Polymer.dom(this).observeNodes(this._onNodesChange)},detached:function(){Polymer.dom(this).unobserveNodes(this._observer);this._observer=null;if(this.__raf){window.cancelAnimationFrame(this.__raf);this.__raf=null}this._manager.removeOverlay(this)},toggle:function(){this._setCanceled(false);this.opened=!this.opened},open:function(){this._setCanceled(false);this.opened=true},close:function(){this._setCanceled(false);this.opened=false},cancel:function(event){var cancelEvent=this.fire("iron-overlay-canceled",event,{cancelable:true});if(cancelEvent.defaultPrevented){return}this._setCanceled(true);this.opened=false},_ensureSetup:function(){if(this._overlaySetup){return}this._overlaySetup=true;this.style.outline="none";this.style.display="none"},_openedChanged:function(opened){if(opened){this.removeAttribute("aria-hidden")}else{this.setAttribute("aria-hidden","true")}if(!this.isAttached){return}this.__isAnimating=true;this.__onNextAnimationFrame(this.__openedChanged)},_canceledChanged:function(){this.closingReason=this.closingReason||{};this.closingReason.canceled=this.canceled},_withBackdropChanged:function(){if(this.withBackdrop&&!this.hasAttribute("tabindex")){this.setAttribute("tabindex","-1");this.__shouldRemoveTabIndex=true}else if(this.__shouldRemoveTabIndex){this.removeAttribute("tabindex");this.__shouldRemoveTabIndex=false}if(this.opened&&this.isAttached){this._manager.trackBackdrop()}},_prepareRenderOpened:function(){this.__restoreFocusNode=this._manager.deepActiveElement;this._preparePositioning();this.refit();this._finishPositioning();if(this.noAutoFocus&&document.activeElement===this._focusNode){this._focusNode.blur();this.__restoreFocusNode.focus()}},_renderOpened:function(){this._finishRenderOpened()},_renderClosed:function(){this._finishRenderClosed()},_finishRenderOpened:function(){this.notifyResize();this.__isAnimating=false;var focusableNodes=this._focusableNodes;this.__firstFocusableNode=focusableNodes[0];this.__lastFocusableNode=focusableNodes[focusableNodes.length-1];this.fire("iron-overlay-opened")},_finishRenderClosed:function(){this.style.display="none";this.style.zIndex="";this.notifyResize();this.__isAnimating=false;this.fire("iron-overlay-closed",this.closingReason)},_preparePositioning:function(){this.style.transition=this.style.webkitTransition="none";this.style.transform=this.style.webkitTransform="none";this.style.display=""},_finishPositioning:function(){this.style.display="none";this.scrollTop=this.scrollTop;this.style.transition=this.style.webkitTransition="";this.style.transform=this.style.webkitTransform="";this.style.display="";this.scrollTop=this.scrollTop},_applyFocus:function(){if(this.opened){if(!this.noAutoFocus){this._focusNode.focus()}}else{this._focusNode.blur();this._focusedChild=null;if(this.restoreFocusOnClose&&this.__restoreFocusNode){this.__restoreFocusNode.focus()}this.__restoreFocusNode=null;var currentOverlay=this._manager.currentOverlay();if(currentOverlay&&this!==currentOverlay){currentOverlay._applyFocus()}}},_onCaptureClick:function(event){if(!this.noCancelOnOutsideClick){this.cancel(event)}},_onCaptureFocus:function(event){if(!this.withBackdrop){return}var path=Polymer.dom(event).path;if(path.indexOf(this)===-1){event.stopPropagation();this._applyFocus()}else{this._focusedChild=path[0]}},_onCaptureEsc:function(event){if(!this.noCancelOnEscKey){this.cancel(event)}},_onCaptureTab:function(event){if(!this.withBackdrop){return}var shift=event.shiftKey;var nodeToCheck=shift?this.__firstFocusableNode:this.__lastFocusableNode;var nodeToSet=shift?this.__lastFocusableNode:this.__firstFocusableNode;var shouldWrap=false;if(nodeToCheck===nodeToSet){shouldWrap=true}else{var focusedNode=this._manager.deepActiveElement;shouldWrap=focusedNode===nodeToCheck||focusedNode===this}if(shouldWrap){event.preventDefault();this._focusedChild=nodeToSet;this._applyFocus()}},_onIronResize:function(){if(this.opened&&!this.__isAnimating){this.__onNextAnimationFrame(this.refit)}},_onNodesChange:function(){if(this.opened&&!this.__isAnimating){this.notifyResize()}},__openedChanged:function(){if(this.opened){this._prepareRenderOpened();this._manager.addOverlay(this);this._applyFocus();this._renderOpened()}else{this._manager.removeOverlay(this);this._applyFocus();this._renderClosed()}},__onNextAnimationFrame:function(callback){if(this.__raf){window.cancelAnimationFrame(this.__raf)}var self=this;this.__raf=window.requestAnimationFrame(function nextAnimationFrame(){self.__raf=null;callback.call(self)})}};Polymer.IronOverlayBehavior=[Polymer.IronFitBehavior,Polymer.IronResizableBehavior,Polymer.IronOverlayBehaviorImpl]})();Polymer.NeonAnimatableBehavior={properties:{animationConfig:{type:Object},entryAnimation:{observer:"_entryAnimationChanged",type:String},exitAnimation:{observer:"_exitAnimationChanged",type:String}},_entryAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["entry"]=[{name:this.entryAnimation,node:this}]},_exitAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["exit"]=[{name:this.exitAnimation,node:this}]},_copyProperties:function(config1,config2){for(var property in config2){config1[property]=config2[property]}},_cloneConfig:function(config){var clone={isClone:true};this._copyProperties(clone,config);return clone},_getAnimationConfigRecursive:function(type,map,allConfigs){if(!this.animationConfig){return}if(this.animationConfig.value&&typeof this.animationConfig.value==="function"){this._warn(this._logf("playAnimation","Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));return}var thisConfig;if(type){thisConfig=this.animationConfig[type]}else{thisConfig=this.animationConfig}if(!Array.isArray(thisConfig)){thisConfig=[thisConfig]}if(thisConfig){for(var config,index=0;config=thisConfig[index];index++){if(config.animatable){config.animatable._getAnimationConfigRecursive(config.type||type,map,allConfigs)}else{if(config.id){var cachedConfig=map[config.id];if(cachedConfig){if(!cachedConfig.isClone){map[config.id]=this._cloneConfig(cachedConfig);cachedConfig=map[config.id]}this._copyProperties(cachedConfig,config)}else{map[config.id]=config}}else{allConfigs.push(config)}}}}},getAnimationConfig:function(type){var map={};var allConfigs=[];this._getAnimationConfigRecursive(type,map,allConfigs);for(var key in map){allConfigs.push(map[key])}return allConfigs}};Polymer.NeonAnimationRunnerBehaviorImpl={_configureAnimations:function(configs){var results=[];if(configs.length>0){for(var config,index=0;config=configs[index];index++){var neonAnimation=document.createElement(config.name);if(neonAnimation.isNeonAnimation){var result=null;try{result=neonAnimation.configure(config);if(typeof result.cancel!="function"){result=document.timeline.play(result)}}catch(e){result=null;console.warn("Couldnt play","(",config.name,").",e)}if(result){results.push({neonAnimation:neonAnimation,config:config,animation:result})}}else{console.warn(this.is+":",config.name,"not found!")}}}return results},_shouldComplete:function(activeEntries){var finished=true;for(var i=0;i<activeEntries.length;i++){if(activeEntries[i].animation.playState!="finished"){finished=false;break}}return finished},_complete:function(activeEntries){for(var i=0;i<activeEntries.length;i++){activeEntries[i].neonAnimation.complete(activeEntries[i].config)}for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.cancel()}},playAnimation:function(type,cookie){var configs=this.getAnimationConfig(type);if(!configs){return}this._active=this._active||{};if(this._active[type]){this._complete(this._active[type]);delete this._active[type]}var activeEntries=this._configureAnimations(configs);if(activeEntries.length==0){this.fire("neon-animation-finish",cookie,{bubbles:false});return}this._active[type]=activeEntries;for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.onfinish=function(){if(this._shouldComplete(activeEntries)){this._complete(activeEntries);delete this._active[type];this.fire("neon-animation-finish",cookie,{bubbles:false})}}.bind(this)}},cancelAnimation:function(){for(var k in this._animations){this._animations[k].cancel()}this._animations={}}};Polymer.NeonAnimationRunnerBehavior=[Polymer.NeonAnimatableBehavior,Polymer.NeonAnimationRunnerBehaviorImpl];Polymer.NeonAnimationBehavior={properties:{animationTiming:{type:Object,value:function(){return{duration:500,easing:"cubic-bezier(0.4, 0, 0.2, 1)",fill:"both"}}}},isNeonAnimation:true,timingFromConfig:function(config){if(config.timing){for(var property in config.timing){this.animationTiming[property]=config.timing[property]}}return this.animationTiming},setPrefixedProperty:function(node,property,value){var map={transform:["webkitTransform"],transformOrigin:["mozTransformOrigin","webkitTransformOrigin"]};var prefixes=map[property];for(var prefix,index=0;prefix=prefixes[index];index++){node.style[prefix]=value}node.style[property]=value},complete:function(){}};Polymer({is:"opaque-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"1"}],this.timingFromConfig(config));node.style.opacity="0";return this._effect},complete:function(config){config.node.style.opacity=""}});(function(){"use strict";var LAST_TOUCH_POSITION={pageX:0,pageY:0};var ROOT_TARGET=null;var SCROLLABLE_NODES=[];Polymer.IronDropdownScrollManager={get currentLockingElement(){return this._lockingElements[this._lockingElements.length-1]},elementIsScrollLocked:function(element){var currentLockingElement=this.currentLockingElement;if(currentLockingElement===undefined)return false;var scrollLocked;if(this._hasCachedLockedElement(element)){return true}if(this._hasCachedUnlockedElement(element)){return false}scrollLocked=!!currentLockingElement&&currentLockingElement!==element&&!this._composedTreeContains(currentLockingElement,element);if(scrollLocked){this._lockedElementCache.push(element)}else{this._unlockedElementCache.push(element)}return scrollLocked},pushScrollLock:function(element){if(this._lockingElements.indexOf(element)>=0){return}if(this._lockingElements.length===0){this._lockScrollInteractions()}this._lockingElements.push(element);this._lockedElementCache=[];this._unlockedElementCache=[]},removeScrollLock:function(element){var index=this._lockingElements.indexOf(element);if(index===-1){return}this._lockingElements.splice(index,1);this._lockedElementCache=[];this._unlockedElementCache=[];if(this._lockingElements.length===0){this._unlockScrollInteractions()}},_lockingElements:[],_lockedElementCache:null,_unlockedElementCache:null,_hasCachedLockedElement:function(element){return this._lockedElementCache.indexOf(element)>-1},_hasCachedUnlockedElement:function(element){return this._unlockedElementCache.indexOf(element)>-1},_composedTreeContains:function(element,child){var contentElements;var distributedNodes;var contentIndex;var nodeIndex;if(element.contains(child)){return true}contentElements=Polymer.dom(element).querySelectorAll("content");for(contentIndex=0;contentIndex<contentElements.length;++contentIndex){distributedNodes=Polymer.dom(contentElements[contentIndex]).getDistributedNodes();for(nodeIndex=0;nodeIndex<distributedNodes.length;++nodeIndex){if(this._composedTreeContains(distributedNodes[nodeIndex],child)){return true}}}return false},_scrollInteractionHandler:function(event){if(event.cancelable&&this._shouldPreventScrolling(event)){event.preventDefault()}if(event.targetTouches){var touch=event.targetTouches[0];LAST_TOUCH_POSITION.pageX=touch.pageX;LAST_TOUCH_POSITION.pageY=touch.pageY}},_lockScrollInteractions:function(){this._boundScrollHandler=this._boundScrollHandler||this._scrollInteractionHandler.bind(this);document.addEventListener("wheel",this._boundScrollHandler,true);document.addEventListener("mousewheel",this._boundScrollHandler,true);document.addEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.addEventListener("touchstart",this._boundScrollHandler,true);document.addEventListener("touchmove",this._boundScrollHandler,true)},_unlockScrollInteractions:function(){document.removeEventListener("wheel",this._boundScrollHandler,true);document.removeEventListener("mousewheel",this._boundScrollHandler,true);document.removeEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.removeEventListener("touchstart",this._boundScrollHandler,true);document.removeEventListener("touchmove",this._boundScrollHandler,true)},_shouldPreventScrolling:function(event){var target=Polymer.dom(event).rootTarget;if(event.type!=="touchmove"&&ROOT_TARGET!==target){ROOT_TARGET=target;SCROLLABLE_NODES=this._getScrollableNodes(Polymer.dom(event).path)}if(!SCROLLABLE_NODES.length){return true}if(event.type==="touchstart"){return false}var info=this._getScrollInfo(event);return!this._getScrollingNode(SCROLLABLE_NODES,info.deltaX,info.deltaY)},_getScrollableNodes:function(nodes){var scrollables=[];var lockingIndex=nodes.indexOf(this.currentLockingElement);for(var i=0;i<=lockingIndex;i++){var node=nodes[i];if(node.nodeType===11){continue}var style=node.style;if(style.overflow!=="scroll"&&style.overflow!=="auto"){style=window.getComputedStyle(node)}if(style.overflow==="scroll"||style.overflow==="auto"){scrollables.push(node)}}return scrollables},_getScrollingNode:function(nodes,deltaX,deltaY){if(!deltaX&&!deltaY){return}var verticalScroll=Math.abs(deltaY)>=Math.abs(deltaX);for(var i=0;i<nodes.length;i++){var node=nodes[i];var canScroll=false;if(verticalScroll){canScroll=deltaY<0?node.scrollTop>0:node.scrollTop<node.scrollHeight-node.clientHeight}else{canScroll=deltaX<0?node.scrollLeft>0:node.scrollLeft<node.scrollWidth-node.clientWidth}if(canScroll){return node}}},_getScrollInfo:function(event){var info={deltaX:event.deltaX,deltaY:event.deltaY};if("deltaX"in event){}else if("wheelDeltaX"in event){info.deltaX=-event.wheelDeltaX;info.deltaY=-event.wheelDeltaY}else if("axis"in event){info.deltaX=event.axis===1?event.detail:0;info.deltaY=event.axis===2?event.detail:0}else if(event.targetTouches){var touch=event.targetTouches[0];info.deltaX=LAST_TOUCH_POSITION.pageX-touch.pageX;info.deltaY=LAST_TOUCH_POSITION.pageY-touch.pageY}return info}}})();(function(){"use strict";Polymer({is:"iron-dropdown",behaviors:[Polymer.IronControlState,Polymer.IronA11yKeysBehavior,Polymer.IronOverlayBehavior,Polymer.NeonAnimationRunnerBehavior],properties:{horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},openAnimationConfig:{type:Object},closeAnimationConfig:{type:Object},focusTarget:{type:Object},noAnimations:{type:Boolean,value:false},allowOutsideScroll:{type:Boolean,value:false},_boundOnCaptureScroll:{type:Function,value:function(){return this._onCaptureScroll.bind(this)}}},listeners:{"neon-animation-finish":"_onNeonAnimationFinish"},observers:["_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)"],get containedElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},get _focusTarget(){return this.focusTarget||this.containedElement},ready:function(){this._scrollTop=0;this._scrollLeft=0;this._refitOnScrollRAF=null},attached:function(){if(!this.sizingTarget||this.sizingTarget===this){this.sizingTarget=this.containedElement}},detached:function(){this.cancelAnimation();document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)},_openedChanged:function(){if(this.opened&&this.disabled){this.cancel()}else{this.cancelAnimation();this._updateAnimationConfig();this._saveScrollPosition();if(this.opened){document.addEventListener("scroll",this._boundOnCaptureScroll);!this.allowOutsideScroll&&Polymer.IronDropdownScrollManager.pushScrollLock(this)}else{document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)}Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this,arguments)}},_renderOpened:function(){if(!this.noAnimations&&this.animationConfig.open){this.$.contentWrapper.classList.add("animating");this.playAnimation("open")}else{Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this,arguments)}},_renderClosed:function(){if(!this.noAnimations&&this.animationConfig.close){this.$.contentWrapper.classList.add("animating");this.playAnimation("close")}else{Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this,arguments)}},_onNeonAnimationFinish:function(){this.$.contentWrapper.classList.remove("animating");if(this.opened){this._finishRenderOpened()}else{this._finishRenderClosed()}},_onCaptureScroll:function(){if(!this.allowOutsideScroll){this._restoreScrollPosition()}else{this._refitOnScrollRAF&&window.cancelAnimationFrame(this._refitOnScrollRAF);this._refitOnScrollRAF=window.requestAnimationFrame(this.refit.bind(this))}},_saveScrollPosition:function(){if(document.scrollingElement){this._scrollTop=document.scrollingElement.scrollTop;this._scrollLeft=document.scrollingElement.scrollLeft}else{this._scrollTop=Math.max(document.documentElement.scrollTop,document.body.scrollTop);this._scrollLeft=Math.max(document.documentElement.scrollLeft,document.body.scrollLeft)}},_restoreScrollPosition:function(){if(document.scrollingElement){document.scrollingElement.scrollTop=this._scrollTop;document.scrollingElement.scrollLeft=this._scrollLeft}else{document.documentElement.scrollTop=this._scrollTop;document.documentElement.scrollLeft=this._scrollLeft;document.body.scrollTop=this._scrollTop;document.body.scrollLeft=this._scrollLeft}},_updateAnimationConfig:function(){var animations=(this.openAnimationConfig||[]).concat(this.closeAnimationConfig||[]);for(var i=0;i<animations.length;i++){animations[i].node=this.containedElement}this.animationConfig={open:this.openAnimationConfig,close:this.closeAnimationConfig}},_updateOverlayPosition:function(){if(this.isAttached){this.notifyResize()}},_applyFocus:function(){var focusTarget=this.focusTarget||this.containedElement;if(focusTarget&&this.opened&&!this.noAutoFocus){focusTarget.focus()}else{Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this,arguments)}}})})();Polymer({is:"fade-in-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"0"},{opacity:"1"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"fade-out-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"0"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;this._effect=new KeyframeEffect(node,[{height:height/2+"px"},{height:height+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width/2+"px"},{width:width+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width+"px"},{width:width-width/20+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;var top=rect.top;this.setPrefixedProperty(node,"transformOrigin","0 0");this._effect=new KeyframeEffect(node,[{height:height+"px",transform:"translateY(0)"},{height:height/2+"px",transform:"translateY(-20px)"}],this.timingFromConfig(config));return this._effect}});(function(){"use strict";var config={ANIMATION_CUBIC_BEZIER:"cubic-bezier(.3,.95,.5,1)",MAX_ANIMATION_TIME_MS:400};var PaperMenuButton=Polymer({is:"paper-menu-button",behaviors:[Polymer.IronA11yKeysBehavior,Polymer.IronControlState],properties:{opened:{type:Boolean,value:false,notify:true,observer:"_openedChanged"},horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},noOverlap:{type:Boolean},noAnimations:{type:Boolean,value:false},ignoreSelect:{type:Boolean,value:false},closeOnActivate:{type:Boolean,value:false},openAnimationConfig:{type:Object,value:function(){return[{name:"fade-in-animation",timing:{delay:100,duration:200}},{name:"paper-menu-grow-width-animation",timing:{delay:100,duration:150,easing:config.ANIMATION_CUBIC_BEZIER}},{name:"paper-menu-grow-height-animation",timing:{delay:100,duration:275,easing:config.ANIMATION_CUBIC_BEZIER}}]}},closeAnimationConfig:{type:Object,value:function(){return[{name:"fade-out-animation",timing:{duration:150}},{name:"paper-menu-shrink-width-animation",timing:{delay:100,duration:50,easing:config.ANIMATION_CUBIC_BEZIER}},{name:"paper-menu-shrink-height-animation",timing:{duration:200,easing:"ease-in"}}]}},allowOutsideScroll:{type:Boolean,value:false},restoreFocusOnClose:{type:Boolean,value:true},_dropdownContent:{type:Object}},hostAttributes:{role:"group","aria-haspopup":"true"},listeners:{"iron-activate":"_onIronActivate","iron-select":"_onIronSelect"},get contentElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},toggle:function(){if(this.opened){this.close()}else{this.open()}},open:function(){if(this.disabled){return}this.$.dropdown.open()},close:function(){this.$.dropdown.close()},_onIronSelect:function(event){if(!this.ignoreSelect){this.close()}},_onIronActivate:function(event){if(this.closeOnActivate){this.close()}},_openedChanged:function(opened,oldOpened){if(opened){this._dropdownContent=this.contentElement;this.fire("paper-dropdown-open")}else if(oldOpened!=null){this.fire("paper-dropdown-close")}},_disabledChanged:function(disabled){Polymer.IronControlState._disabledChanged.apply(this,arguments);if(disabled&&this.opened){this.close()}},__onIronOverlayCanceled:function(event){var uiEvent=event.detail;var target=Polymer.dom(uiEvent).rootTarget;var trigger=this.$.trigger;var path=Polymer.dom(uiEvent).path;if(path.indexOf(trigger)>-1){event.preventDefault()}}});Object.keys(config).forEach(function(key){PaperMenuButton[key]=config[key]});Polymer.PaperMenuButton=PaperMenuButton})();Polymer.PaperInkyFocusBehaviorImpl={observers:["_focusedChanged(receivedFocusFromKeyboard)"],_focusedChanged:function(receivedFocusFromKeyboard){if(receivedFocusFromKeyboard){this.ensureRipple()}if(this.hasRipple()){this._ripple.holdDown=receivedFocusFromKeyboard}},_createRipple:function(){var ripple=Polymer.PaperRippleBehavior._createRipple();ripple.id="ink";ripple.setAttribute("center","");ripple.classList.add("circle");return ripple}};Polymer.PaperInkyFocusBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperInkyFocusBehaviorImpl];Polymer({is:"paper-icon-button",hostAttributes:{role:"button",tabindex:"0"},behaviors:[Polymer.PaperInkyFocusBehavior],properties:{src:{type:String},icon:{type:String},alt:{type:String,observer:"_altChanged"}},_altChanged:function(newValue,oldValue){var label=this.getAttribute("aria-label");if(!label||oldValue==label){this.setAttribute("aria-label",newValue)}}});Polymer({is:"iron-media-query",properties:{queryMatches:{type:Boolean,value:false,readOnly:true,notify:true},query:{type:String,observer:"queryChanged"},full:{type:Boolean,value:false},_boundMQHandler:{value:function(){return this.queryHandler.bind(this)}},_mq:{value:null}},attached:function(){this.style.display="none";this.queryChanged()},detached:function(){this._remove()},_add:function(){if(this._mq){this._mq.addListener(this._boundMQHandler)}},_remove:function(){if(this._mq){this._mq.removeListener(this._boundMQHandler)}this._mq=null},queryChanged:function(){this._remove();var query=this.query;if(!query){return}if(!this.full&&query[0]!=="("){query="("+query+")"}this._mq=window.matchMedia(query);this._add();this.queryHandler(this._mq)},queryHandler:function(mq){this._setQueryMatches(mq.matches)}});(function(){"use strict";Polymer.IronA11yAnnouncer=Polymer({is:"iron-a11y-announcer",properties:{mode:{type:String,value:"polite"},_text:{type:String,value:""}},created:function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=this}document.body.addEventListener("iron-announce",this._onIronAnnounce.bind(this))},announce:function(text){this._text="";this.async(function(){this._text=text},100)},_onIronAnnounce:function(event){if(event.detail&&event.detail.text){this.announce(event.detail.text)}}});Polymer.IronA11yAnnouncer.instance=null;Polymer.IronA11yAnnouncer.requestAvailability=function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=document.createElement("iron-a11y-announcer")}document.body.appendChild(Polymer.IronA11yAnnouncer.instance)}})();Polymer.IronValidatableBehaviorMeta=null;Polymer.IronValidatableBehavior={properties:{validator:{type:String},invalid:{notify:true,reflectToAttribute:true,type:Boolean,value:false},_validatorMeta:{type:Object},validatorType:{type:String,value:"validator"},_validator:{type:Object,computed:"__computeValidator(validator)"}},observers:["_invalidChanged(invalid)"],registered:function(){Polymer.IronValidatableBehaviorMeta=new Polymer.IronMeta({type:"validator"})},_invalidChanged:function(){if(this.invalid){this.setAttribute("aria-invalid","true")}else{this.removeAttribute("aria-invalid")}},hasValidator:function(){return this._validator!=null},validate:function(value){this.invalid=!this._getValidity(value);return!this.invalid},_getValidity:function(value){if(this.hasValidator()){return this._validator.validate(value)}return true},__computeValidator:function(){return Polymer.IronValidatableBehaviorMeta&&Polymer.IronValidatableBehaviorMeta.byKey(this.validator)}};Polymer({is:"iron-input","extends":"input",behaviors:[Polymer.IronValidatableBehavior],properties:{bindValue:{observer:"_bindValueChanged",type:String},preventInvalidInput:{type:Boolean},allowedPattern:{type:String,observer:"_allowedPatternChanged"},_previousValidInput:{type:String,value:""},_patternAlreadyChecked:{type:Boolean,value:false}},listeners:{input:"_onInput",keypress:"_onKeypress"},registered:function(){if(!this._canDispatchEventOnDisabled()){this._origDispatchEvent=this.dispatchEvent;this.dispatchEvent=this._dispatchEventFirefoxIE}},created:function(){Polymer.IronA11yAnnouncer.requestAvailability()},_canDispatchEventOnDisabled:function(){var input=document.createElement("input");var canDispatch=false;input.disabled=true;input.addEventListener("feature-check-dispatch-event",function(){canDispatch=true});try{input.dispatchEvent(new Event("feature-check-dispatch-event"))}catch(e){}return canDispatch},_dispatchEventFirefoxIE:function(){var disabled=this.disabled;this.disabled=false;this._origDispatchEvent.apply(this,arguments);this.disabled=disabled},get _patternRegExp(){var pattern;if(this.allowedPattern){pattern=new RegExp(this.allowedPattern)}else{switch(this.type){case"number":pattern=/[0-9.,e-]/;break}}return pattern},ready:function(){this.bindValue=this.value},_bindValueChanged:function(){if(this.value!==this.bindValue){this.value=!(this.bindValue||this.bindValue===0||this.bindValue===false)?"":this.bindValue}this.fire("bind-value-changed",{value:this.bindValue})},_allowedPatternChanged:function(){this.preventInvalidInput=this.allowedPattern?true:false},_onInput:function(){if(this.preventInvalidInput&&!this._patternAlreadyChecked){var valid=this._checkPatternValidity();if(!valid){this._announceInvalidCharacter("Invalid string of characters not entered.");this.value=this._previousValidInput}}this.bindValue=this.value;this._previousValidInput=this.value;this._patternAlreadyChecked=false},_isPrintable:function(event){var anyNonPrintable=event.keyCode==8||event.keyCode==9||event.keyCode==13||event.keyCode==27;var mozNonPrintable=event.keyCode==19||event.keyCode==20||event.keyCode==45||event.keyCode==46||event.keyCode==144||event.keyCode==145||event.keyCode>32&&event.keyCode<41||event.keyCode>111&&event.keyCode<124;return!anyNonPrintable&&!(event.charCode==0&&mozNonPrintable)},_onKeypress:function(event){if(!this.preventInvalidInput&&this.type!=="number"){return}var regexp=this._patternRegExp;if(!regexp){return}if(event.metaKey||event.ctrlKey||event.altKey)return;this._patternAlreadyChecked=true;var thisChar=String.fromCharCode(event.charCode);if(this._isPrintable(event)&&!regexp.test(thisChar)){event.preventDefault();this._announceInvalidCharacter("Invalid character "+thisChar+" not entered.")}},_checkPatternValidity:function(){var regexp=this._patternRegExp;if(!regexp){return true}for(var i=0;i<this.value.length;i++){if(!regexp.test(this.value[i])){return false}}return true},validate:function(){var valid=this.checkValidity();if(valid){if(this.required&&this.value===""){valid=false}else if(this.hasValidator()){valid=Polymer.IronValidatableBehavior.validate.call(this,this.value)}}this.invalid=!valid;this.fire("iron-input-validate");return valid},_announceInvalidCharacter:function(message){this.fire("iron-announce",{text:message})}});Polymer({is:"paper-input-container",properties:{noLabelFloat:{type:Boolean,value:false},alwaysFloatLabel:{type:Boolean,value:false},attrForValue:{type:String,value:"bind-value"},autoValidate:{type:Boolean,value:false},invalid:{observer:"_invalidChanged",type:Boolean,value:false},focused:{readOnly:true,type:Boolean,value:false,notify:true},_addons:{type:Array},_inputHasContent:{type:Boolean,value:false},_inputSelector:{type:String,value:"input,textarea,.paper-input-input"},_boundOnFocus:{type:Function,value:function(){return this._onFocus.bind(this)}},_boundOnBlur:{type:Function,value:function(){return this._onBlur.bind(this)}},_boundOnInput:{type:Function,value:function(){return this._onInput.bind(this)}},_boundValueChanged:{
+type:Function,value:function(){return this._onValueChanged.bind(this)}}},listeners:{"addon-attached":"_onAddonAttached","iron-input-validate":"_onIronInputValidate"},get _valueChangedEvent(){return this.attrForValue+"-changed"},get _propertyForValue(){return Polymer.CaseMap.dashToCamelCase(this.attrForValue)},get _inputElement(){return Polymer.dom(this).querySelector(this._inputSelector)},get _inputElementValue(){return this._inputElement[this._propertyForValue]||this._inputElement.value},ready:function(){if(!this._addons){this._addons=[]}this.addEventListener("focus",this._boundOnFocus,true);this.addEventListener("blur",this._boundOnBlur,true)},attached:function(){if(this.attrForValue){this._inputElement.addEventListener(this._valueChangedEvent,this._boundValueChanged)}else{this.addEventListener("input",this._onInput)}if(this._inputElementValue!=""){this._handleValueAndAutoValidate(this._inputElement)}else{this._handleValue(this._inputElement)}},_onAddonAttached:function(event){if(!this._addons){this._addons=[]}var target=event.target;if(this._addons.indexOf(target)===-1){this._addons.push(target);if(this.isAttached){this._handleValue(this._inputElement)}}},_onFocus:function(){this._setFocused(true)},_onBlur:function(){this._setFocused(false);this._handleValueAndAutoValidate(this._inputElement)},_onInput:function(event){this._handleValueAndAutoValidate(event.target)},_onValueChanged:function(event){this._handleValueAndAutoValidate(event.target)},_handleValue:function(inputElement){var value=this._inputElementValue;if(value||value===0||inputElement.type==="number"&&!inputElement.checkValidity()){this._inputHasContent=true}else{this._inputHasContent=false}this.updateAddons({inputElement:inputElement,value:value,invalid:this.invalid})},_handleValueAndAutoValidate:function(inputElement){if(this.autoValidate){var valid;if(inputElement.validate){valid=inputElement.validate(this._inputElementValue)}else{valid=inputElement.checkValidity()}this.invalid=!valid}this._handleValue(inputElement)},_onIronInputValidate:function(event){this.invalid=this._inputElement.invalid},_invalidChanged:function(){if(this._addons){this.updateAddons({invalid:this.invalid})}},updateAddons:function(state){for(var addon,index=0;addon=this._addons[index];index++){addon.update(state)}},_computeInputContentClass:function(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent){var cls="input-content";if(!noLabelFloat){var label=this.querySelector("label");if(alwaysFloatLabel||_inputHasContent){cls+=" label-is-floating";this.$.labelAndInputContainer.style.position="static";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" label-is-highlighted"}}else{if(label){this.$.labelAndInputContainer.style.position="relative"}}}else{if(_inputHasContent){cls+=" label-is-hidden"}}return cls},_computeUnderlineClass:function(focused,invalid){var cls="underline";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls},_computeAddOnContentClass:function(focused,invalid){var cls="add-on-content";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls}});Polymer.PaperSpinnerBehavior={listeners:{animationend:"__reset",webkitAnimationEnd:"__reset"},properties:{active:{type:Boolean,value:false,reflectToAttribute:true,observer:"__activeChanged"},alt:{type:String,value:"loading",observer:"__altChanged"},__coolingDown:{type:Boolean,value:false}},__computeContainerClasses:function(active,coolingDown){return[active||coolingDown?"active":"",coolingDown?"cooldown":""].join(" ")},__activeChanged:function(active,old){this.__setAriaHidden(!active);this.__coolingDown=!active&&old},__altChanged:function(alt){if(alt===this.getPropertyInfo("alt").value){this.alt=this.getAttribute("aria-label")||alt}else{this.__setAriaHidden(alt==="");this.setAttribute("aria-label",alt)}},__setAriaHidden:function(hidden){var attr="aria-hidden";if(hidden){this.setAttribute(attr,"true")}else{this.removeAttribute(attr)}},__reset:function(){this.active=false;this.__coolingDown=false}};Polymer({is:"paper-spinner-lite",behaviors:[Polymer.PaperSpinnerBehavior]});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-var CrSearchFieldBehavior = {
-  properties: {
-    label: {
-      type: String,
-      value: ''
-    },
-    clearLabel: {
-      type: String,
-      value: ''
-    },
-    showingSearch: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: 'showingSearchChanged_',
-      reflectToAttribute: true
-    },
-    lastValue_: {
-      type: String,
-      value: ''
-    }
-  },
-  getSearchInput: function() {},
-  getValue: function() {
-    return this.getSearchInput().value;
-  },
-  setValue: function(value) {
-    this.getSearchInput().bindValue = value;
-    this.onValueChanged_(value);
-  },
-  showAndFocus: function() {
-    this.showingSearch = true;
-    this.focus_();
-  },
-  focus_: function() {
-    this.getSearchInput().focus();
-  },
-  onSearchTermSearch: function() {
-    this.onValueChanged_(this.getValue());
-  },
-  onValueChanged_: function(newValue) {
-    if (newValue == this.lastValue_) return;
-    this.fire('search-changed', newValue);
-    this.lastValue_ = newValue;
-  },
-  onSearchTermKeydown: function(e) {
-    if (e.key == 'Escape') this.showingSearch = false;
-  },
-  showingSearchChanged_: function() {
-    if (this.showingSearch) {
-      this.focus_();
-      return;
-    }
-    this.setValue('');
-    this.getSearchInput().blur();
-  }
-};
-
+var CrSearchFieldBehavior={properties:{label:{type:String,value:""},clearLabel:{type:String,value:""},showingSearch:{type:Boolean,value:false,notify:true,observer:"showingSearchChanged_",reflectToAttribute:true},lastValue_:{type:String,value:""}},getSearchInput:function(){},getValue:function(){return this.getSearchInput().value},setValue:function(value){this.getSearchInput().bindValue=value;this.onValueChanged_(value)},showAndFocus:function(){this.showingSearch=true;this.focus_()},focus_:function(){this.getSearchInput().focus()},onSearchTermSearch:function(){this.onValueChanged_(this.getValue())},onValueChanged_:function(newValue){if(newValue==this.lastValue_)return;this.fire("search-changed",newValue);this.lastValue_=newValue},onSearchTermKeydown:function(e){if(e.key=="Escape")this.showingSearch=false},showingSearchChanged_:function(){if(this.showingSearch){this.focus_();return}this.setValue("");this.getSearchInput().blur()}};
 // Copyright 2016 The Chromium 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({
-  is: 'cr-toolbar-search-field',
-  behaviors: [ CrSearchFieldBehavior ],
-  properties: {
-    narrow: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    label: String,
-    clearLabel: String,
-    spinnerActive: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    hasSearchText_: Boolean,
-    isSpinnerShown_: {
-      type: Boolean,
-      computed: 'computeIsSpinnerShown_(spinnerActive, showingSearch)'
-    }
-  },
-  listeners: {
-    tap: 'showSearch_',
-    'searchInput.bind-value-changed': 'onBindValueChanged_'
-  },
-  getSearchInput: function() {
-    return this.$.searchInput;
-  },
-  isSearchFocused: function() {
-    return this.$.searchTerm.focused;
-  },
-  computeIconTabIndex_: function(narrow) {
-    return narrow ? 0 : -1;
-  },
-  computeIsSpinnerShown_: function() {
-    return this.spinnerActive && this.showingSearch;
-  },
-  onInputBlur_: function() {
-    if (!this.hasSearchText_) this.showingSearch = false;
-  },
-  onBindValueChanged_: function() {
-    var newValue = this.$.searchInput.bindValue;
-    this.hasSearchText_ = newValue != '';
-    if (newValue != '') this.showingSearch = true;
-  },
-  showSearch_: function(e) {
-    if (e.target != this.$.clearSearch) this.showingSearch = true;
-  },
-  hideSearch_: function(e) {
-    this.showingSearch = false;
-    e.stopPropagation();
-  }
-});
-
+Polymer({is:"cr-toolbar-search-field",behaviors:[CrSearchFieldBehavior],properties:{narrow:{type:Boolean,reflectToAttribute:true},label:String,clearLabel:String,spinnerActive:{type:Boolean,reflectToAttribute:true},hasSearchText_:Boolean,isSpinnerShown_:{type:Boolean,computed:"computeIsSpinnerShown_(spinnerActive, showingSearch)"}},listeners:{tap:"showSearch_","searchInput.bind-value-changed":"onBindValueChanged_"},getSearchInput:function(){return this.$.searchInput},isSearchFocused:function(){return this.$.searchTerm.focused},computeIconTabIndex_:function(narrow){return narrow?0:-1},computeIsSpinnerShown_:function(){return this.spinnerActive&&this.showingSearch},onInputBlur_:function(){if(!this.hasSearchText_)this.showingSearch=false},onBindValueChanged_:function(){var newValue=this.$.searchInput.bindValue;this.hasSearchText_=newValue!="";if(newValue!="")this.showingSearch=true},showSearch_:function(e){if(e.target!=this.$.clearSearch)this.showingSearch=true},hideSearch_:function(e){this.showingSearch=false;e.stopPropagation()}});
 // Copyright 2016 The Chromium 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({
-  is: 'cr-toolbar',
-  properties: {
-    pageName: String,
-    searchPrompt: String,
-    clearLabel: String,
-    menuLabel: String,
-    menuPromo: String,
-    spinnerActive: Boolean,
-    showMenu: {
-      type: Boolean,
-      value: false
-    },
-    showMenuPromo: {
-      type: Boolean,
-      value: false
-    },
-    closeMenuPromo: String,
-    narrow_: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    showingSearch_: {
-      type: Boolean,
-      reflectToAttribute: true
-    }
-  },
-  observers: [ 'possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)' ],
-  getSearchField: function() {
-    return this.$.search;
-  },
-  onClosePromoTap_: function() {
-    this.showMenuPromo = false;
-  },
-  onMenuTap_: function() {
-    this.fire('cr-menu-tap');
-    this.onClosePromoTap_();
-  },
-  possiblyShowMenuPromo_: function() {
-    Polymer.RenderStatus.afterNextRender(this, function() {
-      if (this.showMenu && this.showMenuPromo && !this.showingSearch_) {
-        this.$$('#menuPromo').animate({
-          opacity: [ 0, .9 ]
-        }, {
-          duration: 500,
-          fill: 'forwards'
-        });
-        this.fire('cr-menu-promo-shown');
-      }
-    }.bind(this));
-  },
-  titleIfNotShowMenuPromo_: function(title, showMenuPromo) {
-    return showMenuPromo ? '' : title;
-  }
-});
-
+Polymer({is:"cr-toolbar",properties:{pageName:String,searchPrompt:String,clearLabel:String,menuLabel:String,menuPromo:String,spinnerActive:Boolean,showMenu:{type:Boolean,value:false},showMenuPromo:{type:Boolean,value:false},closeMenuPromo:String,narrow_:{type:Boolean,reflectToAttribute:true},showingSearch_:{type:Boolean,reflectToAttribute:true}},observers:["possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)"],getSearchField:function(){return this.$.search},onClosePromoTap_:function(){this.showMenuPromo=false},onMenuTap_:function(){this.fire("cr-menu-tap");this.onClosePromoTap_()},possiblyShowMenuPromo_:function(){Polymer.RenderStatus.afterNextRender(this,function(){if(this.showMenu&&this.showMenuPromo&&!this.showingSearch_){this.$$("#menuPromo").animate({opacity:[0,.9]},{duration:500,fill:"forwards"});this.fire("cr-menu-promo-shown")}}.bind(this))},titleIfNotShowMenuPromo_:function(title,showMenuPromo){return showMenuPromo?"":title}});
 // 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.
-cr.define('downloads', function() {
-  var Toolbar = Polymer({
-    is: 'downloads-toolbar',
-    properties: {
-      downloadsShowing: {
-        reflectToAttribute: true,
-        type: Boolean,
-        value: false,
-        observer: 'downloadsShowingChanged_'
-      },
-      spinnerActive: {
-        type: Boolean,
-        notify: true
-      }
-    },
-    listeners: {
-      'paper-dropdown-close': 'onPaperDropdownClose_',
-      'paper-dropdown-open': 'onPaperDropdownOpen_'
-    },
-    canUndo: function() {
-      return !this.$.toolbar.getSearchField().isSearchFocused();
-    },
-    canClearAll: function() {
-      return !this.$.toolbar.getSearchField().getValue() && this.downloadsShowing;
-    },
-    onFindCommand: function() {
-      this.$.toolbar.getSearchField().showAndFocus();
-    },
-    closeMoreActions_: function() {
-      this.$.more.close();
-    },
-    downloadsShowingChanged_: function() {
-      this.updateClearAll_();
-    },
-    onClearAllTap_: function() {
-      assert(this.canClearAll());
-      downloads.ActionService.getInstance().clearAll();
-    },
-    onPaperDropdownClose_: function() {
-      window.removeEventListener('resize', assert(this.boundClose_));
-    },
-    onItemBlur_: function(e) {
-      var menu = this.$$('paper-menu');
-      if (menu.items.indexOf(e.relatedTarget) >= 0) return;
-      this.$.more.restoreFocusOnClose = false;
-      this.closeMoreActions_();
-      this.$.more.restoreFocusOnClose = true;
-    },
-    onPaperDropdownOpen_: function() {
-      this.boundClose_ = this.boundClose_ || this.closeMoreActions_.bind(this);
-      window.addEventListener('resize', this.boundClose_);
-    },
-    onSearchChanged_: function(event) {
-      var actionService = downloads.ActionService.getInstance();
-      if (actionService.search(event.detail)) this.spinnerActive = actionService.isSearching();
-      this.updateClearAll_();
-    },
-    onOpenDownloadsFolderTap_: function() {
-      downloads.ActionService.getInstance().openDownloadsFolder();
-    },
-    updateClearAll_: function() {
-      this.$$('paper-menu .clear-all').hidden = !this.canClearAll();
-    }
-  });
-  return {
-    Toolbar: Toolbar
-  };
-});
-
+cr.define("downloads",function(){var Toolbar=Polymer({is:"downloads-toolbar",properties:{downloadsShowing:{reflectToAttribute:true,type:Boolean,value:false,observer:"downloadsShowingChanged_"},spinnerActive:{type:Boolean,notify:true}},listeners:{"paper-dropdown-close":"onPaperDropdownClose_","paper-dropdown-open":"onPaperDropdownOpen_"},canUndo:function(){return!this.$.toolbar.getSearchField().isSearchFocused()},canClearAll:function(){return!this.$.toolbar.getSearchField().getValue()&&this.downloadsShowing},onFindCommand:function(){this.$.toolbar.getSearchField().showAndFocus()},closeMoreActions_:function(){this.$.more.close()},downloadsShowingChanged_:function(){this.updateClearAll_()},onClearAllTap_:function(){assert(this.canClearAll());downloads.ActionService.getInstance().clearAll()},onPaperDropdownClose_:function(){window.removeEventListener("resize",assert(this.boundClose_))},onItemBlur_:function(e){var menu=this.$$("paper-menu");if(menu.items.indexOf(e.relatedTarget)>=0)return;this.$.more.restoreFocusOnClose=false;this.closeMoreActions_();this.$.more.restoreFocusOnClose=true},onPaperDropdownOpen_:function(){this.boundClose_=this.boundClose_||this.closeMoreActions_.bind(this);window.addEventListener("resize",this.boundClose_)},onSearchChanged_:function(event){var actionService=downloads.ActionService.getInstance();if(actionService.search(event.detail))this.spinnerActive=actionService.isSearching();this.updateClearAll_()},onOpenDownloadsFolderTap_:function(){downloads.ActionService.getInstance().openDownloadsFolder()},updateClearAll_:function(){this.$$("paper-menu .clear-all").hidden=!this.canClearAll()}});return{Toolbar:Toolbar}});
 // 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.
-cr.define('downloads', function() {
-  var Manager = Polymer({
-    is: 'downloads-manager',
-    properties: {
-      hasDownloads_: {
-        observer: 'hasDownloadsChanged_',
-        type: Boolean
-      },
-      hasShadow_: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true
-      },
-      items_: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      spinnerActive_: {
-        type: Boolean,
-        notify: true
-      }
-    },
-    hostAttributes: {
-      loading: true
-    },
-    listeners: {
-      'downloads-list.scroll': 'onListScroll_'
-    },
-    observers: [ 'itemsChanged_(items_.*)' ],
-    clearAll_: function() {
-      this.set('items_', []);
-    },
-    hasDownloadsChanged_: function() {
-      if (loadTimeData.getBoolean('allowDeletingHistory')) this.$.toolbar.downloadsShowing = this.hasDownloads_;
-      if (this.hasDownloads_) {
-        this.$['downloads-list'].fire('iron-resize');
-      } else {
-        var isSearching = downloads.ActionService.getInstance().isSearching();
-        var messageToShow = isSearching ? 'noSearchResults' : 'noDownloads';
-        this.$['no-downloads'].querySelector('span').textContent = loadTimeData.getString(messageToShow);
-      }
-    },
-    insertItems_: function(index, list) {
-      this.splice.apply(this, [ 'items_', index, 0 ].concat(list));
-      this.updateHideDates_(index, index + list.length);
-      this.removeAttribute('loading');
-      this.spinnerActive_ = false;
-    },
-    itemsChanged_: function() {
-      this.hasDownloads_ = this.items_.length > 0;
-    },
-    onCanExecute_: function(e) {
-      e = e;
-      switch (e.command.id) {
-       case 'undo-command':
-        e.canExecute = this.$.toolbar.canUndo();
-        break;
-
-       case 'clear-all-command':
-        e.canExecute = this.$.toolbar.canClearAll();
-        break;
-
-       case 'find-command':
-        e.canExecute = true;
-        break;
-      }
-    },
-    onCommand_: function(e) {
-      if (e.command.id == 'clear-all-command') downloads.ActionService.getInstance().clearAll(); else if (e.command.id == 'undo-command') downloads.ActionService.getInstance().undo(); else if (e.command.id == 'find-command') this.$.toolbar.onFindCommand();
-    },
-    onListScroll_: function() {
-      var list = this.$['downloads-list'];
-      if (list.scrollHeight - list.scrollTop - list.offsetHeight <= 100) {
-        downloads.ActionService.getInstance().loadMore();
-      }
-      this.hasShadow_ = list.scrollTop > 0;
-    },
-    onLoad_: function() {
-      cr.ui.decorate('command', cr.ui.Command);
-      document.addEventListener('canExecute', this.onCanExecute_.bind(this));
-      document.addEventListener('command', this.onCommand_.bind(this));
-      downloads.ActionService.getInstance().loadMore();
-    },
-    removeItem_: function(index) {
-      this.splice('items_', index, 1);
-      this.updateHideDates_(index, index);
-      this.onListScroll_();
-    },
-    updateHideDates_: function(start, end) {
-      for (var i = start; i <= end; ++i) {
-        var current = this.items_[i];
-        if (!current) continue;
-        var prev = this.items_[i - 1];
-        current.hideDate = !!prev && prev.date_string == current.date_string;
-      }
-    },
-    updateItem_: function(index, data) {
-      this.set('items_.' + index, data);
-      this.updateHideDates_(index, index);
-      var list = this.$['downloads-list'];
-      list.updateSizeForItem(index);
-    }
-  });
-  Manager.clearAll = function() {
-    Manager.get().clearAll_();
-  };
-  Manager.get = function() {
-    return queryRequiredElement('downloads-manager');
-  };
-  Manager.insertItems = function(index, list) {
-    Manager.get().insertItems_(index, list);
-  };
-  Manager.onLoad = function() {
-    Manager.get().onLoad_();
-  };
-  Manager.removeItem = function(index) {
-    Manager.get().removeItem_(index);
-  };
-  Manager.updateItem = function(index, data) {
-    Manager.get().updateItem_(index, data);
-  };
-  return {
-    Manager: Manager
-  };
-});
-
+cr.define("downloads",function(){var Manager=Polymer({is:"downloads-manager",properties:{hasDownloads_:{observer:"hasDownloadsChanged_",type:Boolean},hasShadow_:{type:Boolean,value:false,reflectToAttribute:true},items_:{type:Array,value:function(){return[]}},spinnerActive_:{type:Boolean,notify:true}},hostAttributes:{loading:true},listeners:{"downloads-list.scroll":"onListScroll_"},observers:["itemsChanged_(items_.*)"],clearAll_:function(){this.set("items_",[])},hasDownloadsChanged_:function(){if(loadTimeData.getBoolean("allowDeletingHistory"))this.$.toolbar.downloadsShowing=this.hasDownloads_;if(this.hasDownloads_){this.$["downloads-list"].fire("iron-resize")}else{var isSearching=downloads.ActionService.getInstance().isSearching();var messageToShow=isSearching?"noSearchResults":"noDownloads";this.$["no-downloads"].querySelector("span").textContent=loadTimeData.getString(messageToShow)}},insertItems_:function(index,list){this.splice.apply(this,["items_",index,0].concat(list));this.updateHideDates_(index,index+list.length);this.removeAttribute("loading");this.spinnerActive_=false},itemsChanged_:function(){this.hasDownloads_=this.items_.length>0},onCanExecute_:function(e){e=e;switch(e.command.id){case"undo-command":e.canExecute=this.$.toolbar.canUndo();break;case"clear-all-command":e.canExecute=this.$.toolbar.canClearAll();break;case"find-command":e.canExecute=true;break}},onCommand_:function(e){if(e.command.id=="clear-all-command")downloads.ActionService.getInstance().clearAll();else if(e.command.id=="undo-command")downloads.ActionService.getInstance().undo();else if(e.command.id=="find-command")this.$.toolbar.onFindCommand()},onListScroll_:function(){var list=this.$["downloads-list"];if(list.scrollHeight-list.scrollTop-list.offsetHeight<=100){downloads.ActionService.getInstance().loadMore()}this.hasShadow_=list.scrollTop>0},onLoad_:function(){cr.ui.decorate("command",cr.ui.Command);document.addEventListener("canExecute",this.onCanExecute_.bind(this));document.addEventListener("command",this.onCommand_.bind(this));downloads.ActionService.getInstance().loadMore()},removeItem_:function(index){this.splice("items_",index,1);this.updateHideDates_(index,index);this.onListScroll_()},updateHideDates_:function(start,end){for(var i=start;i<=end;++i){var current=this.items_[i];if(!current)continue;var prev=this.items_[i-1];current.hideDate=!!prev&&prev.date_string==current.date_string}},updateItem_:function(index,data){this.set("items_."+index,data);this.updateHideDates_(index,index);var list=this.$["downloads-list"];list.updateSizeForItem(index)}});Manager.clearAll=function(){Manager.get().clearAll_()};Manager.get=function(){return queryRequiredElement("downloads-manager")};Manager.insertItems=function(index,list){Manager.get().insertItems_(index,list)};Manager.onLoad=function(){Manager.get().onLoad_()};Manager.removeItem=function(index){Manager.get().removeItem_(index)};Manager.updateItem=function(index,data){Manager.get().updateItem_(index,data)};return{Manager:Manager}});
 // 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.
-window.addEventListener('load', function() {
-  downloads.Manager.onLoad();
-  document.fonts.load('bold 12px Roboto');
-});
+window.addEventListener("load",function(){downloads.Manager.onLoad();document.fonts.load("bold 12px Roboto")});
\ No newline at end of file
diff --git a/chrome/browser/resources/md_downloads/vulcanized.html b/chrome/browser/resources/md_downloads/vulcanized.html
index 2a45dc6..b810aaa 100644
--- a/chrome/browser/resources/md_downloads/vulcanized.html
+++ b/chrome/browser/resources/md_downloads/vulcanized.html
@@ -1082,7 +1082,8 @@
 
 #content:not(.is-active) {
   background: rgba(255, 255, 255, .6);
-        box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .03), 0 1px 4px 0 rgba(0, 0, 0, .048),
+        box-shadow: 0 2px 2px 0 rgba(0, 0, 0, .03),
+                    0 1px 4px 0 rgba(0, 0, 0, .048),
                     0 3px 1px -2px rgba(0, 0, 0, .12);
 }
 
diff --git a/chrome/browser/resources/md_history/app.crisper.js b/chrome/browser/resources/md_history/app.crisper.js
index 7f6560e2..cce7210 100644
--- a/chrome/browser/resources/md_history/app.crisper.js
+++ b/chrome/browser/resources/md_history/app.crisper.js
@@ -1,5527 +1,86 @@
 // Copyright 2016 The Chromium 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 PromiseResolver() {
-  this.resolve_;
-  this.reject_;
-  this.promise_ = new Promise(function(resolve, reject) {
-    this.resolve_ = resolve;
-    this.reject_ = reject;
-  }.bind(this));
-}
-
-PromiseResolver.prototype = {
-  get promise() {
-    return this.promise_;
-  },
-  set promise(p) {
-    assertNotReached();
-  },
-  get resolve() {
-    return this.resolve_;
-  },
-  set resolve(r) {
-    assertNotReached();
-  },
-  get reject() {
-    return this.reject_;
-  },
-  set reject(s) {
-    assertNotReached();
-  }
-};
-
+function PromiseResolver(){this.resolve_;this.reject_;this.promise_=new Promise(function(resolve,reject){this.resolve_=resolve;this.reject_=reject}.bind(this))}PromiseResolver.prototype={get promise(){return this.promise_},set promise(p){assertNotReached()},get resolve(){return this.resolve_},set resolve(r){assertNotReached()},get reject(){return this.reject_},set reject(s){assertNotReached()}};
 // 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.
-var global = this;
-
-var WebUIListener;
-
-var cr = cr || function() {
-  'use strict';
-  function exportPath(name, opt_object, opt_objectToExportTo) {
-    var parts = name.split('.');
-    var cur = opt_objectToExportTo || global;
-    for (var part; parts.length && (part = parts.shift()); ) {
-      if (!parts.length && opt_object !== undefined) {
-        cur[part] = opt_object;
-      } else if (part in cur) {
-        cur = cur[part];
-      } else {
-        cur = cur[part] = {};
-      }
-    }
-    return cur;
-  }
-  function dispatchPropertyChange(target, propertyName, newValue, oldValue) {
-    var e = new Event(propertyName + 'Change');
-    e.propertyName = propertyName;
-    e.newValue = newValue;
-    e.oldValue = oldValue;
-    target.dispatchEvent(e);
-  }
-  function getAttributeName(jsName) {
-    return jsName.replace(/([A-Z])/g, '-$1').toLowerCase();
-  }
-  var PropertyKind = {
-    JS: 'js',
-    ATTR: 'attr',
-    BOOL_ATTR: 'boolAttr'
-  };
-  function getGetter(name, kind) {
-    switch (kind) {
-     case PropertyKind.JS:
-      var privateName = name + '_';
-      return function() {
-        return this[privateName];
-      };
-
-     case PropertyKind.ATTR:
-      var attributeName = getAttributeName(name);
-      return function() {
-        return this.getAttribute(attributeName);
-      };
-
-     case PropertyKind.BOOL_ATTR:
-      var attributeName = getAttributeName(name);
-      return function() {
-        return this.hasAttribute(attributeName);
-      };
-    }
-    throw 'not reached';
-  }
-  function getSetter(name, kind, opt_setHook) {
-    switch (kind) {
-     case PropertyKind.JS:
-      var privateName = name + '_';
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          this[privateName] = value;
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-
-     case PropertyKind.ATTR:
-      var attributeName = getAttributeName(name);
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          if (value == undefined) this.removeAttribute(attributeName); else this.setAttribute(attributeName, value);
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-
-     case PropertyKind.BOOL_ATTR:
-      var attributeName = getAttributeName(name);
-      return function(value) {
-        var oldValue = this[name];
-        if (value !== oldValue) {
-          if (value) this.setAttribute(attributeName, name); else this.removeAttribute(attributeName);
-          if (opt_setHook) opt_setHook.call(this, value, oldValue);
-          dispatchPropertyChange(this, name, value, oldValue);
-        }
-      };
-    }
-    throw 'not reached';
-  }
-  function defineProperty(obj, name, opt_kind, opt_setHook) {
-    if (typeof obj == 'function') obj = obj.prototype;
-    var kind = opt_kind || PropertyKind.JS;
-    if (!obj.__lookupGetter__(name)) obj.__defineGetter__(name, getGetter(name, kind));
-    if (!obj.__lookupSetter__(name)) obj.__defineSetter__(name, getSetter(name, kind, opt_setHook));
-  }
-  var uidCounter = 1;
-  function createUid() {
-    return uidCounter++;
-  }
-  function getUid(item) {
-    if (item.hasOwnProperty('uid')) return item.uid;
-    return item.uid = createUid();
-  }
-  function dispatchSimpleEvent(target, type, opt_bubbles, opt_cancelable) {
-    var e = new Event(type, {
-      bubbles: opt_bubbles,
-      cancelable: opt_cancelable === undefined || opt_cancelable
-    });
-    return target.dispatchEvent(e);
-  }
-  function define(name, fun) {
-    var obj = exportPath(name);
-    var exports = fun();
-    for (var propertyName in exports) {
-      var propertyDescriptor = Object.getOwnPropertyDescriptor(exports, propertyName);
-      if (propertyDescriptor) Object.defineProperty(obj, propertyName, propertyDescriptor);
-    }
-  }
-  function addSingletonGetter(ctor) {
-    ctor.getInstance = function() {
-      return ctor.instance_ || (ctor.instance_ = new ctor());
-    };
-  }
-  function makePublic(ctor, methods, opt_target) {
-    methods.forEach(function(method) {
-      ctor[method] = function() {
-        var target = opt_target ? document.getElementById(opt_target) : ctor.getInstance();
-        return target[method + '_'].apply(target, arguments);
-      };
-    });
-  }
-  var chromeSendResolverMap = {};
-  function webUIResponse(id, isSuccess, response) {
-    var resolver = chromeSendResolverMap[id];
-    delete chromeSendResolverMap[id];
-    if (isSuccess) resolver.resolve(response); else resolver.reject(response);
-  }
-  function sendWithPromise(methodName, var_args) {
-    var args = Array.prototype.slice.call(arguments, 1);
-    var promiseResolver = new PromiseResolver();
-    var id = methodName + '_' + createUid();
-    chromeSendResolverMap[id] = promiseResolver;
-    chrome.send(methodName, [ id ].concat(args));
-    return promiseResolver.promise;
-  }
-  var webUIListenerMap = {};
-  function webUIListenerCallback(event, var_args) {
-    var eventListenersMap = webUIListenerMap[event];
-    if (!eventListenersMap) {
-      return;
-    }
-    var args = Array.prototype.slice.call(arguments, 1);
-    for (var listenerId in eventListenersMap) {
-      eventListenersMap[listenerId].apply(null, args);
-    }
-  }
-  function addWebUIListener(eventName, callback) {
-    webUIListenerMap[eventName] = webUIListenerMap[eventName] || {};
-    var uid = createUid();
-    webUIListenerMap[eventName][uid] = callback;
-    return {
-      eventName: eventName,
-      uid: uid
-    };
-  }
-  function removeWebUIListener(listener) {
-    var listenerExists = webUIListenerMap[listener.eventName] && webUIListenerMap[listener.eventName][listener.uid];
-    if (listenerExists) {
-      delete webUIListenerMap[listener.eventName][listener.uid];
-      return true;
-    }
-    return false;
-  }
-  return {
-    addSingletonGetter: addSingletonGetter,
-    createUid: createUid,
-    define: define,
-    defineProperty: defineProperty,
-    dispatchPropertyChange: dispatchPropertyChange,
-    dispatchSimpleEvent: dispatchSimpleEvent,
-    exportPath: exportPath,
-    getUid: getUid,
-    makePublic: makePublic,
-    PropertyKind: PropertyKind,
-    addWebUIListener: addWebUIListener,
-    removeWebUIListener: removeWebUIListener,
-    sendWithPromise: sendWithPromise,
-    webUIListenerCallback: webUIListenerCallback,
-    webUIResponse: webUIResponse,
-    get doc() {
-      return document;
-    },
-    get isMac() {
-      return /Mac/.test(navigator.platform);
-    },
-    get isWindows() {
-      return /Win/.test(navigator.platform);
-    },
-    get isChromeOS() {
-      return /CrOS/.test(navigator.userAgent);
-    },
-    get isLinux() {
-      return /Linux/.test(navigator.userAgent);
-    },
-    get isAndroid() {
-      return /Android/.test(navigator.userAgent);
-    },
-    get isIOS() {
-      return /iPad|iPhone|iPod/.test(navigator.platform);
-    }
-  };
-}();
-
+var global=this;var WebUIListener;var cr=cr||function(){"use strict";function exportPath(name,opt_object,opt_objectToExportTo){var parts=name.split(".");var cur=opt_objectToExportTo||global;for(var part;parts.length&&(part=parts.shift());){if(!parts.length&&opt_object!==undefined){cur[part]=opt_object}else if(part in cur){cur=cur[part]}else{cur=cur[part]={}}}return cur}function dispatchPropertyChange(target,propertyName,newValue,oldValue){var e=new Event(propertyName+"Change");e.propertyName=propertyName;e.newValue=newValue;e.oldValue=oldValue;target.dispatchEvent(e)}function getAttributeName(jsName){return jsName.replace(/([A-Z])/g,"-$1").toLowerCase()}var PropertyKind={JS:"js",ATTR:"attr",BOOL_ATTR:"boolAttr"};function getGetter(name,kind){switch(kind){case PropertyKind.JS:var privateName=name+"_";return function(){return this[privateName]};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(){return this.getAttribute(attributeName)};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(){return this.hasAttribute(attributeName)}}throw"not reached"}function getSetter(name,kind,opt_setHook){switch(kind){case PropertyKind.JS:var privateName=name+"_";return function(value){var oldValue=this[name];if(value!==oldValue){this[privateName]=value;if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}};case PropertyKind.ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this[name];if(value!==oldValue){if(value==undefined)this.removeAttribute(attributeName);else this.setAttribute(attributeName,value);if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}};case PropertyKind.BOOL_ATTR:var attributeName=getAttributeName(name);return function(value){var oldValue=this[name];if(value!==oldValue){if(value)this.setAttribute(attributeName,name);else this.removeAttribute(attributeName);if(opt_setHook)opt_setHook.call(this,value,oldValue);dispatchPropertyChange(this,name,value,oldValue)}}}throw"not reached"}function defineProperty(obj,name,opt_kind,opt_setHook){if(typeof obj=="function")obj=obj.prototype;var kind=opt_kind||PropertyKind.JS;if(!obj.__lookupGetter__(name))obj.__defineGetter__(name,getGetter(name,kind));if(!obj.__lookupSetter__(name))obj.__defineSetter__(name,getSetter(name,kind,opt_setHook))}var uidCounter=1;function createUid(){return uidCounter++}function getUid(item){if(item.hasOwnProperty("uid"))return item.uid;return item.uid=createUid()}function dispatchSimpleEvent(target,type,opt_bubbles,opt_cancelable){var e=new Event(type,{bubbles:opt_bubbles,cancelable:opt_cancelable===undefined||opt_cancelable});return target.dispatchEvent(e)}function define(name,fun){var obj=exportPath(name);var exports=fun();for(var propertyName in exports){var propertyDescriptor=Object.getOwnPropertyDescriptor(exports,propertyName);if(propertyDescriptor)Object.defineProperty(obj,propertyName,propertyDescriptor)}}function addSingletonGetter(ctor){ctor.getInstance=function(){return ctor.instance_||(ctor.instance_=new ctor)}}function makePublic(ctor,methods,opt_target){methods.forEach(function(method){ctor[method]=function(){var target=opt_target?document.getElementById(opt_target):ctor.getInstance();return target[method+"_"].apply(target,arguments)}})}var chromeSendResolverMap={};function webUIResponse(id,isSuccess,response){var resolver=chromeSendResolverMap[id];delete chromeSendResolverMap[id];if(isSuccess)resolver.resolve(response);else resolver.reject(response)}function sendWithPromise(methodName,var_args){var args=Array.prototype.slice.call(arguments,1);var promiseResolver=new PromiseResolver;var id=methodName+"_"+createUid();chromeSendResolverMap[id]=promiseResolver;chrome.send(methodName,[id].concat(args));return promiseResolver.promise}var webUIListenerMap={};function webUIListenerCallback(event,var_args){var eventListenersMap=webUIListenerMap[event];if(!eventListenersMap){return}var args=Array.prototype.slice.call(arguments,1);for(var listenerId in eventListenersMap){eventListenersMap[listenerId].apply(null,args)}}function addWebUIListener(eventName,callback){webUIListenerMap[eventName]=webUIListenerMap[eventName]||{};var uid=createUid();webUIListenerMap[eventName][uid]=callback;return{eventName:eventName,uid:uid}}function removeWebUIListener(listener){var listenerExists=webUIListenerMap[listener.eventName]&&webUIListenerMap[listener.eventName][listener.uid];if(listenerExists){delete webUIListenerMap[listener.eventName][listener.uid];return true}return false}return{addSingletonGetter:addSingletonGetter,createUid:createUid,define:define,defineProperty:defineProperty,dispatchPropertyChange:dispatchPropertyChange,dispatchSimpleEvent:dispatchSimpleEvent,exportPath:exportPath,getUid:getUid,makePublic:makePublic,PropertyKind:PropertyKind,addWebUIListener:addWebUIListener,removeWebUIListener:removeWebUIListener,sendWithPromise:sendWithPromise,webUIListenerCallback:webUIListenerCallback,webUIResponse:webUIResponse,get doc(){return document},get isMac(){return/Mac/.test(navigator.platform)},get isWindows(){return/Win/.test(navigator.platform)},get isChromeOS(){return/CrOS/.test(navigator.userAgent)},get isLinux(){return/Linux/.test(navigator.userAgent)},get isAndroid(){return/Android/.test(navigator.userAgent)},get isIOS(){return/iPad|iPhone|iPod/.test(navigator.platform)}}}();
 // 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.
-cr.define('cr.ui', function() {
-  function decorate(source, constr) {
-    var elements;
-    if (typeof source == 'string') elements = cr.doc.querySelectorAll(source); else elements = [ source ];
-    for (var i = 0, el; el = elements[i]; i++) {
-      if (!(el instanceof constr)) constr.decorate(el);
-    }
-  }
-  function createElementHelper(tagName, opt_bag) {
-    var doc;
-    if (opt_bag && opt_bag.ownerDocument) doc = opt_bag.ownerDocument; else doc = cr.doc;
-    return doc.createElement(tagName);
-  }
-  function define(tagNameOrFunction) {
-    var createFunction, tagName;
-    if (typeof tagNameOrFunction == 'function') {
-      createFunction = tagNameOrFunction;
-      tagName = '';
-    } else {
-      createFunction = createElementHelper;
-      tagName = tagNameOrFunction;
-    }
-    function f(opt_propertyBag) {
-      var el = createFunction(tagName, opt_propertyBag);
-      f.decorate(el);
-      for (var propertyName in opt_propertyBag) {
-        el[propertyName] = opt_propertyBag[propertyName];
-      }
-      return el;
-    }
-    f.decorate = function(el) {
-      el.__proto__ = f.prototype;
-      el.decorate();
-    };
-    return f;
-  }
-  function limitInputWidth(el, parentEl, min, opt_scale) {
-    el.style.width = '10px';
-    var doc = el.ownerDocument;
-    var win = doc.defaultView;
-    var computedStyle = win.getComputedStyle(el);
-    var parentComputedStyle = win.getComputedStyle(parentEl);
-    var rtl = computedStyle.direction == 'rtl';
-    var inputRect = el.getBoundingClientRect();
-    var parentRect = parentEl.getBoundingClientRect();
-    var startPos = rtl ? parentRect.right - inputRect.right : inputRect.left - parentRect.left;
-    var inner = parseInt(computedStyle.borderLeftWidth, 10) + parseInt(computedStyle.paddingLeft, 10) + parseInt(computedStyle.paddingRight, 10) + parseInt(computedStyle.borderRightWidth, 10);
-    var parentPadding = rtl ? parseInt(parentComputedStyle.paddingLeft, 10) : parseInt(parentComputedStyle.paddingRight, 10);
-    var max = parentEl.clientWidth - startPos - inner - parentPadding;
-    if (opt_scale) max *= opt_scale;
-    function limit() {
-      if (el.scrollWidth > max) {
-        el.style.width = max + 'px';
-      } else {
-        el.style.width = 0;
-        var sw = el.scrollWidth;
-        if (sw < min) {
-          el.style.width = min + 'px';
-        } else {
-          el.style.width = sw + 'px';
-        }
-      }
-    }
-    el.addEventListener('input', limit);
-    limit();
-  }
-  function toCssPx(pixels) {
-    if (!window.isFinite(pixels)) console.error('Pixel value is not a number: ' + pixels);
-    return Math.round(pixels) + 'px';
-  }
-  function swallowDoubleClick(e) {
-    var doc = e.target.ownerDocument;
-    var counter = Math.min(1, e.detail);
-    function swallow(e) {
-      e.stopPropagation();
-      e.preventDefault();
-    }
-    function onclick(e) {
-      if (e.detail > counter) {
-        counter = e.detail;
-        swallow(e);
-      } else {
-        doc.removeEventListener('dblclick', swallow, true);
-        doc.removeEventListener('click', onclick, true);
-      }
-    }
-    setTimeout(function() {
-      doc.addEventListener('click', onclick, true);
-      doc.addEventListener('dblclick', swallow, true);
-    }, 0);
-  }
-  return {
-    decorate: decorate,
-    define: define,
-    limitInputWidth: limitInputWidth,
-    toCssPx: toCssPx,
-    swallowDoubleClick: swallowDoubleClick
-  };
-});
-
+cr.define("cr.ui",function(){function decorate(source,constr){var elements;if(typeof source=="string")elements=cr.doc.querySelectorAll(source);else elements=[source];for(var i=0,el;el=elements[i];i++){if(!(el instanceof constr))constr.decorate(el)}}function createElementHelper(tagName,opt_bag){var doc;if(opt_bag&&opt_bag.ownerDocument)doc=opt_bag.ownerDocument;else doc=cr.doc;return doc.createElement(tagName)}function define(tagNameOrFunction){var createFunction,tagName;if(typeof tagNameOrFunction=="function"){createFunction=tagNameOrFunction;tagName=""}else{createFunction=createElementHelper;tagName=tagNameOrFunction}function f(opt_propertyBag){var el=createFunction(tagName,opt_propertyBag);f.decorate(el);for(var propertyName in opt_propertyBag){el[propertyName]=opt_propertyBag[propertyName]}return el}f.decorate=function(el){el.__proto__=f.prototype;el.decorate()};return f}function limitInputWidth(el,parentEl,min,opt_scale){el.style.width="10px";var doc=el.ownerDocument;var win=doc.defaultView;var computedStyle=win.getComputedStyle(el);var parentComputedStyle=win.getComputedStyle(parentEl);var rtl=computedStyle.direction=="rtl";var inputRect=el.getBoundingClientRect();var parentRect=parentEl.getBoundingClientRect();var startPos=rtl?parentRect.right-inputRect.right:inputRect.left-parentRect.left;var inner=parseInt(computedStyle.borderLeftWidth,10)+parseInt(computedStyle.paddingLeft,10)+parseInt(computedStyle.paddingRight,10)+parseInt(computedStyle.borderRightWidth,10);var parentPadding=rtl?parseInt(parentComputedStyle.paddingLeft,10):parseInt(parentComputedStyle.paddingRight,10);var max=parentEl.clientWidth-startPos-inner-parentPadding;if(opt_scale)max*=opt_scale;function limit(){if(el.scrollWidth>max){el.style.width=max+"px"}else{el.style.width=0;var sw=el.scrollWidth;if(sw<min){el.style.width=min+"px"}else{el.style.width=sw+"px"}}}el.addEventListener("input",limit);limit()}function toCssPx(pixels){if(!window.isFinite(pixels))console.error("Pixel value is not a number: "+pixels);return Math.round(pixels)+"px"}function swallowDoubleClick(e){var doc=e.target.ownerDocument;var counter=Math.min(1,e.detail);function swallow(e){e.stopPropagation();e.preventDefault()}function onclick(e){if(e.detail>counter){counter=e.detail;swallow(e)}else{doc.removeEventListener("dblclick",swallow,true);doc.removeEventListener("click",onclick,true)}}setTimeout(function(){doc.addEventListener("click",onclick,true);doc.addEventListener("dblclick",swallow,true)},0)}return{decorate:decorate,define:define,limitInputWidth:limitInputWidth,toCssPx:toCssPx,swallowDoubleClick:swallowDoubleClick}});
 // 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.
-cr.define('cr.ui', function() {
-  function KeyboardShortcut(shortcut) {
-    var mods = {};
-    var ident = '';
-    shortcut.split('|').forEach(function(part) {
-      var partLc = part.toLowerCase();
-      switch (partLc) {
-       case 'alt':
-       case 'ctrl':
-       case 'meta':
-       case 'shift':
-        mods[partLc + 'Key'] = true;
-        break;
+cr.define("cr.ui",function(){function KeyboardShortcut(shortcut){var mods={};var ident="";shortcut.split("|").forEach(function(part){var partLc=part.toLowerCase();switch(partLc){case"alt":case"ctrl":case"meta":case"shift":mods[partLc+"Key"]=true;break;default:if(ident)throw Error("Invalid shortcut");ident=part}});this.ident_=ident;this.mods_=mods}KeyboardShortcut.prototype={matchesEvent:function(e){if(e.key==this.ident_){var mods=this.mods_;return["altKey","ctrlKey","metaKey","shiftKey"].every(function(k){return e[k]==!!mods[k]})}return false}};var Command=cr.ui.define("command");Command.prototype={__proto__:HTMLElement.prototype,decorate:function(){CommandManager.init(assert(this.ownerDocument));if(this.hasAttribute("shortcut"))this.shortcut=this.getAttribute("shortcut")},execute:function(opt_element){if(this.disabled)return;var doc=this.ownerDocument;if(doc.activeElement){var e=new Event("command",{bubbles:true});e.command=this;(opt_element||doc.activeElement).dispatchEvent(e)}},canExecuteChange:function(opt_node){dispatchCanExecuteEvent(this,opt_node||this.ownerDocument.activeElement)},shortcut_:"",get shortcut(){return this.shortcut_},set shortcut(shortcut){var oldShortcut=this.shortcut_;if(shortcut!==oldShortcut){this.keyboardShortcuts_=shortcut.split(/\s+/).map(function(shortcut){return new KeyboardShortcut(shortcut)});this.shortcut_=shortcut;cr.dispatchPropertyChange(this,"shortcut",this.shortcut_,oldShortcut)}},matchesEvent:function(e){if(!this.keyboardShortcuts_)return false;return this.keyboardShortcuts_.some(function(keyboardShortcut){return keyboardShortcut.matchesEvent(e)})}};cr.defineProperty(Command,"label",cr.PropertyKind.ATTR);cr.defineProperty(Command,"disabled",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hidden",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"checked",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hideShortcutText",cr.PropertyKind.BOOL_ATTR);function dispatchCanExecuteEvent(command,target){var e=new CanExecuteEvent(command);target.dispatchEvent(e);command.disabled=!e.canExecute}var commandManagers={};function CommandManager(doc){doc.addEventListener("focus",this.handleFocus_.bind(this),true);doc.addEventListener("keydown",this.handleKeyDown_.bind(this),false)}CommandManager.init=function(doc){var uid=cr.getUid(doc);if(!(uid in commandManagers)){commandManagers[uid]=new CommandManager(doc)}};CommandManager.prototype={handleFocus_:function(e){var target=e.target;if(target.menu||target.command)return;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));commands.forEach(function(command){dispatchCanExecuteEvent(command,target)})},handleKeyDown_:function(e){var target=e.target;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));for(var i=0,command;command=commands[i];i++){if(command.matchesEvent(e)){command.canExecuteChange();if(!command.disabled){e.preventDefault();e.stopPropagation();command.execute();return}}}}};function CanExecuteEvent(command){var e=new Event("canExecute",{bubbles:true,cancelable:true});e.__proto__=CanExecuteEvent.prototype;e.command=command;return e}CanExecuteEvent.prototype={__proto__:Event.prototype,command:null,canExecute_:false,get canExecute(){return this.canExecute_},set canExecute(canExecute){this.canExecute_=!!canExecute;this.stopPropagation();this.preventDefault()}};return{Command:Command,CanExecuteEvent:CanExecuteEvent}});Polymer({is:"iron-media-query",properties:{queryMatches:{type:Boolean,value:false,readOnly:true,notify:true},query:{type:String,observer:"queryChanged"},full:{type:Boolean,value:false},_boundMQHandler:{value:function(){return this.queryHandler.bind(this)}},_mq:{value:null}},attached:function(){this.style.display="none";this.queryChanged()},detached:function(){this._remove()},_add:function(){if(this._mq){this._mq.addListener(this._boundMQHandler)}},_remove:function(){if(this._mq){this._mq.removeListener(this._boundMQHandler)}this._mq=null},queryChanged:function(){this._remove();var query=this.query;if(!query){return}if(!this.full&&query[0]!=="("){query="("+query+")"}this._mq=window.matchMedia(query);this._add();this.queryHandler(this._mq)},queryHandler:function(mq){this._setQueryMatches(mq.matches)}});Polymer.IronResizableBehavior={properties:{_parentResizable:{type:Object,observer:"_parentResizableChanged"},_notifyingDescendant:{type:Boolean,value:false}},listeners:{"iron-request-resize-notifications":"_onIronRequestResizeNotifications"},created:function(){this._interestedResizables=[];this._boundNotifyResize=this.notifyResize.bind(this)},attached:function(){this.fire("iron-request-resize-notifications",null,{node:this,bubbles:true,cancelable:true});if(!this._parentResizable){window.addEventListener("resize",this._boundNotifyResize);this.notifyResize()}},detached:function(){if(this._parentResizable){this._parentResizable.stopResizeNotificationsFor(this)}else{window.removeEventListener("resize",this._boundNotifyResize)}this._parentResizable=null},notifyResize:function(){if(!this.isAttached){return}this._interestedResizables.forEach(function(resizable){if(this.resizerShouldNotify(resizable)){this._notifyDescendant(resizable)}},this);this._fireResize()},assignParentResizable:function(parentResizable){this._parentResizable=parentResizable},stopResizeNotificationsFor:function(target){var index=this._interestedResizables.indexOf(target);if(index>-1){this._interestedResizables.splice(index,1);this.unlisten(target,"iron-resize","_onDescendantIronResize")}},resizerShouldNotify:function(element){return true},_onDescendantIronResize:function(event){if(this._notifyingDescendant){event.stopPropagation();return}if(!Polymer.Settings.useShadow){this._fireResize()}},_fireResize:function(){this.fire("iron-resize",null,{node:this,bubbles:false})},_onIronRequestResizeNotifications:function(event){var target=event.path?event.path[0]:event.target;if(target===this){return}if(this._interestedResizables.indexOf(target)===-1){this._interestedResizables.push(target);this.listen(target,"iron-resize","_onDescendantIronResize")}target.assignParentResizable(this);this._notifyDescendant(target);event.stopPropagation()},_parentResizableChanged:function(parentResizable){if(parentResizable){window.removeEventListener("resize",this._boundNotifyResize)}},_notifyDescendant:function(descendant){if(!this.isAttached){return}this._notifyingDescendant=true;descendant.notifyResize();this._notifyingDescendant=false}};Polymer.IronSelection=function(selectCallback){this.selection=[];this.selectCallback=selectCallback};Polymer.IronSelection.prototype={get:function(){return this.multi?this.selection.slice():this.selection[0]},clear:function(excludes){this.selection.slice().forEach(function(item){if(!excludes||excludes.indexOf(item)<0){this.setItemSelected(item,false)}},this)},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!=null){if(isSelected!==this.isSelected(item)){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}if(this.selectCallback){this.selectCallback(item,isSelected)}}}},select:function(item){if(this.multi){this.toggle(item)}else if(this.get()!==item){this.setItemSelected(this.get(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}};Polymer.IronSelectableBehavior={properties:{attrForSelected:{type:String,value:null},selected:{type:String,notify:true},selectedItem:{type:Object,readOnly:true,notify:true},activateEvent:{type:String,value:"tap",observer:"_activateEventChanged"},selectable:String,selectedClass:{type:String,value:"iron-selected"},selectedAttribute:{type:String,value:null},fallbackSelection:{type:String,value:null},items:{type:Array,readOnly:true,notify:true,value:function(){return[]}},_excludedLocalNames:{type:Object,value:function(){return{template:1}}}},observers:["_updateAttrForSelected(attrForSelected)","_updateSelected(selected)","_checkFallback(fallbackSelection)"],created:function(){this._bindFilterItem=this._filterItem.bind(this);this._selection=new Polymer.IronSelection(this._applySelection.bind(this))},attached:function(){this._observer=this._observeItems(this);this._updateItems();if(!this._shouldUpdateSelection){this._updateSelected()}this._addListener(this.activateEvent)},detached:function(){if(this._observer){Polymer.dom(this).unobserveNodes(this._observer)}this._removeListener(this.activateEvent)},indexOf:function(item){return this.items.indexOf(item)},select:function(value){this.selected=value},selectPrevious:function(){var length=this.items.length;var index=(Number(this._valueToIndex(this.selected))-1+length)%length;this.selected=this._indexToValue(index)},selectNext:function(){var index=(Number(this._valueToIndex(this.selected))+1)%this.items.length;this.selected=this._indexToValue(index)},selectIndex:function(index){this.select(this._indexToValue(index))},forceSynchronousItemUpdate:function(){this._updateItems()},get _shouldUpdateSelection(){return this.selected!=null},_checkFallback:function(){if(this._shouldUpdateSelection){this._updateSelected()}},_addListener:function(eventName){this.listen(this,eventName,"_activateHandler")},_removeListener:function(eventName){this.unlisten(this,eventName,"_activateHandler")},_activateEventChanged:function(eventName,old){this._removeListener(old);this._addListener(eventName)},_updateItems:function(){var nodes=Polymer.dom(this).queryDistributedElements(this.selectable||"*");nodes=Array.prototype.filter.call(nodes,this._bindFilterItem);this._setItems(nodes)},_updateAttrForSelected:function(){if(this._shouldUpdateSelection){this.selected=this._indexToValue(this.indexOf(this.selectedItem))}},_updateSelected:function(){this._selectSelected(this.selected)},_selectSelected:function(selected){this._selection.select(this._valueToItem(this.selected));if(this.fallbackSelection&&this.items.length&&this._selection.get()===undefined){this.selected=this.fallbackSelection}},_filterItem:function(node){return!this._excludedLocalNames[node.localName]},_valueToItem:function(value){return value==null?null:this.items[this._valueToIndex(value)]},_valueToIndex:function(value){if(this.attrForSelected){for(var i=0,item;item=this.items[i];i++){if(this._valueForItem(item)==value){return i}}}else{return Number(value)}},_indexToValue:function(index){if(this.attrForSelected){var item=this.items[index];if(item){return this._valueForItem(item)}}else{return index}},_valueForItem:function(item){var propValue=item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];return propValue!=undefined?propValue:item.getAttribute(this.attrForSelected)},_applySelection:function(item,isSelected){if(this.selectedClass){this.toggleClass(this.selectedClass,isSelected,item)}if(this.selectedAttribute){this.toggleAttribute(this.selectedAttribute,isSelected,item)}this._selectionChange();this.fire("iron-"+(isSelected?"select":"deselect"),{item:item})},_selectionChange:function(){this._setSelectedItem(this._selection.get())},_observeItems:function(node){return Polymer.dom(node).observeNodes(function(mutation){this._updateItems();if(this._shouldUpdateSelection){this._updateSelected()}this.fire("iron-items-changed",mutation,{bubbles:false,cancelable:false})})},_activateHandler:function(e){var t=e.target;var items=this.items;while(t&&t!=this){var i=items.indexOf(t);if(i>=0){var value=this._indexToValue(i);this._itemActivate(value,t);return}t=t.parentNode}},_itemActivate:function(value,item){if(!this.fire("iron-activate",{selected:value,item:item},{cancelable:true}).defaultPrevented){this.select(value)}}};Polymer({is:"iron-pages",behaviors:[Polymer.IronResizableBehavior,Polymer.IronSelectableBehavior],properties:{activateEvent:{type:String,value:null}},observers:["_selectedPageChanged(selected)"],_selectedPageChanged:function(selected,old){this.async(this.notifyResize)}});Polymer.IronScrollTargetBehavior={properties:{scrollTarget:{type:HTMLElement,value:function(){return this._defaultScrollTarget}}},observers:["_scrollTargetChanged(scrollTarget, isAttached)"],_scrollTargetChanged:function(scrollTarget,isAttached){var eventTarget;if(this._oldScrollTarget){eventTarget=this._oldScrollTarget===this._doc?window:this._oldScrollTarget;eventTarget.removeEventListener("scroll",this._boundScrollHandler);this._oldScrollTarget=null}if(!isAttached){return}if(scrollTarget==="document"){this.scrollTarget=this._doc}else if(typeof scrollTarget==="string"){this.scrollTarget=this.domHost?this.domHost.$[scrollTarget]:Polymer.dom(this.ownerDocument).querySelector("#"+scrollTarget)}else if(this._isValidScrollTarget()){eventTarget=scrollTarget===this._doc?window:scrollTarget;this._boundScrollHandler=this._boundScrollHandler||this._scrollHandler.bind(this);this._oldScrollTarget=scrollTarget;eventTarget.addEventListener("scroll",this._boundScrollHandler)}},_scrollHandler:function scrollHandler(){},get _defaultScrollTarget(){return this._doc},get _doc(){return this.ownerDocument.documentElement},get _scrollTop(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageYOffset:this.scrollTarget.scrollTop}return 0},get _scrollLeft(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageXOffset:this.scrollTarget.scrollLeft}return 0},set _scrollTop(top){if(this.scrollTarget===this._doc){window.scrollTo(window.pageXOffset,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollTop=top}},set _scrollLeft(left){if(this.scrollTarget===this._doc){window.scrollTo(left,window.pageYOffset)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left}},scroll:function(left,top){if(this.scrollTarget===this._doc){window.scrollTo(left,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left;this.scrollTarget.scrollTop=top}},get _scrollTargetWidth(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerWidth:this.scrollTarget.offsetWidth}return 0},get _scrollTargetHeight(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerHeight:this.scrollTarget.offsetHeight}return 0},_isValidScrollTarget:function(){return this.scrollTarget instanceof HTMLElement}};(function(){var metaDatas={};var metaArrays={};var singleton=null;Polymer.IronMeta=Polymer({is:"iron-meta",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,observer:"_valueChanged"},self:{type:Boolean,observer:"_selfChanged"},list:{type:Array,notify:true}},hostAttributes:{hidden:true},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":case"value":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key,old){this._resetRegistration(old)},_valueChanged:function(value){this._resetRegistration(this.key)},_selfChanged:function(self){if(self){this.value=this}},_typeChanged:function(type){this._unregisterKey(this.key);if(!metaDatas[type]){metaDatas[type]={}}this._metaData=metaDatas[type];if(!metaArrays[type]){metaArrays[type]=[]}this.list=metaArrays[type];this._registerKeyValue(this.key,this.value)},byKey:function(key){return this._metaData&&this._metaData[key]},_resetRegistration:function(oldKey){this._unregisterKey(oldKey);this._registerKeyValue(this.key,this.value)},_unregisterKey:function(key){this._unregister(key,this._metaData,this.list)},_registerKeyValue:function(key,value){this._register(key,value,this._metaData,this.list)},_register:function(key,value,data,list){if(key&&data&&value!==undefined){data[key]=value;list.push(value)}},_unregister:function(key,data,list){if(key&&data){if(key in data){var value=data[key];delete data[key];this.arrayDelete(list,value)}}}});Polymer.IronMeta.getIronMeta=function getIronMeta(){if(singleton===null){singleton=new Polymer.IronMeta}return singleton};Polymer.IronMetaQuery=Polymer({is:"iron-meta-query",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,readOnly:true},list:{type:Array,notify:true}},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key){this._setValue(this._metaData&&this._metaData[key])},_typeChanged:function(type){this._metaData=metaDatas[type];this.list=metaArrays[type];if(this.key){this._keyChanged(this.key)}},byKey:function(key){return this._metaData&&this._metaData[key]}})})();Polymer({is:"iron-icon",properties:{icon:{type:String,observer:"_iconChanged"},theme:{type:String,observer:"_updateIcon"},src:{type:String,observer:"_srcChanged"},_meta:{value:Polymer.Base.create("iron-meta",{type:"iconset"}),observer:"_updateIcon"}},_DEFAULT_ICONSET:"icons",_iconChanged:function(icon){var parts=(icon||"").split(":");this._iconName=parts.pop();this._iconsetName=parts.pop()||this._DEFAULT_ICONSET;this._updateIcon()},_srcChanged:function(src){this._updateIcon()},_usesIconset:function(){return this.icon||!this.src},_updateIcon:function(){if(this._usesIconset()){if(this._img&&this._img.parentNode){Polymer.dom(this.root).removeChild(this._img)}if(this._iconName===""){if(this._iconset){this._iconset.removeIcon(this)}}else if(this._iconsetName&&this._meta){this._iconset=this._meta.byKey(this._iconsetName);if(this._iconset){this._iconset.applyIcon(this,this._iconName,this.theme);this.unlisten(window,"iron-iconset-added","_updateIcon")}else{this.listen(window,"iron-iconset-added","_updateIcon")}}}else{if(this._iconset){this._iconset.removeIcon(this)}if(!this._img){this._img=document.createElement("img");this._img.style.width="100%";this._img.style.height="100%";this._img.draggable=false}this._img.src=this.src;Polymer.dom(this.root).appendChild(this._img)}}});(function(){"use strict";var KEY_IDENTIFIER={"U+0008":"backspace","U+0009":"tab","U+001B":"esc","U+0020":"space","U+007F":"del"};var KEY_CODE={8:"backspace",9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var MODIFIER_KEYS={shift:"shiftKey",ctrl:"ctrlKey",alt:"altKey",meta:"metaKey"};var KEY_CHAR=/[a-z0-9*]/;var IDENT_CHAR=/U\+/;var ARROW_KEY=/^arrow/;var SPACE_KEY=/^space(bar)?/;var ESC_KEY=/^escape$/;function transformKey(key,noSpecialChars){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey===" "||SPACE_KEY.test(lKey)){validKey="space"}else if(ESC_KEY.test(lKey)){validKey="esc"}else if(lKey.length==1){if(!noSpecialChars||KEY_CHAR.test(lKey)){validKey=lKey}}else if(ARROW_KEY.test(lKey)){validKey=lKey.replace("arrow","")}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(keyIdent in KEY_IDENTIFIER){validKey=KEY_IDENTIFIER[keyIdent]}else if(IDENT_CHAR.test(keyIdent)){keyIdent=parseInt(keyIdent.replace("U+","0x"),16);validKey=String.fromCharCode(keyIdent).toLowerCase()}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(keyCode-48)}else if(keyCode>=96&&keyCode<=105){validKey=String(keyCode-96)}else{validKey=KEY_CODE[keyCode]}}return validKey}function normalizedKeyForEvent(keyEvent,noSpecialChars){if(keyEvent.key){return transformKey(keyEvent.key,noSpecialChars)}if(keyEvent.detail&&keyEvent.detail.key){return transformKey(keyEvent.detail.key,noSpecialChars)}return transformKeyIdentifier(keyEvent.keyIdentifier)||transformKeyCode(keyEvent.keyCode)||""}function keyComboMatchesEvent(keyCombo,event){var keyEvent=normalizedKeyForEvent(event,keyCombo.hasModifiers);return keyEvent===keyCombo.key&&(!keyCombo.hasModifiers||!!event.shiftKey===!!keyCombo.shiftKey&&!!event.ctrlKey===!!keyCombo.ctrlKey&&!!event.altKey===!!keyCombo.altKey&&!!event.metaKey===!!keyCombo.metaKey)}function parseKeyComboString(keyComboString){if(keyComboString.length===1){return{combo:keyComboString,key:keyComboString,event:"keydown"}}return keyComboString.split("+").reduce(function(parsedKeyCombo,keyComboPart){var eventParts=keyComboPart.split(":");var keyName=eventParts[0];var event=eventParts[1];if(keyName in MODIFIER_KEYS){parsedKeyCombo[MODIFIER_KEYS[keyName]]=true;parsedKeyCombo.hasModifiers=true}else{parsedKeyCombo.key=keyName;parsedKeyCombo.event=event||"keydown"}return parsedKeyCombo},{combo:keyComboString.split(":").shift()})}function parseEventString(eventString){return eventString.trim().split(" ").map(function(keyComboString){return parseKeyComboString(keyComboString)})}Polymer.IronA11yKeysBehavior={properties:{keyEventTarget:{type:Object,value:function(){return this}},stopKeyboardEventPropagation:{type:Boolean,value:false},_boundKeyHandlers:{type:Array,value:function(){return[]}},_imperativeKeyBindings:{type:Object,value:function(){return{}}}},observers:["_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)"],keyBindings:{},registered:function(){this._prepKeyBindings()},attached:function(){this._listenKeyEventListeners()},detached:function(){this._unlistenKeyEventListeners()},addOwnKeyBinding:function(eventString,handlerName){this._imperativeKeyBindings[eventString]=handlerName;this._prepKeyBindings();this._resetKeyEventListeners()},removeOwnKeyBindings:function(){this._imperativeKeyBindings={};this._prepKeyBindings();this._resetKeyEventListeners()},keyboardEventMatchesKeys:function(event,eventString){var keyCombos=parseEventString(eventString);for(var i=0;i<keyCombos.length;++i){if(keyComboMatchesEvent(keyCombos[i],event)){return true}}return false},_collectKeyBindings:function(){var keyBindings=this.behaviors.map(function(behavior){return behavior.keyBindings});if(keyBindings.indexOf(this.keyBindings)===-1){keyBindings.push(this.keyBindings)}return keyBindings},_prepKeyBindings:function(){this._keyBindings={};this._collectKeyBindings().forEach(function(keyBindings){for(var eventString in keyBindings){this._addKeyBinding(eventString,keyBindings[eventString])}},this);for(var eventString in this._imperativeKeyBindings){this._addKeyBinding(eventString,this._imperativeKeyBindings[eventString])}for(var eventName in this._keyBindings){this._keyBindings[eventName].sort(function(kb1,kb2){var b1=kb1[0].hasModifiers;var b2=kb2[0].hasModifiers;return b1===b2?0:b1?-1:1})}},_addKeyBinding:function(eventString,handlerName){parseEventString(eventString).forEach(function(keyCombo){this._keyBindings[keyCombo.event]=this._keyBindings[keyCombo.event]||[];this._keyBindings[keyCombo.event].push([keyCombo,handlerName])},this)},_resetKeyEventListeners:function(){this._unlistenKeyEventListeners();if(this.isAttached){this._listenKeyEventListeners()}},_listenKeyEventListeners:function(){if(!this.keyEventTarget){return}Object.keys(this._keyBindings).forEach(function(eventName){var keyBindings=this._keyBindings[eventName];var boundKeyHandler=this._onKeyBindingEvent.bind(this,keyBindings);this._boundKeyHandlers.push([this.keyEventTarget,eventName,boundKeyHandler]);this.keyEventTarget.addEventListener(eventName,boundKeyHandler)},this)},_unlistenKeyEventListeners:function(){var keyHandlerTuple;var keyEventTarget;var eventName;var boundKeyHandler;while(this._boundKeyHandlers.length){keyHandlerTuple=this._boundKeyHandlers.pop();keyEventTarget=keyHandlerTuple[0];eventName=keyHandlerTuple[1];boundKeyHandler=keyHandlerTuple[2];keyEventTarget.removeEventListener(eventName,boundKeyHandler)}},_onKeyBindingEvent:function(keyBindings,event){if(this.stopKeyboardEventPropagation){event.stopPropagation()}if(event.defaultPrevented){return}for(var i=0;i<keyBindings.length;i++){var keyCombo=keyBindings[i][0];var handlerName=keyBindings[i][1];if(keyComboMatchesEvent(keyCombo,event)){this._triggerKeyHandler(keyCombo,handlerName,event);if(event.defaultPrevented){return}}}},_triggerKeyHandler:function(keyCombo,handlerName,keyboardEvent){var detail=Object.create(keyCombo);detail.keyboardEvent=keyboardEvent;var event=new CustomEvent(keyCombo.event,{detail:detail,cancelable:true});this[handlerName].call(this,event);if(event.defaultPrevented){keyboardEvent.preventDefault()}}}})();Polymer.IronControlState={properties:{focused:{type:Boolean,value:false,notify:true,readOnly:true,reflectToAttribute:true},disabled:{type:Boolean,value:false,notify:true,observer:"_disabledChanged",reflectToAttribute:true},_oldTabIndex:{type:Number},_boundFocusBlurHandler:{type:Function,value:function(){return this._focusBlurHandler.bind(this)}}},observers:["_changedControlState(focused, disabled)"],ready:function(){this.addEventListener("focus",this._boundFocusBlurHandler,true);this.addEventListener("blur",this._boundFocusBlurHandler,true)},_focusBlurHandler:function(event){if(event.target===this){this._setFocused(event.type==="focus")}else if(!this.shadowRoot){var target=Polymer.dom(event).localTarget;if(!this.isLightDescendant(target)){this.fire(event.type,{sourceEvent:event},{node:this,bubbles:event.bubbles,cancelable:event.cancelable})}}},_disabledChanged:function(disabled,old){this.setAttribute("aria-disabled",disabled?"true":"false");this.style.pointerEvents=disabled?"none":"";if(disabled){this._oldTabIndex=this.tabIndex;this._setFocused(false);this.tabIndex=-1;this.blur()}else if(this._oldTabIndex!==undefined){this.tabIndex=this._oldTabIndex}},_changedControlState:function(){if(this._controlStateChanged){this._controlStateChanged()}}};Polymer.IronButtonStateImpl={properties:{pressed:{type:Boolean,readOnly:true,value:false,reflectToAttribute:true,observer:"_pressedChanged"},toggles:{type:Boolean,value:false,reflectToAttribute:true},active:{type:Boolean,value:false,notify:true,reflectToAttribute:true},pointerDown:{type:Boolean,readOnly:true,value:false},receivedFocusFromKeyboard:{type:Boolean,readOnly:true},ariaActiveAttribute:{type:String,value:"aria-pressed",observer:"_ariaActiveAttributeChanged"}},listeners:{down:"_downHandler",up:"_upHandler",tap:"_tapHandler"},observers:["_detectKeyboardFocus(focused)","_activeChanged(active, ariaActiveAttribute)"],keyBindings:{"enter:keydown":"_asyncClick","space:keydown":"_spaceKeyDownHandler","space:keyup":"_spaceKeyUpHandler"},_mouseEventRe:/^mouse/,_tapHandler:function(){if(this.toggles){this._userActivate(!this.active)}else{this.active=false}},_detectKeyboardFocus:function(focused){this._setReceivedFocusFromKeyboard(!this.pointerDown&&focused)},_userActivate:function(active){if(this.active!==active){this.active=active;this.fire("change")}},_downHandler:function(event){this._setPointerDown(true);this._setPressed(true);this._setReceivedFocusFromKeyboard(false)},_upHandler:function(){this._setPointerDown(false);this._setPressed(false)},_spaceKeyDownHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;keyboardEvent.preventDefault();keyboardEvent.stopImmediatePropagation();this._setPressed(true)},_spaceKeyUpHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;if(this.pressed){this._asyncClick()}this._setPressed(false)},_asyncClick:function(){this.async(function(){this.click()},1)},_pressedChanged:function(pressed){this._changedButtonState()},_ariaActiveAttributeChanged:function(value,oldValue){if(oldValue&&oldValue!=value&&this.hasAttribute(oldValue)){this.removeAttribute(oldValue)}},_activeChanged:function(active,ariaActiveAttribute){if(this.toggles){this.setAttribute(this.ariaActiveAttribute,active?"true":"false")}else{this.removeAttribute(this.ariaActiveAttribute)}this._changedButtonState()},_controlStateChanged:function(){if(this.disabled){this._setPressed(false)}else{this._changedButtonState()}},_changedButtonState:function(){if(this._buttonStateChanged){this._buttonStateChanged()}}};Polymer.IronButtonState=[Polymer.IronA11yKeysBehavior,Polymer.IronButtonStateImpl];(function(){var Utility={distance:function(x1,y1,x2,y2){var xDelta=x1-x2;var yDelta=y1-y2;return Math.sqrt(xDelta*xDelta+yDelta*yDelta)},now:window.performance&&window.performance.now?window.performance.now.bind(window.performance):Date.now};function ElementMetrics(element){this.element=element;this.width=this.boundingRect.width;this.height=this.boundingRect.height;this.size=Math.max(this.width,this.height)}ElementMetrics.prototype={get boundingRect(){return this.element.getBoundingClientRect()},furthestCornerDistanceFrom:function(x,y){var topLeft=Utility.distance(x,y,0,0);var topRight=Utility.distance(x,y,this.width,0);var bottomLeft=Utility.distance(x,y,0,this.height);var bottomRight=Utility.distance(x,y,this.width,this.height);return Math.max(topLeft,topRight,bottomLeft,bottomRight)}};function Ripple(element){this.element=element;this.color=window.getComputedStyle(element).color;this.wave=document.createElement("div");this.waveContainer=document.createElement("div");this.wave.style.backgroundColor=this.color;this.wave.classList.add("wave");this.waveContainer.classList.add("wave-container");Polymer.dom(this.waveContainer).appendChild(this.wave);this.resetInteractionState()}Ripple.MAX_RADIUS=300;Ripple.prototype={get recenters(){return this.element.recenters},get center(){return this.element.center},get mouseDownElapsed(){var elapsed;if(!this.mouseDownStart){return 0}elapsed=Utility.now()-this.mouseDownStart;if(this.mouseUpStart){elapsed-=this.mouseUpElapsed}return elapsed},get mouseUpElapsed(){return this.mouseUpStart?Utility.now()-this.mouseUpStart:0},get mouseDownElapsedSeconds(){return this.mouseDownElapsed/1e3},get mouseUpElapsedSeconds(){return this.mouseUpElapsed/1e3},get mouseInteractionSeconds(){return this.mouseDownElapsedSeconds+this.mouseUpElapsedSeconds},get initialOpacity(){return this.element.initialOpacity},get opacityDecayVelocity(){return this.element.opacityDecayVelocity},get radius(){var width2=this.containerMetrics.width*this.containerMetrics.width;var height2=this.containerMetrics.height*this.containerMetrics.height;var waveRadius=Math.min(Math.sqrt(width2+height2),Ripple.MAX_RADIUS)*1.1+5;var duration=1.1-.2*(waveRadius/Ripple.MAX_RADIUS);var timeNow=this.mouseInteractionSeconds/duration;var size=waveRadius*(1-Math.pow(80,-timeNow));return Math.abs(size)},get opacity(){if(!this.mouseUpStart){return this.initialOpacity}return Math.max(0,this.initialOpacity-this.mouseUpElapsedSeconds*this.opacityDecayVelocity)},get outerOpacity(){var outerOpacity=this.mouseUpElapsedSeconds*.3;var waveOpacity=this.opacity;return Math.max(0,Math.min(outerOpacity,waveOpacity))},get isOpacityFullyDecayed(){return this.opacity<.01&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isRestingAtMaxRadius(){return this.opacity>=this.initialOpacity&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isAnimationComplete(){return this.mouseUpStart?this.isOpacityFullyDecayed:this.isRestingAtMaxRadius},get translationFraction(){return Math.min(1,this.radius/this.containerMetrics.size*2/Math.sqrt(2))},get xNow(){if(this.xEnd){return this.xStart+this.translationFraction*(this.xEnd-this.xStart)}return this.xStart},get yNow(){if(this.yEnd){return this.yStart+this.translationFraction*(this.yEnd-this.yStart)}return this.yStart},get isMouseDown(){return this.mouseDownStart&&!this.mouseUpStart},resetInteractionState:function(){this.maxRadius=0;this.mouseDownStart=0;this.mouseUpStart=0;this.xStart=0;this.yStart=0;this.xEnd=0;this.yEnd=0;this.slideDistance=0;this.containerMetrics=new ElementMetrics(this.element)},draw:function(){var scale;var translateString;var dx;var dy;this.wave.style.opacity=this.opacity;scale=this.radius/(this.containerMetrics.size/2);dx=this.xNow-this.containerMetrics.width/2;
 
-       default:
-        if (ident) throw Error('Invalid shortcut');
-        ident = part;
-      }
-    });
-    this.ident_ = ident;
-    this.mods_ = mods;
-  }
-  KeyboardShortcut.prototype = {
-    matchesEvent: function(e) {
-      if (e.key == this.ident_) {
-        var mods = this.mods_;
-        return [ 'altKey', 'ctrlKey', 'metaKey', 'shiftKey' ].every(function(k) {
-          return e[k] == !!mods[k];
-        });
-      }
-      return false;
-    }
-  };
-  var Command = cr.ui.define('command');
-  Command.prototype = {
-    __proto__: HTMLElement.prototype,
-    decorate: function() {
-      CommandManager.init(assert(this.ownerDocument));
-      if (this.hasAttribute('shortcut')) this.shortcut = this.getAttribute('shortcut');
-    },
-    execute: function(opt_element) {
-      if (this.disabled) return;
-      var doc = this.ownerDocument;
-      if (doc.activeElement) {
-        var e = new Event('command', {
-          bubbles: true
-        });
-        e.command = this;
-        (opt_element || doc.activeElement).dispatchEvent(e);
-      }
-    },
-    canExecuteChange: function(opt_node) {
-      dispatchCanExecuteEvent(this, opt_node || this.ownerDocument.activeElement);
-    },
-    shortcut_: '',
-    get shortcut() {
-      return this.shortcut_;
-    },
-    set shortcut(shortcut) {
-      var oldShortcut = this.shortcut_;
-      if (shortcut !== oldShortcut) {
-        this.keyboardShortcuts_ = shortcut.split(/\s+/).map(function(shortcut) {
-          return new KeyboardShortcut(shortcut);
-        });
-        this.shortcut_ = shortcut;
-        cr.dispatchPropertyChange(this, 'shortcut', this.shortcut_, oldShortcut);
-      }
-    },
-    matchesEvent: function(e) {
-      if (!this.keyboardShortcuts_) return false;
-      return this.keyboardShortcuts_.some(function(keyboardShortcut) {
-        return keyboardShortcut.matchesEvent(e);
-      });
-    }
-  };
-  cr.defineProperty(Command, 'label', cr.PropertyKind.ATTR);
-  cr.defineProperty(Command, 'disabled', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'hidden', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'checked', cr.PropertyKind.BOOL_ATTR);
-  cr.defineProperty(Command, 'hideShortcutText', cr.PropertyKind.BOOL_ATTR);
-  function dispatchCanExecuteEvent(command, target) {
-    var e = new CanExecuteEvent(command);
-    target.dispatchEvent(e);
-    command.disabled = !e.canExecute;
-  }
-  var commandManagers = {};
-  function CommandManager(doc) {
-    doc.addEventListener('focus', this.handleFocus_.bind(this), true);
-    doc.addEventListener('keydown', this.handleKeyDown_.bind(this), false);
-  }
-  CommandManager.init = function(doc) {
-    var uid = cr.getUid(doc);
-    if (!(uid in commandManagers)) {
-      commandManagers[uid] = new CommandManager(doc);
-    }
-  };
-  CommandManager.prototype = {
-    handleFocus_: function(e) {
-      var target = e.target;
-      if (target.menu || target.command) return;
-      var commands = Array.prototype.slice.call(target.ownerDocument.querySelectorAll('command'));
-      commands.forEach(function(command) {
-        dispatchCanExecuteEvent(command, target);
-      });
-    },
-    handleKeyDown_: function(e) {
-      var target = e.target;
-      var commands = Array.prototype.slice.call(target.ownerDocument.querySelectorAll('command'));
-      for (var i = 0, command; command = commands[i]; i++) {
-        if (command.matchesEvent(e)) {
-          command.canExecuteChange();
-          if (!command.disabled) {
-            e.preventDefault();
-            e.stopPropagation();
-            command.execute();
-            return;
-          }
-        }
-      }
-    }
-  };
-  function CanExecuteEvent(command) {
-    var e = new Event('canExecute', {
-      bubbles: true,
-      cancelable: true
-    });
-    e.__proto__ = CanExecuteEvent.prototype;
-    e.command = command;
-    return e;
-  }
-  CanExecuteEvent.prototype = {
-    __proto__: Event.prototype,
-    command: null,
-    canExecute_: false,
-    get canExecute() {
-      return this.canExecute_;
-    },
-    set canExecute(canExecute) {
-      this.canExecute_ = !!canExecute;
-      this.stopPropagation();
-      this.preventDefault();
-    }
-  };
-  return {
-    Command: Command,
-    CanExecuteEvent: CanExecuteEvent
-  };
-});
-
-Polymer({
-  is: 'iron-media-query',
-  properties: {
-    queryMatches: {
-      type: Boolean,
-      value: false,
-      readOnly: true,
-      notify: true
-    },
-    query: {
-      type: String,
-      observer: 'queryChanged'
-    },
-    full: {
-      type: Boolean,
-      value: false
-    },
-    _boundMQHandler: {
-      value: function() {
-        return this.queryHandler.bind(this);
-      }
-    },
-    _mq: {
-      value: null
-    }
-  },
-  attached: function() {
-    this.style.display = 'none';
-    this.queryChanged();
-  },
-  detached: function() {
-    this._remove();
-  },
-  _add: function() {
-    if (this._mq) {
-      this._mq.addListener(this._boundMQHandler);
-    }
-  },
-  _remove: function() {
-    if (this._mq) {
-      this._mq.removeListener(this._boundMQHandler);
-    }
-    this._mq = null;
-  },
-  queryChanged: function() {
-    this._remove();
-    var query = this.query;
-    if (!query) {
-      return;
-    }
-    if (!this.full && query[0] !== '(') {
-      query = '(' + query + ')';
-    }
-    this._mq = window.matchMedia(query);
-    this._add();
-    this.queryHandler(this._mq);
-  },
-  queryHandler: function(mq) {
-    this._setQueryMatches(mq.matches);
-  }
-});
-
-Polymer.IronResizableBehavior = {
-  properties: {
-    _parentResizable: {
-      type: Object,
-      observer: '_parentResizableChanged'
-    },
-    _notifyingDescendant: {
-      type: Boolean,
-      value: false
-    }
-  },
-  listeners: {
-    'iron-request-resize-notifications': '_onIronRequestResizeNotifications'
-  },
-  created: function() {
-    this._interestedResizables = [];
-    this._boundNotifyResize = this.notifyResize.bind(this);
-  },
-  attached: function() {
-    this.fire('iron-request-resize-notifications', null, {
-      node: this,
-      bubbles: true,
-      cancelable: true
-    });
-    if (!this._parentResizable) {
-      window.addEventListener('resize', this._boundNotifyResize);
-      this.notifyResize();
-    }
-  },
-  detached: function() {
-    if (this._parentResizable) {
-      this._parentResizable.stopResizeNotificationsFor(this);
-    } else {
-      window.removeEventListener('resize', this._boundNotifyResize);
-    }
-    this._parentResizable = null;
-  },
-  notifyResize: function() {
-    if (!this.isAttached) {
-      return;
-    }
-    this._interestedResizables.forEach(function(resizable) {
-      if (this.resizerShouldNotify(resizable)) {
-        this._notifyDescendant(resizable);
-      }
-    }, this);
-    this._fireResize();
-  },
-  assignParentResizable: function(parentResizable) {
-    this._parentResizable = parentResizable;
-  },
-  stopResizeNotificationsFor: function(target) {
-    var index = this._interestedResizables.indexOf(target);
-    if (index > -1) {
-      this._interestedResizables.splice(index, 1);
-      this.unlisten(target, 'iron-resize', '_onDescendantIronResize');
-    }
-  },
-  resizerShouldNotify: function(element) {
-    return true;
-  },
-  _onDescendantIronResize: function(event) {
-    if (this._notifyingDescendant) {
-      event.stopPropagation();
-      return;
-    }
-    if (!Polymer.Settings.useShadow) {
-      this._fireResize();
-    }
-  },
-  _fireResize: function() {
-    this.fire('iron-resize', null, {
-      node: this,
-      bubbles: false
-    });
-  },
-  _onIronRequestResizeNotifications: function(event) {
-    var target = event.path ? event.path[0] : event.target;
-    if (target === this) {
-      return;
-    }
-    if (this._interestedResizables.indexOf(target) === -1) {
-      this._interestedResizables.push(target);
-      this.listen(target, 'iron-resize', '_onDescendantIronResize');
-    }
-    target.assignParentResizable(this);
-    this._notifyDescendant(target);
-    event.stopPropagation();
-  },
-  _parentResizableChanged: function(parentResizable) {
-    if (parentResizable) {
-      window.removeEventListener('resize', this._boundNotifyResize);
-    }
-  },
-  _notifyDescendant: function(descendant) {
-    if (!this.isAttached) {
-      return;
-    }
-    this._notifyingDescendant = true;
-    descendant.notifyResize();
-    this._notifyingDescendant = false;
-  }
-};
-
-Polymer.IronSelection = function(selectCallback) {
-  this.selection = [];
-  this.selectCallback = selectCallback;
-};
-
-Polymer.IronSelection.prototype = {
-  get: function() {
-    return this.multi ? this.selection.slice() : this.selection[0];
-  },
-  clear: function(excludes) {
-    this.selection.slice().forEach(function(item) {
-      if (!excludes || excludes.indexOf(item) < 0) {
-        this.setItemSelected(item, false);
-      }
-    }, this);
-  },
-  isSelected: function(item) {
-    return this.selection.indexOf(item) >= 0;
-  },
-  setItemSelected: function(item, isSelected) {
-    if (item != null) {
-      if (isSelected !== this.isSelected(item)) {
-        if (isSelected) {
-          this.selection.push(item);
-        } else {
-          var i = this.selection.indexOf(item);
-          if (i >= 0) {
-            this.selection.splice(i, 1);
-          }
-        }
-        if (this.selectCallback) {
-          this.selectCallback(item, isSelected);
-        }
-      }
-    }
-  },
-  select: function(item) {
-    if (this.multi) {
-      this.toggle(item);
-    } else if (this.get() !== item) {
-      this.setItemSelected(this.get(), false);
-      this.setItemSelected(item, true);
-    }
-  },
-  toggle: function(item) {
-    this.setItemSelected(item, !this.isSelected(item));
-  }
-};
-
-Polymer.IronSelectableBehavior = {
-  properties: {
-    attrForSelected: {
-      type: String,
-      value: null
-    },
-    selected: {
-      type: String,
-      notify: true
-    },
-    selectedItem: {
-      type: Object,
-      readOnly: true,
-      notify: true
-    },
-    activateEvent: {
-      type: String,
-      value: 'tap',
-      observer: '_activateEventChanged'
-    },
-    selectable: String,
-    selectedClass: {
-      type: String,
-      value: 'iron-selected'
-    },
-    selectedAttribute: {
-      type: String,
-      value: null
-    },
-    fallbackSelection: {
-      type: String,
-      value: null
-    },
-    items: {
-      type: Array,
-      readOnly: true,
-      notify: true,
-      value: function() {
-        return [];
-      }
-    },
-    _excludedLocalNames: {
-      type: Object,
-      value: function() {
-        return {
-          template: 1
-        };
-      }
-    }
-  },
-  observers: [ '_updateAttrForSelected(attrForSelected)', '_updateSelected(selected)', '_checkFallback(fallbackSelection)' ],
-  created: function() {
-    this._bindFilterItem = this._filterItem.bind(this);
-    this._selection = new Polymer.IronSelection(this._applySelection.bind(this));
-  },
-  attached: function() {
-    this._observer = this._observeItems(this);
-    this._updateItems();
-    if (!this._shouldUpdateSelection) {
-      this._updateSelected();
-    }
-    this._addListener(this.activateEvent);
-  },
-  detached: function() {
-    if (this._observer) {
-      Polymer.dom(this).unobserveNodes(this._observer);
-    }
-    this._removeListener(this.activateEvent);
-  },
-  indexOf: function(item) {
-    return this.items.indexOf(item);
-  },
-  select: function(value) {
-    this.selected = value;
-  },
-  selectPrevious: function() {
-    var length = this.items.length;
-    var index = (Number(this._valueToIndex(this.selected)) - 1 + length) % length;
-    this.selected = this._indexToValue(index);
-  },
-  selectNext: function() {
-    var index = (Number(this._valueToIndex(this.selected)) + 1) % this.items.length;
-    this.selected = this._indexToValue(index);
-  },
-  selectIndex: function(index) {
-    this.select(this._indexToValue(index));
-  },
-  forceSynchronousItemUpdate: function() {
-    this._updateItems();
-  },
-  get _shouldUpdateSelection() {
-    return this.selected != null;
-  },
-  _checkFallback: function() {
-    if (this._shouldUpdateSelection) {
-      this._updateSelected();
-    }
-  },
-  _addListener: function(eventName) {
-    this.listen(this, eventName, '_activateHandler');
-  },
-  _removeListener: function(eventName) {
-    this.unlisten(this, eventName, '_activateHandler');
-  },
-  _activateEventChanged: function(eventName, old) {
-    this._removeListener(old);
-    this._addListener(eventName);
-  },
-  _updateItems: function() {
-    var nodes = Polymer.dom(this).queryDistributedElements(this.selectable || '*');
-    nodes = Array.prototype.filter.call(nodes, this._bindFilterItem);
-    this._setItems(nodes);
-  },
-  _updateAttrForSelected: function() {
-    if (this._shouldUpdateSelection) {
-      this.selected = this._indexToValue(this.indexOf(this.selectedItem));
-    }
-  },
-  _updateSelected: function() {
-    this._selectSelected(this.selected);
-  },
-  _selectSelected: function(selected) {
-    this._selection.select(this._valueToItem(this.selected));
-    if (this.fallbackSelection && this.items.length && this._selection.get() === undefined) {
-      this.selected = this.fallbackSelection;
-    }
-  },
-  _filterItem: function(node) {
-    return !this._excludedLocalNames[node.localName];
-  },
-  _valueToItem: function(value) {
-    return value == null ? null : this.items[this._valueToIndex(value)];
-  },
-  _valueToIndex: function(value) {
-    if (this.attrForSelected) {
-      for (var i = 0, item; item = this.items[i]; i++) {
-        if (this._valueForItem(item) == value) {
-          return i;
-        }
-      }
-    } else {
-      return Number(value);
-    }
-  },
-  _indexToValue: function(index) {
-    if (this.attrForSelected) {
-      var item = this.items[index];
-      if (item) {
-        return this._valueForItem(item);
-      }
-    } else {
-      return index;
-    }
-  },
-  _valueForItem: function(item) {
-    var propValue = item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];
-    return propValue != undefined ? propValue : item.getAttribute(this.attrForSelected);
-  },
-  _applySelection: function(item, isSelected) {
-    if (this.selectedClass) {
-      this.toggleClass(this.selectedClass, isSelected, item);
-    }
-    if (this.selectedAttribute) {
-      this.toggleAttribute(this.selectedAttribute, isSelected, item);
-    }
-    this._selectionChange();
-    this.fire('iron-' + (isSelected ? 'select' : 'deselect'), {
-      item: item
-    });
-  },
-  _selectionChange: function() {
-    this._setSelectedItem(this._selection.get());
-  },
-  _observeItems: function(node) {
-    return Polymer.dom(node).observeNodes(function(mutation) {
-      this._updateItems();
-      if (this._shouldUpdateSelection) {
-        this._updateSelected();
-      }
-      this.fire('iron-items-changed', mutation, {
-        bubbles: false,
-        cancelable: false
-      });
-    });
-  },
-  _activateHandler: function(e) {
-    var t = e.target;
-    var items = this.items;
-    while (t && t != this) {
-      var i = items.indexOf(t);
-      if (i >= 0) {
-        var value = this._indexToValue(i);
-        this._itemActivate(value, t);
-        return;
-      }
-      t = t.parentNode;
-    }
-  },
-  _itemActivate: function(value, item) {
-    if (!this.fire('iron-activate', {
-      selected: value,
-      item: item
-    }, {
-      cancelable: true
-    }).defaultPrevented) {
-      this.select(value);
-    }
-  }
-};
-
-Polymer({
-  is: 'iron-pages',
-  behaviors: [ Polymer.IronResizableBehavior, Polymer.IronSelectableBehavior ],
-  properties: {
-    activateEvent: {
-      type: String,
-      value: null
-    }
-  },
-  observers: [ '_selectedPageChanged(selected)' ],
-  _selectedPageChanged: function(selected, old) {
-    this.async(this.notifyResize);
-  }
-});
-
-Polymer.IronScrollTargetBehavior = {
-  properties: {
-    scrollTarget: {
-      type: HTMLElement,
-      value: function() {
-        return this._defaultScrollTarget;
-      }
-    }
-  },
-  observers: [ '_scrollTargetChanged(scrollTarget, isAttached)' ],
-  _scrollTargetChanged: function(scrollTarget, isAttached) {
-    var eventTarget;
-    if (this._oldScrollTarget) {
-      eventTarget = this._oldScrollTarget === this._doc ? window : this._oldScrollTarget;
-      eventTarget.removeEventListener('scroll', this._boundScrollHandler);
-      this._oldScrollTarget = null;
-    }
-    if (!isAttached) {
-      return;
-    }
-    if (scrollTarget === 'document') {
-      this.scrollTarget = this._doc;
-    } else if (typeof scrollTarget === 'string') {
-      this.scrollTarget = this.domHost ? this.domHost.$[scrollTarget] : Polymer.dom(this.ownerDocument).querySelector('#' + scrollTarget);
-    } else if (this._isValidScrollTarget()) {
-      eventTarget = scrollTarget === this._doc ? window : scrollTarget;
-      this._boundScrollHandler = this._boundScrollHandler || this._scrollHandler.bind(this);
-      this._oldScrollTarget = scrollTarget;
-      eventTarget.addEventListener('scroll', this._boundScrollHandler);
-    }
-  },
-  _scrollHandler: function scrollHandler() {},
-  get _defaultScrollTarget() {
-    return this._doc;
-  },
-  get _doc() {
-    return this.ownerDocument.documentElement;
-  },
-  get _scrollTop() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.pageYOffset : this.scrollTarget.scrollTop;
-    }
-    return 0;
-  },
-  get _scrollLeft() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.pageXOffset : this.scrollTarget.scrollLeft;
-    }
-    return 0;
-  },
-  set _scrollTop(top) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(window.pageXOffset, top);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollTop = top;
-    }
-  },
-  set _scrollLeft(left) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(left, window.pageYOffset);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollLeft = left;
-    }
-  },
-  scroll: function(left, top) {
-    if (this.scrollTarget === this._doc) {
-      window.scrollTo(left, top);
-    } else if (this._isValidScrollTarget()) {
-      this.scrollTarget.scrollLeft = left;
-      this.scrollTarget.scrollTop = top;
-    }
-  },
-  get _scrollTargetWidth() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.innerWidth : this.scrollTarget.offsetWidth;
-    }
-    return 0;
-  },
-  get _scrollTargetHeight() {
-    if (this._isValidScrollTarget()) {
-      return this.scrollTarget === this._doc ? window.innerHeight : this.scrollTarget.offsetHeight;
-    }
-    return 0;
-  },
-  _isValidScrollTarget: function() {
-    return this.scrollTarget instanceof HTMLElement;
-  }
-};
-
-(function() {
-  var metaDatas = {};
-  var metaArrays = {};
-  var singleton = null;
-  Polymer.IronMeta = Polymer({
-    is: 'iron-meta',
-    properties: {
-      type: {
-        type: String,
-        value: 'default',
-        observer: '_typeChanged'
-      },
-      key: {
-        type: String,
-        observer: '_keyChanged'
-      },
-      value: {
-        type: Object,
-        notify: true,
-        observer: '_valueChanged'
-      },
-      self: {
-        type: Boolean,
-        observer: '_selfChanged'
-      },
-      list: {
-        type: Array,
-        notify: true
-      }
-    },
-    hostAttributes: {
-      hidden: true
-    },
-    factoryImpl: function(config) {
-      if (config) {
-        for (var n in config) {
-          switch (n) {
-           case 'type':
-           case 'key':
-           case 'value':
-            this[n] = config[n];
-            break;
-          }
-        }
-      }
-    },
-    created: function() {
-      this._metaDatas = metaDatas;
-      this._metaArrays = metaArrays;
-    },
-    _keyChanged: function(key, old) {
-      this._resetRegistration(old);
-    },
-    _valueChanged: function(value) {
-      this._resetRegistration(this.key);
-    },
-    _selfChanged: function(self) {
-      if (self) {
-        this.value = this;
-      }
-    },
-    _typeChanged: function(type) {
-      this._unregisterKey(this.key);
-      if (!metaDatas[type]) {
-        metaDatas[type] = {};
-      }
-      this._metaData = metaDatas[type];
-      if (!metaArrays[type]) {
-        metaArrays[type] = [];
-      }
-      this.list = metaArrays[type];
-      this._registerKeyValue(this.key, this.value);
-    },
-    byKey: function(key) {
-      return this._metaData && this._metaData[key];
-    },
-    _resetRegistration: function(oldKey) {
-      this._unregisterKey(oldKey);
-      this._registerKeyValue(this.key, this.value);
-    },
-    _unregisterKey: function(key) {
-      this._unregister(key, this._metaData, this.list);
-    },
-    _registerKeyValue: function(key, value) {
-      this._register(key, value, this._metaData, this.list);
-    },
-    _register: function(key, value, data, list) {
-      if (key && data && value !== undefined) {
-        data[key] = value;
-        list.push(value);
-      }
-    },
-    _unregister: function(key, data, list) {
-      if (key && data) {
-        if (key in data) {
-          var value = data[key];
-          delete data[key];
-          this.arrayDelete(list, value);
-        }
-      }
-    }
-  });
-  Polymer.IronMeta.getIronMeta = function getIronMeta() {
-    if (singleton === null) {
-      singleton = new Polymer.IronMeta();
-    }
-    return singleton;
-  };
-  Polymer.IronMetaQuery = Polymer({
-    is: 'iron-meta-query',
-    properties: {
-      type: {
-        type: String,
-        value: 'default',
-        observer: '_typeChanged'
-      },
-      key: {
-        type: String,
-        observer: '_keyChanged'
-      },
-      value: {
-        type: Object,
-        notify: true,
-        readOnly: true
-      },
-      list: {
-        type: Array,
-        notify: true
-      }
-    },
-    factoryImpl: function(config) {
-      if (config) {
-        for (var n in config) {
-          switch (n) {
-           case 'type':
-           case 'key':
-            this[n] = config[n];
-            break;
-          }
-        }
-      }
-    },
-    created: function() {
-      this._metaDatas = metaDatas;
-      this._metaArrays = metaArrays;
-    },
-    _keyChanged: function(key) {
-      this._setValue(this._metaData && this._metaData[key]);
-    },
-    _typeChanged: function(type) {
-      this._metaData = metaDatas[type];
-      this.list = metaArrays[type];
-      if (this.key) {
-        this._keyChanged(this.key);
-      }
-    },
-    byKey: function(key) {
-      return this._metaData && this._metaData[key];
-    }
-  });
-})();
-
-Polymer({
-  is: 'iron-icon',
-  properties: {
-    icon: {
-      type: String,
-      observer: '_iconChanged'
-    },
-    theme: {
-      type: String,
-      observer: '_updateIcon'
-    },
-    src: {
-      type: String,
-      observer: '_srcChanged'
-    },
-    _meta: {
-      value: Polymer.Base.create('iron-meta', {
-        type: 'iconset'
-      }),
-      observer: '_updateIcon'
-    }
-  },
-  _DEFAULT_ICONSET: 'icons',
-  _iconChanged: function(icon) {
-    var parts = (icon || '').split(':');
-    this._iconName = parts.pop();
-    this._iconsetName = parts.pop() || this._DEFAULT_ICONSET;
-    this._updateIcon();
-  },
-  _srcChanged: function(src) {
-    this._updateIcon();
-  },
-  _usesIconset: function() {
-    return this.icon || !this.src;
-  },
-  _updateIcon: function() {
-    if (this._usesIconset()) {
-      if (this._img && this._img.parentNode) {
-        Polymer.dom(this.root).removeChild(this._img);
-      }
-      if (this._iconName === "") {
-        if (this._iconset) {
-          this._iconset.removeIcon(this);
-        }
-      } else if (this._iconsetName && this._meta) {
-        this._iconset = this._meta.byKey(this._iconsetName);
-        if (this._iconset) {
-          this._iconset.applyIcon(this, this._iconName, this.theme);
-          this.unlisten(window, 'iron-iconset-added', '_updateIcon');
-        } else {
-          this.listen(window, 'iron-iconset-added', '_updateIcon');
-        }
-      }
-    } else {
-      if (this._iconset) {
-        this._iconset.removeIcon(this);
-      }
-      if (!this._img) {
-        this._img = document.createElement('img');
-        this._img.style.width = '100%';
-        this._img.style.height = '100%';
-        this._img.draggable = false;
-      }
-      this._img.src = this.src;
-      Polymer.dom(this.root).appendChild(this._img);
-    }
-  }
-});
-
-(function() {
-  'use strict';
-  var KEY_IDENTIFIER = {
-    'U+0008': 'backspace',
-    'U+0009': 'tab',
-    'U+001B': 'esc',
-    'U+0020': 'space',
-    'U+007F': 'del'
-  };
-  var KEY_CODE = {
-    8: 'backspace',
-    9: 'tab',
-    13: 'enter',
-    27: 'esc',
-    33: 'pageup',
-    34: 'pagedown',
-    35: 'end',
-    36: 'home',
-    32: 'space',
-    37: 'left',
-    38: 'up',
-    39: 'right',
-    40: 'down',
-    46: 'del',
-    106: '*'
-  };
-  var MODIFIER_KEYS = {
-    shift: 'shiftKey',
-    ctrl: 'ctrlKey',
-    alt: 'altKey',
-    meta: 'metaKey'
-  };
-  var KEY_CHAR = /[a-z0-9*]/;
-  var IDENT_CHAR = /U\+/;
-  var ARROW_KEY = /^arrow/;
-  var SPACE_KEY = /^space(bar)?/;
-  var ESC_KEY = /^escape$/;
-  function transformKey(key, noSpecialChars) {
-    var validKey = '';
-    if (key) {
-      var lKey = key.toLowerCase();
-      if (lKey === ' ' || SPACE_KEY.test(lKey)) {
-        validKey = 'space';
-      } else if (ESC_KEY.test(lKey)) {
-        validKey = 'esc';
-      } else if (lKey.length == 1) {
-        if (!noSpecialChars || KEY_CHAR.test(lKey)) {
-          validKey = lKey;
-        }
-      } else if (ARROW_KEY.test(lKey)) {
-        validKey = lKey.replace('arrow', '');
-      } else if (lKey == 'multiply') {
-        validKey = '*';
-      } else {
-        validKey = lKey;
-      }
-    }
-    return validKey;
-  }
-  function transformKeyIdentifier(keyIdent) {
-    var validKey = '';
-    if (keyIdent) {
-      if (keyIdent in KEY_IDENTIFIER) {
-        validKey = KEY_IDENTIFIER[keyIdent];
-      } else if (IDENT_CHAR.test(keyIdent)) {
-        keyIdent = parseInt(keyIdent.replace('U+', '0x'), 16);
-        validKey = String.fromCharCode(keyIdent).toLowerCase();
-      } else {
-        validKey = keyIdent.toLowerCase();
-      }
-    }
-    return validKey;
-  }
-  function transformKeyCode(keyCode) {
-    var validKey = '';
-    if (Number(keyCode)) {
-      if (keyCode >= 65 && keyCode <= 90) {
-        validKey = String.fromCharCode(32 + keyCode);
-      } else if (keyCode >= 112 && keyCode <= 123) {
-        validKey = 'f' + (keyCode - 112);
-      } else if (keyCode >= 48 && keyCode <= 57) {
-        validKey = String(keyCode - 48);
-      } else if (keyCode >= 96 && keyCode <= 105) {
-        validKey = String(keyCode - 96);
-      } else {
-        validKey = KEY_CODE[keyCode];
-      }
-    }
-    return validKey;
-  }
-  function normalizedKeyForEvent(keyEvent, noSpecialChars) {
-    if (keyEvent.key) {
-      return transformKey(keyEvent.key, noSpecialChars);
-    }
-    if (keyEvent.detail && keyEvent.detail.key) {
-      return transformKey(keyEvent.detail.key, noSpecialChars);
-    }
-    return transformKeyIdentifier(keyEvent.keyIdentifier) || transformKeyCode(keyEvent.keyCode) || '';
-  }
-  function keyComboMatchesEvent(keyCombo, event) {
-    var keyEvent = normalizedKeyForEvent(event, keyCombo.hasModifiers);
-    return keyEvent === keyCombo.key && (!keyCombo.hasModifiers || !!event.shiftKey === !!keyCombo.shiftKey && !!event.ctrlKey === !!keyCombo.ctrlKey && !!event.altKey === !!keyCombo.altKey && !!event.metaKey === !!keyCombo.metaKey);
-  }
-  function parseKeyComboString(keyComboString) {
-    if (keyComboString.length === 1) {
-      return {
-        combo: keyComboString,
-        key: keyComboString,
-        event: 'keydown'
-      };
-    }
-    return keyComboString.split('+').reduce(function(parsedKeyCombo, keyComboPart) {
-      var eventParts = keyComboPart.split(':');
-      var keyName = eventParts[0];
-      var event = eventParts[1];
-      if (keyName in MODIFIER_KEYS) {
-        parsedKeyCombo[MODIFIER_KEYS[keyName]] = true;
-        parsedKeyCombo.hasModifiers = true;
-      } else {
-        parsedKeyCombo.key = keyName;
-        parsedKeyCombo.event = event || 'keydown';
-      }
-      return parsedKeyCombo;
-    }, {
-      combo: keyComboString.split(':').shift()
-    });
-  }
-  function parseEventString(eventString) {
-    return eventString.trim().split(' ').map(function(keyComboString) {
-      return parseKeyComboString(keyComboString);
-    });
-  }
-  Polymer.IronA11yKeysBehavior = {
-    properties: {
-      keyEventTarget: {
-        type: Object,
-        value: function() {
-          return this;
-        }
-      },
-      stopKeyboardEventPropagation: {
-        type: Boolean,
-        value: false
-      },
-      _boundKeyHandlers: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      _imperativeKeyBindings: {
-        type: Object,
-        value: function() {
-          return {};
-        }
-      }
-    },
-    observers: [ '_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)' ],
-    keyBindings: {},
-    registered: function() {
-      this._prepKeyBindings();
-    },
-    attached: function() {
-      this._listenKeyEventListeners();
-    },
-    detached: function() {
-      this._unlistenKeyEventListeners();
-    },
-    addOwnKeyBinding: function(eventString, handlerName) {
-      this._imperativeKeyBindings[eventString] = handlerName;
-      this._prepKeyBindings();
-      this._resetKeyEventListeners();
-    },
-    removeOwnKeyBindings: function() {
-      this._imperativeKeyBindings = {};
-      this._prepKeyBindings();
-      this._resetKeyEventListeners();
-    },
-    keyboardEventMatchesKeys: function(event, eventString) {
-      var keyCombos = parseEventString(eventString);
-      for (var i = 0; i < keyCombos.length; ++i) {
-        if (keyComboMatchesEvent(keyCombos[i], event)) {
-          return true;
-        }
-      }
-      return false;
-    },
-    _collectKeyBindings: function() {
-      var keyBindings = this.behaviors.map(function(behavior) {
-        return behavior.keyBindings;
-      });
-      if (keyBindings.indexOf(this.keyBindings) === -1) {
-        keyBindings.push(this.keyBindings);
-      }
-      return keyBindings;
-    },
-    _prepKeyBindings: function() {
-      this._keyBindings = {};
-      this._collectKeyBindings().forEach(function(keyBindings) {
-        for (var eventString in keyBindings) {
-          this._addKeyBinding(eventString, keyBindings[eventString]);
-        }
-      }, this);
-      for (var eventString in this._imperativeKeyBindings) {
-        this._addKeyBinding(eventString, this._imperativeKeyBindings[eventString]);
-      }
-      for (var eventName in this._keyBindings) {
-        this._keyBindings[eventName].sort(function(kb1, kb2) {
-          var b1 = kb1[0].hasModifiers;
-          var b2 = kb2[0].hasModifiers;
-          return b1 === b2 ? 0 : b1 ? -1 : 1;
-        });
-      }
-    },
-    _addKeyBinding: function(eventString, handlerName) {
-      parseEventString(eventString).forEach(function(keyCombo) {
-        this._keyBindings[keyCombo.event] = this._keyBindings[keyCombo.event] || [];
-        this._keyBindings[keyCombo.event].push([ keyCombo, handlerName ]);
-      }, this);
-    },
-    _resetKeyEventListeners: function() {
-      this._unlistenKeyEventListeners();
-      if (this.isAttached) {
-        this._listenKeyEventListeners();
-      }
-    },
-    _listenKeyEventListeners: function() {
-      if (!this.keyEventTarget) {
-        return;
-      }
-      Object.keys(this._keyBindings).forEach(function(eventName) {
-        var keyBindings = this._keyBindings[eventName];
-        var boundKeyHandler = this._onKeyBindingEvent.bind(this, keyBindings);
-        this._boundKeyHandlers.push([ this.keyEventTarget, eventName, boundKeyHandler ]);
-        this.keyEventTarget.addEventListener(eventName, boundKeyHandler);
-      }, this);
-    },
-    _unlistenKeyEventListeners: function() {
-      var keyHandlerTuple;
-      var keyEventTarget;
-      var eventName;
-      var boundKeyHandler;
-      while (this._boundKeyHandlers.length) {
-        keyHandlerTuple = this._boundKeyHandlers.pop();
-        keyEventTarget = keyHandlerTuple[0];
-        eventName = keyHandlerTuple[1];
-        boundKeyHandler = keyHandlerTuple[2];
-        keyEventTarget.removeEventListener(eventName, boundKeyHandler);
-      }
-    },
-    _onKeyBindingEvent: function(keyBindings, event) {
-      if (this.stopKeyboardEventPropagation) {
-        event.stopPropagation();
-      }
-      if (event.defaultPrevented) {
-        return;
-      }
-      for (var i = 0; i < keyBindings.length; i++) {
-        var keyCombo = keyBindings[i][0];
-        var handlerName = keyBindings[i][1];
-        if (keyComboMatchesEvent(keyCombo, event)) {
-          this._triggerKeyHandler(keyCombo, handlerName, event);
-          if (event.defaultPrevented) {
-            return;
-          }
-        }
-      }
-    },
-    _triggerKeyHandler: function(keyCombo, handlerName, keyboardEvent) {
-      var detail = Object.create(keyCombo);
-      detail.keyboardEvent = keyboardEvent;
-      var event = new CustomEvent(keyCombo.event, {
-        detail: detail,
-        cancelable: true
-      });
-      this[handlerName].call(this, event);
-      if (event.defaultPrevented) {
-        keyboardEvent.preventDefault();
-      }
-    }
-  };
-})();
-
-Polymer.IronControlState = {
-  properties: {
-    focused: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      readOnly: true,
-      reflectToAttribute: true
-    },
-    disabled: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: '_disabledChanged',
-      reflectToAttribute: true
-    },
-    _oldTabIndex: {
-      type: Number
-    },
-    _boundFocusBlurHandler: {
-      type: Function,
-      value: function() {
-        return this._focusBlurHandler.bind(this);
-      }
-    }
-  },
-  observers: [ '_changedControlState(focused, disabled)' ],
-  ready: function() {
-    this.addEventListener('focus', this._boundFocusBlurHandler, true);
-    this.addEventListener('blur', this._boundFocusBlurHandler, true);
-  },
-  _focusBlurHandler: function(event) {
-    if (event.target === this) {
-      this._setFocused(event.type === 'focus');
-    } else if (!this.shadowRoot) {
-      var target = Polymer.dom(event).localTarget;
-      if (!this.isLightDescendant(target)) {
-        this.fire(event.type, {
-          sourceEvent: event
-        }, {
-          node: this,
-          bubbles: event.bubbles,
-          cancelable: event.cancelable
-        });
-      }
-    }
-  },
-  _disabledChanged: function(disabled, old) {
-    this.setAttribute('aria-disabled', disabled ? 'true' : 'false');
-    this.style.pointerEvents = disabled ? 'none' : '';
-    if (disabled) {
-      this._oldTabIndex = this.tabIndex;
-      this._setFocused(false);
-      this.tabIndex = -1;
-      this.blur();
-    } else if (this._oldTabIndex !== undefined) {
-      this.tabIndex = this._oldTabIndex;
-    }
-  },
-  _changedControlState: function() {
-    if (this._controlStateChanged) {
-      this._controlStateChanged();
-    }
-  }
-};
-
-Polymer.IronButtonStateImpl = {
-  properties: {
-    pressed: {
-      type: Boolean,
-      readOnly: true,
-      value: false,
-      reflectToAttribute: true,
-      observer: '_pressedChanged'
-    },
-    toggles: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    active: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      reflectToAttribute: true
-    },
-    pointerDown: {
-      type: Boolean,
-      readOnly: true,
-      value: false
-    },
-    receivedFocusFromKeyboard: {
-      type: Boolean,
-      readOnly: true
-    },
-    ariaActiveAttribute: {
-      type: String,
-      value: 'aria-pressed',
-      observer: '_ariaActiveAttributeChanged'
-    }
-  },
-  listeners: {
-    down: '_downHandler',
-    up: '_upHandler',
-    tap: '_tapHandler'
-  },
-  observers: [ '_detectKeyboardFocus(focused)', '_activeChanged(active, ariaActiveAttribute)' ],
-  keyBindings: {
-    'enter:keydown': '_asyncClick',
-    'space:keydown': '_spaceKeyDownHandler',
-    'space:keyup': '_spaceKeyUpHandler'
-  },
-  _mouseEventRe: /^mouse/,
-  _tapHandler: function() {
-    if (this.toggles) {
-      this._userActivate(!this.active);
-    } else {
-      this.active = false;
-    }
-  },
-  _detectKeyboardFocus: function(focused) {
-    this._setReceivedFocusFromKeyboard(!this.pointerDown && focused);
-  },
-  _userActivate: function(active) {
-    if (this.active !== active) {
-      this.active = active;
-      this.fire('change');
-    }
-  },
-  _downHandler: function(event) {
-    this._setPointerDown(true);
-    this._setPressed(true);
-    this._setReceivedFocusFromKeyboard(false);
-  },
-  _upHandler: function() {
-    this._setPointerDown(false);
-    this._setPressed(false);
-  },
-  _spaceKeyDownHandler: function(event) {
-    var keyboardEvent = event.detail.keyboardEvent;
-    var target = Polymer.dom(keyboardEvent).localTarget;
-    if (this.isLightDescendant(target)) return;
-    keyboardEvent.preventDefault();
-    keyboardEvent.stopImmediatePropagation();
-    this._setPressed(true);
-  },
-  _spaceKeyUpHandler: function(event) {
-    var keyboardEvent = event.detail.keyboardEvent;
-    var target = Polymer.dom(keyboardEvent).localTarget;
-    if (this.isLightDescendant(target)) return;
-    if (this.pressed) {
-      this._asyncClick();
-    }
-    this._setPressed(false);
-  },
-  _asyncClick: function() {
-    this.async(function() {
-      this.click();
-    }, 1);
-  },
-  _pressedChanged: function(pressed) {
-    this._changedButtonState();
-  },
-  _ariaActiveAttributeChanged: function(value, oldValue) {
-    if (oldValue && oldValue != value && this.hasAttribute(oldValue)) {
-      this.removeAttribute(oldValue);
-    }
-  },
-  _activeChanged: function(active, ariaActiveAttribute) {
-    if (this.toggles) {
-      this.setAttribute(this.ariaActiveAttribute, active ? 'true' : 'false');
-    } else {
-      this.removeAttribute(this.ariaActiveAttribute);
-    }
-    this._changedButtonState();
-  },
-  _controlStateChanged: function() {
-    if (this.disabled) {
-      this._setPressed(false);
-    } else {
-      this._changedButtonState();
-    }
-  },
-  _changedButtonState: function() {
-    if (this._buttonStateChanged) {
-      this._buttonStateChanged();
-    }
-  }
-};
-
-Polymer.IronButtonState = [ Polymer.IronA11yKeysBehavior, Polymer.IronButtonStateImpl ];
-
-(function() {
-  var Utility = {
-    distance: function(x1, y1, x2, y2) {
-      var xDelta = x1 - x2;
-      var yDelta = y1 - y2;
-      return Math.sqrt(xDelta * xDelta + yDelta * yDelta);
-    },
-    now: window.performance && window.performance.now ? window.performance.now.bind(window.performance) : Date.now
-  };
-  function ElementMetrics(element) {
-    this.element = element;
-    this.width = this.boundingRect.width;
-    this.height = this.boundingRect.height;
-    this.size = Math.max(this.width, this.height);
-  }
-  ElementMetrics.prototype = {
-    get boundingRect() {
-      return this.element.getBoundingClientRect();
-    },
-    furthestCornerDistanceFrom: function(x, y) {
-      var topLeft = Utility.distance(x, y, 0, 0);
-      var topRight = Utility.distance(x, y, this.width, 0);
-      var bottomLeft = Utility.distance(x, y, 0, this.height);
-      var bottomRight = Utility.distance(x, y, this.width, this.height);
-      return Math.max(topLeft, topRight, bottomLeft, bottomRight);
-    }
-  };
-  function Ripple(element) {
-    this.element = element;
-    this.color = window.getComputedStyle(element).color;
-    this.wave = document.createElement('div');
-    this.waveContainer = document.createElement('div');
-    this.wave.style.backgroundColor = this.color;
-    this.wave.classList.add('wave');
-    this.waveContainer.classList.add('wave-container');
-    Polymer.dom(this.waveContainer).appendChild(this.wave);
-    this.resetInteractionState();
-  }
-  Ripple.MAX_RADIUS = 300;
-  Ripple.prototype = {
-    get recenters() {
-      return this.element.recenters;
-    },
-    get center() {
-      return this.element.center;
-    },
-    get mouseDownElapsed() {
-      var elapsed;
-      if (!this.mouseDownStart) {
-        return 0;
-      }
-      elapsed = Utility.now() - this.mouseDownStart;
-      if (this.mouseUpStart) {
-        elapsed -= this.mouseUpElapsed;
-      }
-      return elapsed;
-    },
-    get mouseUpElapsed() {
-      return this.mouseUpStart ? Utility.now() - this.mouseUpStart : 0;
-    },
-    get mouseDownElapsedSeconds() {
-      return this.mouseDownElapsed / 1e3;
-    },
-    get mouseUpElapsedSeconds() {
-      return this.mouseUpElapsed / 1e3;
-    },
-    get mouseInteractionSeconds() {
-      return this.mouseDownElapsedSeconds + this.mouseUpElapsedSeconds;
-    },
-    get initialOpacity() {
-      return this.element.initialOpacity;
-    },
-    get opacityDecayVelocity() {
-      return this.element.opacityDecayVelocity;
-    },
-    get radius() {
-      var width2 = this.containerMetrics.width * this.containerMetrics.width;
-      var height2 = this.containerMetrics.height * this.containerMetrics.height;
-      var waveRadius = Math.min(Math.sqrt(width2 + height2), Ripple.MAX_RADIUS) * 1.1 + 5;
-      var duration = 1.1 - .2 * (waveRadius / Ripple.MAX_RADIUS);
-      var timeNow = this.mouseInteractionSeconds / duration;
-      var size = waveRadius * (1 - Math.pow(80, -timeNow));
-      return Math.abs(size);
-    },
-    get opacity() {
-      if (!this.mouseUpStart) {
-        return this.initialOpacity;
-      }
-      return Math.max(0, this.initialOpacity - this.mouseUpElapsedSeconds * this.opacityDecayVelocity);
-    },
-    get outerOpacity() {
-      var outerOpacity = this.mouseUpElapsedSeconds * .3;
-      var waveOpacity = this.opacity;
-      return Math.max(0, Math.min(outerOpacity, waveOpacity));
-    },
-    get isOpacityFullyDecayed() {
-      return this.opacity < .01 && this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
-    },
-    get isRestingAtMaxRadius() {
-      return this.opacity >= this.initialOpacity && this.radius >= Math.min(this.maxRadius, Ripple.MAX_RADIUS);
-    },
-    get isAnimationComplete() {
-      return this.mouseUpStart ? this.isOpacityFullyDecayed : this.isRestingAtMaxRadius;
-    },
-    get translationFraction() {
-      return Math.min(1, this.radius / this.containerMetrics.size * 2 / Math.sqrt(2));
-    },
-    get xNow() {
-      if (this.xEnd) {
-        return this.xStart + this.translationFraction * (this.xEnd - this.xStart);
-      }
-      return this.xStart;
-    },
-    get yNow() {
-      if (this.yEnd) {
-        return this.yStart + this.translationFraction * (this.yEnd - this.yStart);
-      }
-      return this.yStart;
-    },
-    get isMouseDown() {
-      return this.mouseDownStart && !this.mouseUpStart;
-    },
-    resetInteractionState: function() {
-      this.maxRadius = 0;
-      this.mouseDownStart = 0;
-      this.mouseUpStart = 0;
-      this.xStart = 0;
-      this.yStart = 0;
-      this.xEnd = 0;
-      this.yEnd = 0;
-      this.slideDistance = 0;
-      this.containerMetrics = new ElementMetrics(this.element);
-    },
-    draw: function() {
-      var scale;
-      var translateString;
-      var dx;
-      var dy;
-      this.wave.style.opacity = this.opacity;
-      scale = this.radius / (this.containerMetrics.size / 2);
-      dx = this.xNow - this.containerMetrics.width / 2;
-      dy = this.yNow - this.containerMetrics.height / 2;
-      this.waveContainer.style.webkitTransform = 'translate(' + dx + 'px, ' + dy + 'px)';
-      this.waveContainer.style.transform = 'translate3d(' + dx + 'px, ' + dy + 'px, 0)';
-      this.wave.style.webkitTransform = 'scale(' + scale + ',' + scale + ')';
-      this.wave.style.transform = 'scale3d(' + scale + ',' + scale + ',1)';
-    },
-    downAction: function(event) {
-      var xCenter = this.containerMetrics.width / 2;
-      var yCenter = this.containerMetrics.height / 2;
-      this.resetInteractionState();
-      this.mouseDownStart = Utility.now();
-      if (this.center) {
-        this.xStart = xCenter;
-        this.yStart = yCenter;
-        this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEnd, this.yEnd);
-      } else {
-        this.xStart = event ? event.detail.x - this.containerMetrics.boundingRect.left : this.containerMetrics.width / 2;
-        this.yStart = event ? event.detail.y - this.containerMetrics.boundingRect.top : this.containerMetrics.height / 2;
-      }
-      if (this.recenters) {
-        this.xEnd = xCenter;
-        this.yEnd = yCenter;
-        this.slideDistance = Utility.distance(this.xStart, this.yStart, this.xEnd, this.yEnd);
-      }
-      this.maxRadius = this.containerMetrics.furthestCornerDistanceFrom(this.xStart, this.yStart);
-      this.waveContainer.style.top = (this.containerMetrics.height - this.containerMetrics.size) / 2 + 'px';
-      this.waveContainer.style.left = (this.containerMetrics.width - this.containerMetrics.size) / 2 + 'px';
-      this.waveContainer.style.width = this.containerMetrics.size + 'px';
-      this.waveContainer.style.height = this.containerMetrics.size + 'px';
-    },
-    upAction: function(event) {
-      if (!this.isMouseDown) {
-        return;
-      }
-      this.mouseUpStart = Utility.now();
-    },
-    remove: function() {
-      Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer);
-    }
-  };
-  Polymer({
-    is: 'paper-ripple',
-    behaviors: [ Polymer.IronA11yKeysBehavior ],
-    properties: {
-      initialOpacity: {
-        type: Number,
-        value: .25
-      },
-      opacityDecayVelocity: {
-        type: Number,
-        value: .8
-      },
-      recenters: {
-        type: Boolean,
-        value: false
-      },
-      center: {
-        type: Boolean,
-        value: false
-      },
-      ripples: {
-        type: Array,
-        value: function() {
-          return [];
-        }
-      },
-      animating: {
-        type: Boolean,
-        readOnly: true,
-        reflectToAttribute: true,
-        value: false
-      },
-      holdDown: {
-        type: Boolean,
-        value: false,
-        observer: '_holdDownChanged'
-      },
-      noink: {
-        type: Boolean,
-        value: false
-      },
-      _animating: {
-        type: Boolean
-      },
-      _boundAnimate: {
-        type: Function,
-        value: function() {
-          return this.animate.bind(this);
-        }
-      }
-    },
-    get target() {
-      return this.keyEventTarget;
-    },
-    keyBindings: {
-      'enter:keydown': '_onEnterKeydown',
-      'space:keydown': '_onSpaceKeydown',
-      'space:keyup': '_onSpaceKeyup'
-    },
-    attached: function() {
-      if (this.parentNode.nodeType == 11) {
-        this.keyEventTarget = Polymer.dom(this).getOwnerRoot().host;
-      } else {
-        this.keyEventTarget = this.parentNode;
-      }
-      var keyEventTarget = this.keyEventTarget;
-      this.listen(keyEventTarget, 'up', 'uiUpAction');
-      this.listen(keyEventTarget, 'down', 'uiDownAction');
-    },
-    detached: function() {
-      this.unlisten(this.keyEventTarget, 'up', 'uiUpAction');
-      this.unlisten(this.keyEventTarget, 'down', 'uiDownAction');
-      this.keyEventTarget = null;
-    },
-    get shouldKeepAnimating() {
-      for (var index = 0; index < this.ripples.length; ++index) {
-        if (!this.ripples[index].isAnimationComplete) {
-          return true;
-        }
-      }
-      return false;
-    },
-    simulatedRipple: function() {
-      this.downAction(null);
-      this.async(function() {
-        this.upAction();
-      }, 1);
-    },
-    uiDownAction: function(event) {
-      if (!this.noink) {
-        this.downAction(event);
-      }
-    },
-    downAction: function(event) {
-      if (this.holdDown && this.ripples.length > 0) {
-        return;
-      }
-      var ripple = this.addRipple();
-      ripple.downAction(event);
-      if (!this._animating) {
-        this._animating = true;
-        this.animate();
-      }
-    },
-    uiUpAction: function(event) {
-      if (!this.noink) {
-        this.upAction(event);
-      }
-    },
-    upAction: function(event) {
-      if (this.holdDown) {
-        return;
-      }
-      this.ripples.forEach(function(ripple) {
-        ripple.upAction(event);
-      });
-      this._animating = true;
-      this.animate();
-    },
-    onAnimationComplete: function() {
-      this._animating = false;
-      this.$.background.style.backgroundColor = null;
-      this.fire('transitionend');
-    },
-    addRipple: function() {
-      var ripple = new Ripple(this);
-      Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);
-      this.$.background.style.backgroundColor = ripple.color;
-      this.ripples.push(ripple);
-      this._setAnimating(true);
-      return ripple;
-    },
-    removeRipple: function(ripple) {
-      var rippleIndex = this.ripples.indexOf(ripple);
-      if (rippleIndex < 0) {
-        return;
-      }
-      this.ripples.splice(rippleIndex, 1);
-      ripple.remove();
-      if (!this.ripples.length) {
-        this._setAnimating(false);
-      }
-    },
-    animate: function() {
-      if (!this._animating) {
-        return;
-      }
-      var index;
-      var ripple;
-      for (index = 0; index < this.ripples.length; ++index) {
-        ripple = this.ripples[index];
-        ripple.draw();
-        this.$.background.style.opacity = ripple.outerOpacity;
-        if (ripple.isOpacityFullyDecayed && !ripple.isRestingAtMaxRadius) {
-          this.removeRipple(ripple);
-        }
-      }
-      if (!this.shouldKeepAnimating && this.ripples.length === 0) {
-        this.onAnimationComplete();
-      } else {
-        window.requestAnimationFrame(this._boundAnimate);
-      }
-    },
-    _onEnterKeydown: function() {
-      this.uiDownAction();
-      this.async(this.uiUpAction, 1);
-    },
-    _onSpaceKeydown: function() {
-      this.uiDownAction();
-    },
-    _onSpaceKeyup: function() {
-      this.uiUpAction();
-    },
-    _holdDownChanged: function(newVal, oldVal) {
-      if (oldVal === undefined) {
-        return;
-      }
-      if (newVal) {
-        this.downAction();
-      } else {
-        this.upAction();
-      }
-    }
-  });
-})();
-
-Polymer.PaperRippleBehavior = {
-  properties: {
-    noink: {
-      type: Boolean,
-      observer: '_noinkChanged'
-    },
-    _rippleContainer: {
-      type: Object
-    }
-  },
-  _buttonStateChanged: function() {
-    if (this.focused) {
-      this.ensureRipple();
-    }
-  },
-  _downHandler: function(event) {
-    Polymer.IronButtonStateImpl._downHandler.call(this, event);
-    if (this.pressed) {
-      this.ensureRipple(event);
-    }
-  },
-  ensureRipple: function(optTriggeringEvent) {
-    if (!this.hasRipple()) {
-      this._ripple = this._createRipple();
-      this._ripple.noink = this.noink;
-      var rippleContainer = this._rippleContainer || this.root;
-      if (rippleContainer) {
-        Polymer.dom(rippleContainer).appendChild(this._ripple);
-      }
-      if (optTriggeringEvent) {
-        var domContainer = Polymer.dom(this._rippleContainer || this);
-        var target = Polymer.dom(optTriggeringEvent).rootTarget;
-        if (domContainer.deepContains(target)) {
-          this._ripple.uiDownAction(optTriggeringEvent);
-        }
-      }
-    }
-  },
-  getRipple: function() {
-    this.ensureRipple();
-    return this._ripple;
-  },
-  hasRipple: function() {
-    return Boolean(this._ripple);
-  },
-  _createRipple: function() {
-    return document.createElement('paper-ripple');
-  },
-  _noinkChanged: function(noink) {
-    if (this.hasRipple()) {
-      this._ripple.noink = noink;
-    }
-  }
-};
-
-Polymer.PaperInkyFocusBehaviorImpl = {
-  observers: [ '_focusedChanged(receivedFocusFromKeyboard)' ],
-  _focusedChanged: function(receivedFocusFromKeyboard) {
-    if (receivedFocusFromKeyboard) {
-      this.ensureRipple();
-    }
-    if (this.hasRipple()) {
-      this._ripple.holdDown = receivedFocusFromKeyboard;
-    }
-  },
-  _createRipple: function() {
-    var ripple = Polymer.PaperRippleBehavior._createRipple();
-    ripple.id = 'ink';
-    ripple.setAttribute('center', '');
-    ripple.classList.add('circle');
-    return ripple;
-  }
-};
-
-Polymer.PaperInkyFocusBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperInkyFocusBehaviorImpl ];
-
-Polymer({
-  is: 'paper-icon-button',
-  hostAttributes: {
-    role: 'button',
-    tabindex: '0'
-  },
-  behaviors: [ Polymer.PaperInkyFocusBehavior ],
-  properties: {
-    src: {
-      type: String
-    },
-    icon: {
-      type: String
-    },
-    alt: {
-      type: String,
-      observer: "_altChanged"
-    }
-  },
-  _altChanged: function(newValue, oldValue) {
-    var label = this.getAttribute('aria-label');
-    if (!label || oldValue == label) {
-      this.setAttribute('aria-label', newValue);
-    }
-  }
-});
-
-Polymer({
-  is: 'iron-iconset-svg',
-  properties: {
-    name: {
-      type: String,
-      observer: '_nameChanged'
-    },
-    size: {
-      type: Number,
-      value: 24
-    }
-  },
-  attached: function() {
-    this.style.display = 'none';
-  },
-  getIconNames: function() {
-    this._icons = this._createIconMap();
-    return Object.keys(this._icons).map(function(n) {
-      return this.name + ':' + n;
-    }, this);
-  },
-  applyIcon: function(element, iconName) {
-    element = element.root || element;
-    this.removeIcon(element);
-    var svg = this._cloneIcon(iconName);
-    if (svg) {
-      var pde = Polymer.dom(element);
-      pde.insertBefore(svg, pde.childNodes[0]);
-      return element._svgIcon = svg;
-    }
-    return null;
-  },
-  removeIcon: function(element) {
-    if (element._svgIcon) {
-      Polymer.dom(element).removeChild(element._svgIcon);
-      element._svgIcon = null;
-    }
-  },
-  _nameChanged: function() {
-    new Polymer.IronMeta({
-      type: 'iconset',
-      key: this.name,
-      value: this
-    });
-    this.async(function() {
-      this.fire('iron-iconset-added', this, {
-        node: window
-      });
-    });
-  },
-  _createIconMap: function() {
-    var icons = Object.create(null);
-    Polymer.dom(this).querySelectorAll('[id]').forEach(function(icon) {
-      icons[icon.id] = icon;
-    });
-    return icons;
-  },
-  _cloneIcon: function(id) {
-    this._icons = this._icons || this._createIconMap();
-    return this._prepareSvgClone(this._icons[id], this.size);
-  },
-  _prepareSvgClone: function(sourceSvg, size) {
-    if (sourceSvg) {
-      var content = sourceSvg.cloneNode(true), svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg'), viewBox = content.getAttribute('viewBox') || '0 0 ' + size + ' ' + size;
-      svg.setAttribute('viewBox', viewBox);
-      svg.setAttribute('preserveAspectRatio', 'xMidYMid meet');
-      svg.style.cssText = 'pointer-events: none; display: block; width: 100%; height: 100%;';
-      svg.appendChild(content).removeAttribute('id');
-      return svg;
-    }
-    return null;
-  }
-});
-
+dy=this.yNow-this.containerMetrics.height/2;this.waveContainer.style.webkitTransform="translate("+dx+"px, "+dy+"px)";this.waveContainer.style.transform="translate3d("+dx+"px, "+dy+"px, 0)";this.wave.style.webkitTransform="scale("+scale+","+scale+")";this.wave.style.transform="scale3d("+scale+","+scale+",1)"},downAction:function(event){var xCenter=this.containerMetrics.width/2;var yCenter=this.containerMetrics.height/2;this.resetInteractionState();this.mouseDownStart=Utility.now();if(this.center){this.xStart=xCenter;this.yStart=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}else{this.xStart=event?event.detail.x-this.containerMetrics.boundingRect.left:this.containerMetrics.width/2;this.yStart=event?event.detail.y-this.containerMetrics.boundingRect.top:this.containerMetrics.height/2}if(this.recenters){this.xEnd=xCenter;this.yEnd=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}this.maxRadius=this.containerMetrics.furthestCornerDistanceFrom(this.xStart,this.yStart);this.waveContainer.style.top=(this.containerMetrics.height-this.containerMetrics.size)/2+"px";this.waveContainer.style.left=(this.containerMetrics.width-this.containerMetrics.size)/2+"px";this.waveContainer.style.width=this.containerMetrics.size+"px";this.waveContainer.style.height=this.containerMetrics.size+"px"},upAction:function(event){if(!this.isMouseDown){return}this.mouseUpStart=Utility.now()},remove:function(){Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)}};Polymer({is:"paper-ripple",behaviors:[Polymer.IronA11yKeysBehavior],properties:{initialOpacity:{type:Number,value:.25},opacityDecayVelocity:{type:Number,value:.8},recenters:{type:Boolean,value:false},center:{type:Boolean,value:false},ripples:{type:Array,value:function(){return[]}},animating:{type:Boolean,readOnly:true,reflectToAttribute:true,value:false},holdDown:{type:Boolean,value:false,observer:"_holdDownChanged"},noink:{type:Boolean,value:false},_animating:{type:Boolean},_boundAnimate:{type:Function,value:function(){return this.animate.bind(this)}}},get target(){return this.keyEventTarget},keyBindings:{"enter:keydown":"_onEnterKeydown","space:keydown":"_onSpaceKeydown","space:keyup":"_onSpaceKeyup"},attached:function(){if(this.parentNode.nodeType==11){this.keyEventTarget=Polymer.dom(this).getOwnerRoot().host}else{this.keyEventTarget=this.parentNode}var keyEventTarget=this.keyEventTarget;this.listen(keyEventTarget,"up","uiUpAction");this.listen(keyEventTarget,"down","uiDownAction")},detached:function(){this.unlisten(this.keyEventTarget,"up","uiUpAction");this.unlisten(this.keyEventTarget,"down","uiDownAction");this.keyEventTarget=null},get shouldKeepAnimating(){for(var index=0;index<this.ripples.length;++index){if(!this.ripples[index].isAnimationComplete){return true}}return false},simulatedRipple:function(){this.downAction(null);this.async(function(){this.upAction()},1)},uiDownAction:function(event){if(!this.noink){this.downAction(event)}},downAction:function(event){if(this.holdDown&&this.ripples.length>0){return}var ripple=this.addRipple();ripple.downAction(event);if(!this._animating){this._animating=true;this.animate()}},uiUpAction:function(event){if(!this.noink){this.upAction(event)}},upAction:function(event){if(this.holdDown){return}this.ripples.forEach(function(ripple){ripple.upAction(event)});this._animating=true;this.animate()},onAnimationComplete:function(){this._animating=false;this.$.background.style.backgroundColor=null;this.fire("transitionend")},addRipple:function(){var ripple=new Ripple(this);Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);this.$.background.style.backgroundColor=ripple.color;this.ripples.push(ripple);this._setAnimating(true);return ripple},removeRipple:function(ripple){var rippleIndex=this.ripples.indexOf(ripple);if(rippleIndex<0){return}this.ripples.splice(rippleIndex,1);ripple.remove();if(!this.ripples.length){this._setAnimating(false)}},animate:function(){if(!this._animating){return}var index;var ripple;for(index=0;index<this.ripples.length;++index){ripple=this.ripples[index];ripple.draw();this.$.background.style.opacity=ripple.outerOpacity;if(ripple.isOpacityFullyDecayed&&!ripple.isRestingAtMaxRadius){this.removeRipple(ripple)}}if(!this.shouldKeepAnimating&&this.ripples.length===0){this.onAnimationComplete()}else{window.requestAnimationFrame(this._boundAnimate)}},_onEnterKeydown:function(){this.uiDownAction();this.async(this.uiUpAction,1)},_onSpaceKeydown:function(){this.uiDownAction()},_onSpaceKeyup:function(){this.uiUpAction()},_holdDownChanged:function(newVal,oldVal){if(oldVal===undefined){return}if(newVal){this.downAction()}else{this.upAction()}}})})();Polymer.PaperRippleBehavior={properties:{noink:{type:Boolean,observer:"_noinkChanged"},_rippleContainer:{type:Object}},_buttonStateChanged:function(){if(this.focused){this.ensureRipple()}},_downHandler:function(event){Polymer.IronButtonStateImpl._downHandler.call(this,event);if(this.pressed){this.ensureRipple(event)}},ensureRipple:function(optTriggeringEvent){if(!this.hasRipple()){this._ripple=this._createRipple();this._ripple.noink=this.noink;var rippleContainer=this._rippleContainer||this.root;if(rippleContainer){Polymer.dom(rippleContainer).appendChild(this._ripple)}if(optTriggeringEvent){var domContainer=Polymer.dom(this._rippleContainer||this);var target=Polymer.dom(optTriggeringEvent).rootTarget;if(domContainer.deepContains(target)){this._ripple.uiDownAction(optTriggeringEvent)}}}},getRipple:function(){this.ensureRipple();return this._ripple},hasRipple:function(){return Boolean(this._ripple)},_createRipple:function(){return document.createElement("paper-ripple")},_noinkChanged:function(noink){if(this.hasRipple()){this._ripple.noink=noink}}};Polymer.PaperInkyFocusBehaviorImpl={observers:["_focusedChanged(receivedFocusFromKeyboard)"],_focusedChanged:function(receivedFocusFromKeyboard){if(receivedFocusFromKeyboard){this.ensureRipple()}if(this.hasRipple()){this._ripple.holdDown=receivedFocusFromKeyboard}},_createRipple:function(){var ripple=Polymer.PaperRippleBehavior._createRipple();ripple.id="ink";ripple.setAttribute("center","");ripple.classList.add("circle");return ripple}};Polymer.PaperInkyFocusBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperInkyFocusBehaviorImpl];Polymer({is:"paper-icon-button",hostAttributes:{role:"button",tabindex:"0"},behaviors:[Polymer.PaperInkyFocusBehavior],properties:{src:{type:String},icon:{type:String},alt:{type:String,observer:"_altChanged"}},_altChanged:function(newValue,oldValue){var label=this.getAttribute("aria-label");if(!label||oldValue==label){this.setAttribute("aria-label",newValue)}}});Polymer({is:"iron-iconset-svg",properties:{name:{type:String,observer:"_nameChanged"},size:{type:Number,value:24}},attached:function(){this.style.display="none"},getIconNames:function(){this._icons=this._createIconMap();return Object.keys(this._icons).map(function(n){return this.name+":"+n},this)},applyIcon:function(element,iconName){element=element.root||element;this.removeIcon(element);var svg=this._cloneIcon(iconName);if(svg){var pde=Polymer.dom(element);pde.insertBefore(svg,pde.childNodes[0]);return element._svgIcon=svg}return null},removeIcon:function(element){if(element._svgIcon){Polymer.dom(element).removeChild(element._svgIcon);element._svgIcon=null}},_nameChanged:function(){new Polymer.IronMeta({type:"iconset",key:this.name,value:this});this.async(function(){this.fire("iron-iconset-added",this,{node:window})})},_createIconMap:function(){var icons=Object.create(null);Polymer.dom(this).querySelectorAll("[id]").forEach(function(icon){icons[icon.id]=icon});return icons},_cloneIcon:function(id){this._icons=this._icons||this._createIconMap();return this._prepareSvgClone(this._icons[id],this.size)},_prepareSvgClone:function(sourceSvg,size){if(sourceSvg){var content=sourceSvg.cloneNode(true),svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),viewBox=content.getAttribute("viewBox")||"0 0 "+size+" "+size;svg.setAttribute("viewBox",viewBox);svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.cssText="pointer-events: none; display: block; width: 100%; height: 100%;";svg.appendChild(content).removeAttribute("id");return svg}return null}});
 // Copyright 2016 The Chromium 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({
-  is: 'cr-lazy-render',
-  "extends": 'template',
-  behaviors: [ Polymer.Templatizer ],
-  child_: null,
-  get: function() {
-    if (!this.child_) this.render_();
-    return this.child_;
-  },
-  getIfExists: function() {
-    return this.child_;
-  },
-  render_: function() {
-    if (!this.ctor) this.templatize(this);
-    var parentNode = this.parentNode;
-    if (parentNode && !this.child_) {
-      var instance = this.stamp({});
-      this.child_ = instance.root.firstElementChild;
-      parentNode.insertBefore(instance.root, this);
-    }
-  },
-  _forwardParentProp: function(prop, value) {
-    if (this.child_) this.child_._templateInstance[prop] = value;
-  },
-  _forwardParentPath: function(path, value) {
-    if (this.child_) this.child_._templateInstance.notifyPath(path, value, true);
-  }
-});
-
-(function() {
-  'use strict';
-  Polymer.IronA11yAnnouncer = Polymer({
-    is: 'iron-a11y-announcer',
-    properties: {
-      mode: {
-        type: String,
-        value: 'polite'
-      },
-      _text: {
-        type: String,
-        value: ''
-      }
-    },
-    created: function() {
-      if (!Polymer.IronA11yAnnouncer.instance) {
-        Polymer.IronA11yAnnouncer.instance = this;
-      }
-      document.body.addEventListener('iron-announce', this._onIronAnnounce.bind(this));
-    },
-    announce: function(text) {
-      this._text = '';
-      this.async(function() {
-        this._text = text;
-      }, 100);
-    },
-    _onIronAnnounce: function(event) {
-      if (event.detail && event.detail.text) {
-        this.announce(event.detail.text);
-      }
-    }
-  });
-  Polymer.IronA11yAnnouncer.instance = null;
-  Polymer.IronA11yAnnouncer.requestAvailability = function() {
-    if (!Polymer.IronA11yAnnouncer.instance) {
-      Polymer.IronA11yAnnouncer.instance = document.createElement('iron-a11y-announcer');
-    }
-    document.body.appendChild(Polymer.IronA11yAnnouncer.instance);
-  };
-})();
-
-Polymer.IronValidatableBehaviorMeta = null;
-
-Polymer.IronValidatableBehavior = {
-  properties: {
-    validator: {
-      type: String
-    },
-    invalid: {
-      notify: true,
-      reflectToAttribute: true,
-      type: Boolean,
-      value: false
-    },
-    _validatorMeta: {
-      type: Object
-    },
-    validatorType: {
-      type: String,
-      value: 'validator'
-    },
-    _validator: {
-      type: Object,
-      computed: '__computeValidator(validator)'
-    }
-  },
-  observers: [ '_invalidChanged(invalid)' ],
-  registered: function() {
-    Polymer.IronValidatableBehaviorMeta = new Polymer.IronMeta({
-      type: 'validator'
-    });
-  },
-  _invalidChanged: function() {
-    if (this.invalid) {
-      this.setAttribute('aria-invalid', 'true');
-    } else {
-      this.removeAttribute('aria-invalid');
-    }
-  },
-  hasValidator: function() {
-    return this._validator != null;
-  },
-  validate: function(value) {
-    this.invalid = !this._getValidity(value);
-    return !this.invalid;
-  },
-  _getValidity: function(value) {
-    if (this.hasValidator()) {
-      return this._validator.validate(value);
-    }
-    return true;
-  },
-  __computeValidator: function() {
-    return Polymer.IronValidatableBehaviorMeta && Polymer.IronValidatableBehaviorMeta.byKey(this.validator);
-  }
-};
-
-Polymer({
-  is: 'iron-input',
-  "extends": 'input',
-  behaviors: [ Polymer.IronValidatableBehavior ],
-  properties: {
-    bindValue: {
-      observer: '_bindValueChanged',
-      type: String
-    },
-    preventInvalidInput: {
-      type: Boolean
-    },
-    allowedPattern: {
-      type: String,
-      observer: "_allowedPatternChanged"
-    },
-    _previousValidInput: {
-      type: String,
-      value: ''
-    },
-    _patternAlreadyChecked: {
-      type: Boolean,
-      value: false
-    }
-  },
-  listeners: {
-    input: '_onInput',
-    keypress: '_onKeypress'
-  },
-  registered: function() {
-    if (!this._canDispatchEventOnDisabled()) {
-      this._origDispatchEvent = this.dispatchEvent;
-      this.dispatchEvent = this._dispatchEventFirefoxIE;
-    }
-  },
-  created: function() {
-    Polymer.IronA11yAnnouncer.requestAvailability();
-  },
-  _canDispatchEventOnDisabled: function() {
-    var input = document.createElement('input');
-    var canDispatch = false;
-    input.disabled = true;
-    input.addEventListener('feature-check-dispatch-event', function() {
-      canDispatch = true;
-    });
-    try {
-      input.dispatchEvent(new Event('feature-check-dispatch-event'));
-    } catch (e) {}
-    return canDispatch;
-  },
-  _dispatchEventFirefoxIE: function() {
-    var disabled = this.disabled;
-    this.disabled = false;
-    this._origDispatchEvent.apply(this, arguments);
-    this.disabled = disabled;
-  },
-  get _patternRegExp() {
-    var pattern;
-    if (this.allowedPattern) {
-      pattern = new RegExp(this.allowedPattern);
-    } else {
-      switch (this.type) {
-       case 'number':
-        pattern = /[0-9.,e-]/;
-        break;
-      }
-    }
-    return pattern;
-  },
-  ready: function() {
-    this.bindValue = this.value;
-  },
-  _bindValueChanged: function() {
-    if (this.value !== this.bindValue) {
-      this.value = !(this.bindValue || this.bindValue === 0 || this.bindValue === false) ? '' : this.bindValue;
-    }
-    this.fire('bind-value-changed', {
-      value: this.bindValue
-    });
-  },
-  _allowedPatternChanged: function() {
-    this.preventInvalidInput = this.allowedPattern ? true : false;
-  },
-  _onInput: function() {
-    if (this.preventInvalidInput && !this._patternAlreadyChecked) {
-      var valid = this._checkPatternValidity();
-      if (!valid) {
-        this._announceInvalidCharacter('Invalid string of characters not entered.');
-        this.value = this._previousValidInput;
-      }
-    }
-    this.bindValue = this.value;
-    this._previousValidInput = this.value;
-    this._patternAlreadyChecked = false;
-  },
-  _isPrintable: function(event) {
-    var anyNonPrintable = event.keyCode == 8 || event.keyCode == 9 || event.keyCode == 13 || event.keyCode == 27;
-    var mozNonPrintable = event.keyCode == 19 || event.keyCode == 20 || event.keyCode == 45 || event.keyCode == 46 || event.keyCode == 144 || event.keyCode == 145 || event.keyCode > 32 && event.keyCode < 41 || event.keyCode > 111 && event.keyCode < 124;
-    return !anyNonPrintable && !(event.charCode == 0 && mozNonPrintable);
-  },
-  _onKeypress: function(event) {
-    if (!this.preventInvalidInput && this.type !== 'number') {
-      return;
-    }
-    var regexp = this._patternRegExp;
-    if (!regexp) {
-      return;
-    }
-    if (event.metaKey || event.ctrlKey || event.altKey) return;
-    this._patternAlreadyChecked = true;
-    var thisChar = String.fromCharCode(event.charCode);
-    if (this._isPrintable(event) && !regexp.test(thisChar)) {
-      event.preventDefault();
-      this._announceInvalidCharacter('Invalid character ' + thisChar + ' not entered.');
-    }
-  },
-  _checkPatternValidity: function() {
-    var regexp = this._patternRegExp;
-    if (!regexp) {
-      return true;
-    }
-    for (var i = 0; i < this.value.length; i++) {
-      if (!regexp.test(this.value[i])) {
-        return false;
-      }
-    }
-    return true;
-  },
-  validate: function() {
-    var valid = this.checkValidity();
-    if (valid) {
-      if (this.required && this.value === '') {
-        valid = false;
-      } else if (this.hasValidator()) {
-        valid = Polymer.IronValidatableBehavior.validate.call(this, this.value);
-      }
-    }
-    this.invalid = !valid;
-    this.fire('iron-input-validate');
-    return valid;
-  },
-  _announceInvalidCharacter: function(message) {
-    this.fire('iron-announce', {
-      text: message
-    });
-  }
-});
-
-Polymer({
-  is: 'paper-input-container',
-  properties: {
-    noLabelFloat: {
-      type: Boolean,
-      value: false
-    },
-    alwaysFloatLabel: {
-      type: Boolean,
-      value: false
-    },
-    attrForValue: {
-      type: String,
-      value: 'bind-value'
-    },
-    autoValidate: {
-      type: Boolean,
-      value: false
-    },
-    invalid: {
-      observer: '_invalidChanged',
-      type: Boolean,
-      value: false
-    },
-    focused: {
-      readOnly: true,
-      type: Boolean,
-      value: false,
-      notify: true
-    },
-    _addons: {
-      type: Array
-    },
-    _inputHasContent: {
-      type: Boolean,
-      value: false
-    },
-    _inputSelector: {
-      type: String,
-      value: 'input,textarea,.paper-input-input'
-    },
-    _boundOnFocus: {
-      type: Function,
-      value: function() {
-        return this._onFocus.bind(this);
-      }
-    },
-    _boundOnBlur: {
-      type: Function,
-      value: function() {
-        return this._onBlur.bind(this);
-      }
-    },
-    _boundOnInput: {
-      type: Function,
-      value: function() {
-        return this._onInput.bind(this);
-      }
-    },
-    _boundValueChanged: {
-      type: Function,
-      value: function() {
-        return this._onValueChanged.bind(this);
-      }
-    }
-  },
-  listeners: {
-    'addon-attached': '_onAddonAttached',
-    'iron-input-validate': '_onIronInputValidate'
-  },
-  get _valueChangedEvent() {
-    return this.attrForValue + '-changed';
-  },
-  get _propertyForValue() {
-    return Polymer.CaseMap.dashToCamelCase(this.attrForValue);
-  },
-  get _inputElement() {
-    return Polymer.dom(this).querySelector(this._inputSelector);
-  },
-  get _inputElementValue() {
-    return this._inputElement[this._propertyForValue] || this._inputElement.value;
-  },
-  ready: function() {
-    if (!this._addons) {
-      this._addons = [];
-    }
-    this.addEventListener('focus', this._boundOnFocus, true);
-    this.addEventListener('blur', this._boundOnBlur, true);
-  },
-  attached: function() {
-    if (this.attrForValue) {
-      this._inputElement.addEventListener(this._valueChangedEvent, this._boundValueChanged);
-    } else {
-      this.addEventListener('input', this._onInput);
-    }
-    if (this._inputElementValue != '') {
-      this._handleValueAndAutoValidate(this._inputElement);
-    } else {
-      this._handleValue(this._inputElement);
-    }
-  },
-  _onAddonAttached: function(event) {
-    if (!this._addons) {
-      this._addons = [];
-    }
-    var target = event.target;
-    if (this._addons.indexOf(target) === -1) {
-      this._addons.push(target);
-      if (this.isAttached) {
-        this._handleValue(this._inputElement);
-      }
-    }
-  },
-  _onFocus: function() {
-    this._setFocused(true);
-  },
-  _onBlur: function() {
-    this._setFocused(false);
-    this._handleValueAndAutoValidate(this._inputElement);
-  },
-  _onInput: function(event) {
-    this._handleValueAndAutoValidate(event.target);
-  },
-  _onValueChanged: function(event) {
-    this._handleValueAndAutoValidate(event.target);
-  },
-  _handleValue: function(inputElement) {
-    var value = this._inputElementValue;
-    if (value || value === 0 || inputElement.type === 'number' && !inputElement.checkValidity()) {
-      this._inputHasContent = true;
-    } else {
-      this._inputHasContent = false;
-    }
-    this.updateAddons({
-      inputElement: inputElement,
-      value: value,
-      invalid: this.invalid
-    });
-  },
-  _handleValueAndAutoValidate: function(inputElement) {
-    if (this.autoValidate) {
-      var valid;
-      if (inputElement.validate) {
-        valid = inputElement.validate(this._inputElementValue);
-      } else {
-        valid = inputElement.checkValidity();
-      }
-      this.invalid = !valid;
-    }
-    this._handleValue(inputElement);
-  },
-  _onIronInputValidate: function(event) {
-    this.invalid = this._inputElement.invalid;
-  },
-  _invalidChanged: function() {
-    if (this._addons) {
-      this.updateAddons({
-        invalid: this.invalid
-      });
-    }
-  },
-  updateAddons: function(state) {
-    for (var addon, index = 0; addon = this._addons[index]; index++) {
-      addon.update(state);
-    }
-  },
-  _computeInputContentClass: function(noLabelFloat, alwaysFloatLabel, focused, invalid, _inputHasContent) {
-    var cls = 'input-content';
-    if (!noLabelFloat) {
-      var label = this.querySelector('label');
-      if (alwaysFloatLabel || _inputHasContent) {
-        cls += ' label-is-floating';
-        this.$.labelAndInputContainer.style.position = 'static';
-        if (invalid) {
-          cls += ' is-invalid';
-        } else if (focused) {
-          cls += " label-is-highlighted";
-        }
-      } else {
-        if (label) {
-          this.$.labelAndInputContainer.style.position = 'relative';
-        }
-      }
-    } else {
-      if (_inputHasContent) {
-        cls += ' label-is-hidden';
-      }
-    }
-    return cls;
-  },
-  _computeUnderlineClass: function(focused, invalid) {
-    var cls = 'underline';
-    if (invalid) {
-      cls += ' is-invalid';
-    } else if (focused) {
-      cls += ' is-highlighted';
-    }
-    return cls;
-  },
-  _computeAddOnContentClass: function(focused, invalid) {
-    var cls = 'add-on-content';
-    if (invalid) {
-      cls += ' is-invalid';
-    } else if (focused) {
-      cls += ' is-highlighted';
-    }
-    return cls;
-  }
-});
-
-Polymer.PaperSpinnerBehavior = {
-  listeners: {
-    animationend: '__reset',
-    webkitAnimationEnd: '__reset'
-  },
-  properties: {
-    active: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      observer: '__activeChanged'
-    },
-    alt: {
-      type: String,
-      value: 'loading',
-      observer: '__altChanged'
-    },
-    __coolingDown: {
-      type: Boolean,
-      value: false
-    }
-  },
-  __computeContainerClasses: function(active, coolingDown) {
-    return [ active || coolingDown ? 'active' : '', coolingDown ? 'cooldown' : '' ].join(' ');
-  },
-  __activeChanged: function(active, old) {
-    this.__setAriaHidden(!active);
-    this.__coolingDown = !active && old;
-  },
-  __altChanged: function(alt) {
-    if (alt === this.getPropertyInfo('alt').value) {
-      this.alt = this.getAttribute('aria-label') || alt;
-    } else {
-      this.__setAriaHidden(alt === '');
-      this.setAttribute('aria-label', alt);
-    }
-  },
-  __setAriaHidden: function(hidden) {
-    var attr = 'aria-hidden';
-    if (hidden) {
-      this.setAttribute(attr, 'true');
-    } else {
-      this.removeAttribute(attr);
-    }
-  },
-  __reset: function() {
-    this.active = false;
-    this.__coolingDown = false;
-  }
-};
-
-Polymer({
-  is: 'paper-spinner-lite',
-  behaviors: [ Polymer.PaperSpinnerBehavior ]
-});
-
+Polymer({is:"cr-lazy-render","extends":"template",behaviors:[Polymer.Templatizer],child_:null,get:function(){if(!this.child_)this.render_();return this.child_},getIfExists:function(){return this.child_},render_:function(){if(!this.ctor)this.templatize(this);var parentNode=this.parentNode;if(parentNode&&!this.child_){var instance=this.stamp({});this.child_=instance.root.firstElementChild;parentNode.insertBefore(instance.root,this)}},_forwardParentProp:function(prop,value){if(this.child_)this.child_._templateInstance[prop]=value},_forwardParentPath:function(path,value){if(this.child_)this.child_._templateInstance.notifyPath(path,value,true)}});(function(){"use strict";Polymer.IronA11yAnnouncer=Polymer({is:"iron-a11y-announcer",properties:{mode:{type:String,value:"polite"},_text:{type:String,value:""}},created:function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=this}document.body.addEventListener("iron-announce",this._onIronAnnounce.bind(this))},announce:function(text){this._text="";this.async(function(){this._text=text},100)},_onIronAnnounce:function(event){if(event.detail&&event.detail.text){this.announce(event.detail.text)}}});Polymer.IronA11yAnnouncer.instance=null;Polymer.IronA11yAnnouncer.requestAvailability=function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=document.createElement("iron-a11y-announcer")}document.body.appendChild(Polymer.IronA11yAnnouncer.instance)}})();Polymer.IronValidatableBehaviorMeta=null;Polymer.IronValidatableBehavior={properties:{validator:{type:String},invalid:{notify:true,reflectToAttribute:true,type:Boolean,value:false},_validatorMeta:{type:Object},validatorType:{type:String,value:"validator"},_validator:{type:Object,computed:"__computeValidator(validator)"}},observers:["_invalidChanged(invalid)"],registered:function(){Polymer.IronValidatableBehaviorMeta=new Polymer.IronMeta({type:"validator"})},_invalidChanged:function(){if(this.invalid){this.setAttribute("aria-invalid","true")}else{this.removeAttribute("aria-invalid")}},hasValidator:function(){return this._validator!=null},validate:function(value){this.invalid=!this._getValidity(value);return!this.invalid},_getValidity:function(value){if(this.hasValidator()){return this._validator.validate(value)}return true},__computeValidator:function(){return Polymer.IronValidatableBehaviorMeta&&Polymer.IronValidatableBehaviorMeta.byKey(this.validator)}};Polymer({is:"iron-input","extends":"input",behaviors:[Polymer.IronValidatableBehavior],properties:{bindValue:{observer:"_bindValueChanged",type:String},preventInvalidInput:{type:Boolean},allowedPattern:{type:String,observer:"_allowedPatternChanged"},_previousValidInput:{type:String,value:""},_patternAlreadyChecked:{type:Boolean,value:false}},listeners:{input:"_onInput",keypress:"_onKeypress"},registered:function(){if(!this._canDispatchEventOnDisabled()){this._origDispatchEvent=this.dispatchEvent;this.dispatchEvent=this._dispatchEventFirefoxIE}},created:function(){Polymer.IronA11yAnnouncer.requestAvailability()},_canDispatchEventOnDisabled:function(){var input=document.createElement("input");var canDispatch=false;input.disabled=true;input.addEventListener("feature-check-dispatch-event",function(){canDispatch=true});try{input.dispatchEvent(new Event("feature-check-dispatch-event"))}catch(e){}return canDispatch},_dispatchEventFirefoxIE:function(){var disabled=this.disabled;this.disabled=false;this._origDispatchEvent.apply(this,arguments);this.disabled=disabled},get _patternRegExp(){var pattern;if(this.allowedPattern){pattern=new RegExp(this.allowedPattern)}else{switch(this.type){case"number":pattern=/[0-9.,e-]/;break}}return pattern},ready:function(){this.bindValue=this.value},_bindValueChanged:function(){if(this.value!==this.bindValue){this.value=!(this.bindValue||this.bindValue===0||this.bindValue===false)?"":this.bindValue}this.fire("bind-value-changed",{value:this.bindValue})},_allowedPatternChanged:function(){this.preventInvalidInput=this.allowedPattern?true:false},_onInput:function(){if(this.preventInvalidInput&&!this._patternAlreadyChecked){var valid=this._checkPatternValidity();if(!valid){this._announceInvalidCharacter("Invalid string of characters not entered.");this.value=this._previousValidInput}}this.bindValue=this.value;this._previousValidInput=this.value;this._patternAlreadyChecked=false},_isPrintable:function(event){var anyNonPrintable=event.keyCode==8||event.keyCode==9||event.keyCode==13||event.keyCode==27;var mozNonPrintable=event.keyCode==19||event.keyCode==20||event.keyCode==45||event.keyCode==46||event.keyCode==144||event.keyCode==145||event.keyCode>32&&event.keyCode<41||event.keyCode>111&&event.keyCode<124;return!anyNonPrintable&&!(event.charCode==0&&mozNonPrintable)},_onKeypress:function(event){if(!this.preventInvalidInput&&this.type!=="number"){return}var regexp=this._patternRegExp;if(!regexp){return}if(event.metaKey||event.ctrlKey||event.altKey)return;this._patternAlreadyChecked=true;var thisChar=String.fromCharCode(event.charCode);if(this._isPrintable(event)&&!regexp.test(thisChar)){event.preventDefault();this._announceInvalidCharacter("Invalid character "+thisChar+" not entered.")}},_checkPatternValidity:function(){var regexp=this._patternRegExp;if(!regexp){return true}for(var i=0;i<this.value.length;i++){if(!regexp.test(this.value[i])){return false}}return true},validate:function(){var valid=this.checkValidity();if(valid){if(this.required&&this.value===""){valid=false}else if(this.hasValidator()){valid=Polymer.IronValidatableBehavior.validate.call(this,this.value)}}this.invalid=!valid;this.fire("iron-input-validate");return valid},_announceInvalidCharacter:function(message){this.fire("iron-announce",{text:message})}});Polymer({is:"paper-input-container",properties:{noLabelFloat:{type:Boolean,value:false},alwaysFloatLabel:{type:Boolean,value:false},attrForValue:{type:String,value:"bind-value"},autoValidate:{type:Boolean,value:false},invalid:{observer:"_invalidChanged",type:Boolean,value:false},focused:{readOnly:true,type:Boolean,value:false,notify:true},_addons:{type:Array},_inputHasContent:{type:Boolean,value:false},_inputSelector:{type:String,value:"input,textarea,.paper-input-input"},_boundOnFocus:{type:Function,value:function(){return this._onFocus.bind(this)}},_boundOnBlur:{type:Function,value:function(){return this._onBlur.bind(this)}},_boundOnInput:{type:Function,value:function(){return this._onInput.bind(this)}},_boundValueChanged:{type:Function,value:function(){return this._onValueChanged.bind(this)}}},listeners:{"addon-attached":"_onAddonAttached","iron-input-validate":"_onIronInputValidate"},get _valueChangedEvent(){return this.attrForValue+"-changed"},get _propertyForValue(){return Polymer.CaseMap.dashToCamelCase(this.attrForValue)},get _inputElement(){return Polymer.dom(this).querySelector(this._inputSelector)},get _inputElementValue(){return this._inputElement[this._propertyForValue]||this._inputElement.value},ready:function(){if(!this._addons){this._addons=[]}this.addEventListener("focus",this._boundOnFocus,true);this.addEventListener("blur",this._boundOnBlur,true)},attached:function(){if(this.attrForValue){this._inputElement.addEventListener(this._valueChangedEvent,this._boundValueChanged)}else{this.addEventListener("input",this._onInput)}if(this._inputElementValue!=""){this._handleValueAndAutoValidate(this._inputElement)}else{this._handleValue(this._inputElement)}},_onAddonAttached:function(event){if(!this._addons){this._addons=[]}var target=event.target;if(this._addons.indexOf(target)===-1){this._addons.push(target);if(this.isAttached){this._handleValue(this._inputElement)}}},_onFocus:function(){this._setFocused(true)},_onBlur:function(){this._setFocused(false);this._handleValueAndAutoValidate(this._inputElement)},_onInput:function(event){this._handleValueAndAutoValidate(event.target)},_onValueChanged:function(event){this._handleValueAndAutoValidate(event.target)},_handleValue:function(inputElement){var value=this._inputElementValue;if(value||value===0||inputElement.type==="number"&&!inputElement.checkValidity()){this._inputHasContent=true}else{this._inputHasContent=false}this.updateAddons({inputElement:inputElement,value:value,invalid:this.invalid})},_handleValueAndAutoValidate:function(inputElement){if(this.autoValidate){var valid;if(inputElement.validate){valid=inputElement.validate(this._inputElementValue)}else{valid=inputElement.checkValidity()}this.invalid=!valid}this._handleValue(inputElement)},_onIronInputValidate:function(event){this.invalid=this._inputElement.invalid},_invalidChanged:function(){if(this._addons){this.updateAddons({invalid:this.invalid})}},updateAddons:function(state){for(var addon,index=0;addon=this._addons[index];index++){addon.update(state)}},_computeInputContentClass:function(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent){var cls="input-content";if(!noLabelFloat){var label=this.querySelector("label");if(alwaysFloatLabel||_inputHasContent){cls+=" label-is-floating";this.$.labelAndInputContainer.style.position="static";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" label-is-highlighted"}}else{if(label){this.$.labelAndInputContainer.style.position="relative"}}}else{if(_inputHasContent){cls+=" label-is-hidden"}}return cls},_computeUnderlineClass:function(focused,invalid){var cls="underline";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls},_computeAddOnContentClass:function(focused,invalid){var cls="add-on-content";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls}});Polymer.PaperSpinnerBehavior={listeners:{animationend:"__reset",webkitAnimationEnd:"__reset"},properties:{active:{type:Boolean,value:false,reflectToAttribute:true,observer:"__activeChanged"},alt:{type:String,value:"loading",observer:"__altChanged"},__coolingDown:{type:Boolean,value:false}},__computeContainerClasses:function(active,coolingDown){return[active||coolingDown?"active":"",coolingDown?"cooldown":""].join(" ")},__activeChanged:function(active,old){this.__setAriaHidden(!active);this.__coolingDown=!active&&old},__altChanged:function(alt){if(alt===this.getPropertyInfo("alt").value){this.alt=this.getAttribute("aria-label")||alt}else{this.__setAriaHidden(alt==="");this.setAttribute("aria-label",alt)}},__setAriaHidden:function(hidden){var attr="aria-hidden";if(hidden){this.setAttribute(attr,"true")}else{this.removeAttribute(attr)}},__reset:function(){this.active=false;this.__coolingDown=false}};Polymer({is:"paper-spinner-lite",behaviors:[Polymer.PaperSpinnerBehavior]});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-var CrSearchFieldBehavior = {
-  properties: {
-    label: {
-      type: String,
-      value: ''
-    },
-    clearLabel: {
-      type: String,
-      value: ''
-    },
-    showingSearch: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: 'showingSearchChanged_',
-      reflectToAttribute: true
-    },
-    lastValue_: {
-      type: String,
-      value: ''
-    }
-  },
-  getSearchInput: function() {},
-  getValue: function() {
-    return this.getSearchInput().value;
-  },
-  setValue: function(value) {
-    this.getSearchInput().bindValue = value;
-    this.onValueChanged_(value);
-  },
-  showAndFocus: function() {
-    this.showingSearch = true;
-    this.focus_();
-  },
-  focus_: function() {
-    this.getSearchInput().focus();
-  },
-  onSearchTermSearch: function() {
-    this.onValueChanged_(this.getValue());
-  },
-  onValueChanged_: function(newValue) {
-    if (newValue == this.lastValue_) return;
-    this.fire('search-changed', newValue);
-    this.lastValue_ = newValue;
-  },
-  onSearchTermKeydown: function(e) {
-    if (e.key == 'Escape') this.showingSearch = false;
-  },
-  showingSearchChanged_: function() {
-    if (this.showingSearch) {
-      this.focus_();
-      return;
-    }
-    this.setValue('');
-    this.getSearchInput().blur();
-  }
-};
-
+var CrSearchFieldBehavior={properties:{label:{type:String,value:""},clearLabel:{type:String,value:""},showingSearch:{type:Boolean,value:false,notify:true,observer:"showingSearchChanged_",reflectToAttribute:true},lastValue_:{type:String,value:""}},getSearchInput:function(){},getValue:function(){return this.getSearchInput().value},setValue:function(value){this.getSearchInput().bindValue=value;this.onValueChanged_(value)},showAndFocus:function(){this.showingSearch=true;this.focus_()},focus_:function(){this.getSearchInput().focus()},onSearchTermSearch:function(){this.onValueChanged_(this.getValue())},onValueChanged_:function(newValue){if(newValue==this.lastValue_)return;this.fire("search-changed",newValue);this.lastValue_=newValue},onSearchTermKeydown:function(e){if(e.key=="Escape")this.showingSearch=false},showingSearchChanged_:function(){if(this.showingSearch){this.focus_();return}this.setValue("");this.getSearchInput().blur()}};
 // Copyright 2016 The Chromium 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({
-  is: 'cr-toolbar-search-field',
-  behaviors: [ CrSearchFieldBehavior ],
-  properties: {
-    narrow: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    label: String,
-    clearLabel: String,
-    spinnerActive: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    hasSearchText_: Boolean,
-    isSpinnerShown_: {
-      type: Boolean,
-      computed: 'computeIsSpinnerShown_(spinnerActive, showingSearch)'
-    }
-  },
-  listeners: {
-    tap: 'showSearch_',
-    'searchInput.bind-value-changed': 'onBindValueChanged_'
-  },
-  getSearchInput: function() {
-    return this.$.searchInput;
-  },
-  isSearchFocused: function() {
-    return this.$.searchTerm.focused;
-  },
-  computeIconTabIndex_: function(narrow) {
-    return narrow ? 0 : -1;
-  },
-  computeIsSpinnerShown_: function() {
-    return this.spinnerActive && this.showingSearch;
-  },
-  onInputBlur_: function() {
-    if (!this.hasSearchText_) this.showingSearch = false;
-  },
-  onBindValueChanged_: function() {
-    var newValue = this.$.searchInput.bindValue;
-    this.hasSearchText_ = newValue != '';
-    if (newValue != '') this.showingSearch = true;
-  },
-  showSearch_: function(e) {
-    if (e.target != this.$.clearSearch) this.showingSearch = true;
-  },
-  hideSearch_: function(e) {
-    this.showingSearch = false;
-    e.stopPropagation();
-  }
-});
-
+Polymer({is:"cr-toolbar-search-field",behaviors:[CrSearchFieldBehavior],properties:{narrow:{type:Boolean,reflectToAttribute:true},label:String,clearLabel:String,spinnerActive:{type:Boolean,reflectToAttribute:true},hasSearchText_:Boolean,isSpinnerShown_:{type:Boolean,computed:"computeIsSpinnerShown_(spinnerActive, showingSearch)"}},listeners:{tap:"showSearch_","searchInput.bind-value-changed":"onBindValueChanged_"},getSearchInput:function(){return this.$.searchInput},isSearchFocused:function(){return this.$.searchTerm.focused},computeIconTabIndex_:function(narrow){return narrow?0:-1},computeIsSpinnerShown_:function(){return this.spinnerActive&&this.showingSearch},onInputBlur_:function(){if(!this.hasSearchText_)this.showingSearch=false},onBindValueChanged_:function(){var newValue=this.$.searchInput.bindValue;this.hasSearchText_=newValue!="";if(newValue!="")this.showingSearch=true},showSearch_:function(e){if(e.target!=this.$.clearSearch)this.showingSearch=true},hideSearch_:function(e){this.showingSearch=false;e.stopPropagation()}});
 // Copyright 2016 The Chromium 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({
-  is: 'cr-toolbar',
-  properties: {
-    pageName: String,
-    searchPrompt: String,
-    clearLabel: String,
-    menuLabel: String,
-    menuPromo: String,
-    spinnerActive: Boolean,
-    showMenu: {
-      type: Boolean,
-      value: false
-    },
-    showMenuPromo: {
-      type: Boolean,
-      value: false
-    },
-    closeMenuPromo: String,
-    narrow_: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    showingSearch_: {
-      type: Boolean,
-      reflectToAttribute: true
-    }
-  },
-  observers: [ 'possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)' ],
-  getSearchField: function() {
-    return this.$.search;
-  },
-  onClosePromoTap_: function() {
-    this.showMenuPromo = false;
-  },
-  onMenuTap_: function() {
-    this.fire('cr-menu-tap');
-    this.onClosePromoTap_();
-  },
-  possiblyShowMenuPromo_: function() {
-    Polymer.RenderStatus.afterNextRender(this, function() {
-      if (this.showMenu && this.showMenuPromo && !this.showingSearch_) {
-        this.$$('#menuPromo').animate({
-          opacity: [ 0, .9 ]
-        }, {
-          duration: 500,
-          fill: 'forwards'
-        });
-        this.fire('cr-menu-promo-shown');
-      }
-    }.bind(this));
-  },
-  titleIfNotShowMenuPromo_: function(title, showMenuPromo) {
-    return showMenuPromo ? '' : title;
-  }
-});
-
+Polymer({is:"cr-toolbar",properties:{pageName:String,searchPrompt:String,clearLabel:String,menuLabel:String,menuPromo:String,spinnerActive:Boolean,showMenu:{type:Boolean,value:false},showMenuPromo:{type:Boolean,value:false},closeMenuPromo:String,narrow_:{type:Boolean,reflectToAttribute:true},showingSearch_:{type:Boolean,reflectToAttribute:true}},observers:["possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)"],getSearchField:function(){return this.$.search},onClosePromoTap_:function(){this.showMenuPromo=false},onMenuTap_:function(){this.fire("cr-menu-tap");this.onClosePromoTap_()},possiblyShowMenuPromo_:function(){Polymer.RenderStatus.afterNextRender(this,function(){if(this.showMenu&&this.showMenuPromo&&!this.showingSearch_){this.$$("#menuPromo").animate({opacity:[0,.9]},{duration:500,fill:"forwards"});this.fire("cr-menu-promo-shown")}}.bind(this))},titleIfNotShowMenuPromo_:function(title,showMenuPromo){return showMenuPromo?"":title}});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-cr.define('md_history', function() {
-  function BrowserService() {
-    this.pendingDeleteItems_ = null;
-    this.pendingDeletePromise_ = null;
-  }
-  BrowserService.prototype = {
-    deleteItems: function(items) {
-      if (this.pendingDeleteItems_ != null) {
-        return new Promise(function(resolve, reject) {
-          reject(items);
-        });
-      }
-      var removalList = items.map(function(item) {
-        return {
-          url: item.url,
-          timestamps: item.allTimestamps
-        };
-      });
-      this.pendingDeleteItems_ = items;
-      this.pendingDeletePromise_ = new PromiseResolver();
-      chrome.send('removeVisits', removalList);
-      return this.pendingDeletePromise_.promise;
-    },
-    removeBookmark: function(url) {
-      chrome.send('removeBookmark', [ url ]);
-    },
-    openForeignSessionAllTabs: function(sessionTag) {
-      chrome.send('openForeignSession', [ sessionTag ]);
-    },
-    openForeignSessionTab: function(sessionTag, windowId, tabId, e) {
-      chrome.send('openForeignSession', [ sessionTag, String(windowId), String(tabId), e.button || 0, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey ]);
-    },
-    deleteForeignSession: function(sessionTag) {
-      chrome.send('deleteForeignSession', [ sessionTag ]);
-    },
-    openClearBrowsingData: function() {
-      chrome.send('clearBrowsingData');
-    },
-    recordHistogram: function(histogram, value, max) {
-      chrome.send('metricsHandler:recordInHistogram', [ histogram, value, max ]);
-    },
-    recordAction: function(action) {
-      if (action.indexOf('_') == -1) action = 'HistoryPage_' + action;
-      chrome.send('metricsHandler:recordAction', [ action ]);
-    },
-    resolveDelete_: function(successful) {
-      if (this.pendingDeleteItems_ == null || this.pendingDeletePromise_ == null) {
-        return;
-      }
-      if (successful) this.pendingDeletePromise_.resolve(this.pendingDeleteItems_); else this.pendingDeletePromise_.reject(this.pendingDeleteItems_);
-      this.pendingDeleteItems_ = null;
-      this.pendingDeletePromise_ = null;
-    },
-    menuPromoShown: function() {
-      chrome.send('menuPromoShown');
-    }
-  };
-  cr.addSingletonGetter(BrowserService);
-  return {
-    BrowserService: BrowserService
-  };
-});
-
-function deleteComplete() {
-  md_history.BrowserService.getInstance().resolveDelete_(true);
-}
-
-function deleteFailed() {
-  md_history.BrowserService.getInstance().resolveDelete_(false);
-}
-
+cr.define("md_history",function(){function BrowserService(){this.pendingDeleteItems_=null;this.pendingDeletePromise_=null}BrowserService.prototype={deleteItems:function(items){if(this.pendingDeleteItems_!=null){return new Promise(function(resolve,reject){reject(items)})}var removalList=items.map(function(item){return{url:item.url,timestamps:item.allTimestamps}});this.pendingDeleteItems_=items;this.pendingDeletePromise_=new PromiseResolver;chrome.send("removeVisits",removalList);return this.pendingDeletePromise_.promise},removeBookmark:function(url){chrome.send("removeBookmark",[url])},openForeignSessionAllTabs:function(sessionTag){chrome.send("openForeignSession",[sessionTag])},openForeignSessionTab:function(sessionTag,windowId,tabId,e){chrome.send("openForeignSession",[sessionTag,String(windowId),String(tabId),e.button||0,e.altKey,e.ctrlKey,e.metaKey,e.shiftKey])},deleteForeignSession:function(sessionTag){chrome.send("deleteForeignSession",[sessionTag])},openClearBrowsingData:function(){chrome.send("clearBrowsingData")},recordHistogram:function(histogram,value,max){chrome.send("metricsHandler:recordInHistogram",[histogram,value,max])},recordAction:function(action){if(action.indexOf("_")==-1)action="HistoryPage_"+action;chrome.send("metricsHandler:recordAction",[action])},resolveDelete_:function(successful){if(this.pendingDeleteItems_==null||this.pendingDeletePromise_==null){return}if(successful)this.pendingDeletePromise_.resolve(this.pendingDeleteItems_);else this.pendingDeletePromise_.reject(this.pendingDeleteItems_);this.pendingDeleteItems_=null;this.pendingDeletePromise_=null},menuPromoShown:function(){chrome.send("menuPromoShown")}};cr.addSingletonGetter(BrowserService);return{BrowserService:BrowserService}});function deleteComplete(){md_history.BrowserService.getInstance().resolveDelete_(true)}function deleteFailed(){md_history.BrowserService.getInstance().resolveDelete_(false)}
 // 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({
-  is: 'history-toolbar',
-  properties: {
-    count: {
-      type: Number,
-      value: 0,
-      observer: 'changeToolbarView_'
-    },
-    itemsSelected_: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    searchTerm: {
-      type: String,
-      observer: 'searchTermChanged_',
-      notify: true
-    },
-    spinnerActive: {
-      type: Boolean,
-      value: false
-    },
-    hasDrawer: {
-      type: Boolean,
-      observer: 'hasDrawerChanged_',
-      reflectToAttribute: true
-    },
-    showSyncNotice: Boolean,
-    isGroupedMode: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    groupedRange: {
-      type: Number,
-      value: 0,
-      reflectToAttribute: true,
-      notify: true
-    },
-    queryStartTime: String,
-    queryEndTime: String,
-    showMenuPromo_: {
-      type: Boolean,
-      value: function() {
-        return loadTimeData.getBoolean('showMenuPromo');
-      }
-    }
-  },
-  get searchField() {
-    return this.$['main-toolbar'].getSearchField();
-  },
-  showSearchField: function() {
-    this.searchField.showAndFocus();
-  },
-  changeToolbarView_: function() {
-    this.itemsSelected_ = this.count > 0;
-  },
-  searchTermChanged_: function() {
-    if (this.searchField.getValue() != this.searchTerm) {
-      this.searchField.showAndFocus();
-      this.searchField.setValue(this.searchTerm);
-    }
-  },
-  onMenuPromoShown_: function() {
-    md_history.BrowserService.getInstance().menuPromoShown();
-  },
-  onSearchChanged_: function(event) {
-    this.searchTerm = event.detail;
-  },
-  onInfoButtonTap_: function() {
-    var dropdown = this.$.syncNotice.get();
-    dropdown.positionTarget = this.$$('#info-button-icon');
-    if (dropdown.style.display == 'none') dropdown.open();
-  },
-  onClearSelectionTap_: function() {
-    this.fire('unselect-all');
-  },
-  onDeleteTap_: function() {
-    this.fire('delete-selected');
-  },
-  deletingAllowed_: function() {
-    return loadTimeData.getBoolean('allowDeletingHistory');
-  },
-  numberOfItemsSelected_: function(count) {
-    return count > 0 ? loadTimeData.getStringF('itemsSelected', count) : '';
-  },
-  getHistoryInterval_: function(queryStartTime, queryEndTime) {
-    return loadTimeData.getStringF('historyInterval', queryStartTime, queryEndTime);
-  },
-  hasDrawerChanged_: function() {
-    this.updateStyles();
-  }
-});
-
-(function() {
-  var IOS = navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);
-  var IOS_TOUCH_SCROLLING = IOS && IOS[1] >= 8;
-  var DEFAULT_PHYSICAL_COUNT = 3;
-  var HIDDEN_Y = '-10000px';
-  var DEFAULT_GRID_SIZE = 200;
-  var SECRET_TABINDEX = -100;
-  Polymer({
-    is: 'iron-list',
-    properties: {
-      items: {
-        type: Array
-      },
-      maxPhysicalCount: {
-        type: Number,
-        value: 500
-      },
-      as: {
-        type: String,
-        value: 'item'
-      },
-      indexAs: {
-        type: String,
-        value: 'index'
-      },
-      selectedAs: {
-        type: String,
-        value: 'selected'
-      },
-      grid: {
-        type: Boolean,
-        value: false,
-        reflectToAttribute: true
-      },
-      selectionEnabled: {
-        type: Boolean,
-        value: false
-      },
-      selectedItem: {
-        type: Object,
-        notify: true
-      },
-      selectedItems: {
-        type: Object,
-        notify: true
-      },
-      multiSelection: {
-        type: Boolean,
-        value: false
-      }
-    },
-    observers: [ '_itemsChanged(items.*)', '_selectionEnabledChanged(selectionEnabled)', '_multiSelectionChanged(multiSelection)', '_setOverflow(scrollTarget)' ],
-    behaviors: [ Polymer.Templatizer, Polymer.IronResizableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronScrollTargetBehavior ],
-    keyBindings: {
-      up: '_didMoveUp',
-      down: '_didMoveDown',
-      enter: '_didEnter'
-    },
-    _ratio: .5,
-    _scrollerPaddingTop: 0,
-    _scrollPosition: 0,
-    _physicalSize: 0,
-    _physicalAverage: 0,
-    _physicalAverageCount: 0,
-    _physicalTop: 0,
-    _virtualCount: 0,
-    _physicalIndexForKey: null,
-    _estScrollHeight: 0,
-    _scrollHeight: 0,
-    _viewportHeight: 0,
-    _viewportWidth: 0,
-    _physicalItems: null,
-    _physicalSizes: null,
-    _firstVisibleIndexVal: null,
-    _lastVisibleIndexVal: null,
-    _collection: null,
-    _maxPages: 3,
-    _focusedItem: null,
-    _focusedIndex: -1,
-    _offscreenFocusedItem: null,
-    _focusBackfillItem: null,
-    _itemsPerRow: 1,
-    _itemWidth: 0,
-    _rowHeight: 0,
-    _templateCost: 0,
-    get _physicalBottom() {
-      return this._physicalTop + this._physicalSize;
-    },
-    get _scrollBottom() {
-      return this._scrollPosition + this._viewportHeight;
-    },
-    get _virtualEnd() {
-      return this._virtualStart + this._physicalCount - 1;
-    },
-    get _hiddenContentSize() {
-      var size = this.grid ? this._physicalRows * this._rowHeight : this._physicalSize;
-      return size - this._viewportHeight;
-    },
-    get _maxScrollTop() {
-      return this._estScrollHeight - this._viewportHeight + this._scrollerPaddingTop;
-    },
-    _minVirtualStart: 0,
-    get _maxVirtualStart() {
-      return Math.max(0, this._virtualCount - this._physicalCount);
-    },
-    _virtualStartVal: 0,
-    set _virtualStart(val) {
-      this._virtualStartVal = Math.min(this._maxVirtualStart, Math.max(this._minVirtualStart, val));
-    },
-    get _virtualStart() {
-      return this._virtualStartVal || 0;
-    },
-    _physicalStartVal: 0,
-    set _physicalStart(val) {
-      this._physicalStartVal = val % this._physicalCount;
-      if (this._physicalStartVal < 0) {
-        this._physicalStartVal = this._physicalCount + this._physicalStartVal;
-      }
-      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-    },
-    get _physicalStart() {
-      return this._physicalStartVal || 0;
-    },
-    _physicalCountVal: 0,
-    set _physicalCount(val) {
-      this._physicalCountVal = val;
-      this._physicalEnd = (this._physicalStart + this._physicalCount - 1) % this._physicalCount;
-    },
-    get _physicalCount() {
-      return this._physicalCountVal;
-    },
-    _physicalEnd: 0,
-    get _optPhysicalSize() {
-      if (this.grid) {
-        return this._estRowsInView * this._rowHeight * this._maxPages;
-      }
-      return this._viewportHeight * this._maxPages;
-    },
-    get _optPhysicalCount() {
-      return this._estRowsInView * this._itemsPerRow * this._maxPages;
-    },
-    get _isVisible() {
-      return Boolean(this.offsetWidth || this.offsetHeight);
-    },
-    get firstVisibleIndex() {
-      if (this._firstVisibleIndexVal === null) {
-        var physicalOffset = Math.floor(this._physicalTop + this._scrollerPaddingTop);
-        this._firstVisibleIndexVal = this._iterateItems(function(pidx, vidx) {
-          physicalOffset += this._getPhysicalSizeIncrement(pidx);
-          if (physicalOffset > this._scrollPosition) {
-            return this.grid ? vidx - vidx % this._itemsPerRow : vidx;
-          }
-          if (this.grid && this._virtualCount - 1 === vidx) {
-            return vidx - vidx % this._itemsPerRow;
-          }
-        }) || 0;
-      }
-      return this._firstVisibleIndexVal;
-    },
-    get lastVisibleIndex() {
-      if (this._lastVisibleIndexVal === null) {
-        if (this.grid) {
-          var lastIndex = this.firstVisibleIndex + this._estRowsInView * this._itemsPerRow - 1;
-          this._lastVisibleIndexVal = Math.min(this._virtualCount, lastIndex);
-        } else {
-          var physicalOffset = this._physicalTop;
-          this._iterateItems(function(pidx, vidx) {
-            if (physicalOffset < this._scrollBottom) {
-              this._lastVisibleIndexVal = vidx;
-            } else {
-              return true;
-            }
-            physicalOffset += this._getPhysicalSizeIncrement(pidx);
-          });
-        }
-      }
-      return this._lastVisibleIndexVal;
-    },
-    get _defaultScrollTarget() {
-      return this;
-    },
-    get _virtualRowCount() {
-      return Math.ceil(this._virtualCount / this._itemsPerRow);
-    },
-    get _estRowsInView() {
-      return Math.ceil(this._viewportHeight / this._rowHeight);
-    },
-    get _physicalRows() {
-      return Math.ceil(this._physicalCount / this._itemsPerRow);
-    },
-    ready: function() {
-      this.addEventListener('focus', this._didFocus.bind(this), true);
-    },
-    attached: function() {
-      this.updateViewportBoundaries();
-      if (this._physicalCount === 0) {
-        this._debounceTemplate(this._render);
-      }
-      this.listen(this, 'iron-resize', '_resizeHandler');
-    },
-    detached: function() {
-      this.unlisten(this, 'iron-resize', '_resizeHandler');
-    },
-    _setOverflow: function(scrollTarget) {
-      this.style.webkitOverflowScrolling = scrollTarget === this ? 'touch' : '';
-      this.style.overflow = scrollTarget === this ? 'auto' : '';
-    },
-    updateViewportBoundaries: function() {
-      this._scrollerPaddingTop = this.scrollTarget === this ? 0 : parseInt(window.getComputedStyle(this)['padding-top'], 10);
-      this._viewportHeight = this._scrollTargetHeight;
-      if (this.grid) {
-        this._updateGridMetrics();
-      }
-    },
-    _scrollHandler: function() {
-      var scrollTop = Math.max(0, Math.min(this._maxScrollTop, this._scrollTop));
-      var delta = scrollTop - this._scrollPosition;
-      var tileHeight, tileTop, kth, recycledTileSet, scrollBottom, physicalBottom;
-      var ratio = this._ratio;
-      var recycledTiles = 0;
-      var hiddenContentSize = this._hiddenContentSize;
-      var currentRatio = ratio;
-      var movingUp = [];
-      this._scrollPosition = scrollTop;
-      this._firstVisibleIndexVal = null;
-      this._lastVisibleIndexVal = null;
-      scrollBottom = this._scrollBottom;
-      physicalBottom = this._physicalBottom;
-      if (Math.abs(delta) > this._physicalSize) {
-        this._physicalTop += delta;
-        recycledTiles = Math.round(delta / this._physicalAverage);
-      } else if (delta < 0) {
-        var topSpace = scrollTop - this._physicalTop;
-        var virtualStart = this._virtualStart;
-        recycledTileSet = [];
-        kth = this._physicalEnd;
-        currentRatio = topSpace / hiddenContentSize;
-        while (currentRatio < ratio && recycledTiles < this._physicalCount && virtualStart - recycledTiles > 0 && physicalBottom - this._getPhysicalSizeIncrement(kth) > scrollBottom) {
-          tileHeight = this._getPhysicalSizeIncrement(kth);
-          currentRatio += tileHeight / hiddenContentSize;
-          physicalBottom -= tileHeight;
-          recycledTileSet.push(kth);
-          recycledTiles++;
-          kth = kth === 0 ? this._physicalCount - 1 : kth - 1;
-        }
-        movingUp = recycledTileSet;
-        recycledTiles = -recycledTiles;
-      } else if (delta > 0) {
-        var bottomSpace = physicalBottom - scrollBottom;
-        var virtualEnd = this._virtualEnd;
-        var lastVirtualItemIndex = this._virtualCount - 1;
-        recycledTileSet = [];
-        kth = this._physicalStart;
-        currentRatio = bottomSpace / hiddenContentSize;
-        while (currentRatio < ratio && recycledTiles < this._physicalCount && virtualEnd + recycledTiles < lastVirtualItemIndex && this._physicalTop + this._getPhysicalSizeIncrement(kth) < scrollTop) {
-          tileHeight = this._getPhysicalSizeIncrement(kth);
-          currentRatio += tileHeight / hiddenContentSize;
-          this._physicalTop += tileHeight;
-          recycledTileSet.push(kth);
-          recycledTiles++;
-          kth = (kth + 1) % this._physicalCount;
-        }
-      }
-      if (recycledTiles === 0) {
-        if (physicalBottom < scrollBottom || this._physicalTop > scrollTop) {
-          this._increasePoolIfNeeded();
-        }
-      } else {
-        this._virtualStart = this._virtualStart + recycledTiles;
-        this._physicalStart = this._physicalStart + recycledTiles;
-        this._update(recycledTileSet, movingUp);
-      }
-    },
-    _update: function(itemSet, movingUp) {
-      this._manageFocus();
-      this._assignModels(itemSet);
-      this._updateMetrics(itemSet);
-      if (movingUp) {
-        while (movingUp.length) {
-          var idx = movingUp.pop();
-          this._physicalTop -= this._getPhysicalSizeIncrement(idx);
-        }
-      }
-      this._positionItems();
-      this._updateScrollerSize();
-      this._increasePoolIfNeeded();
-    },
-    _createPool: function(size) {
-      var physicalItems = new Array(size);
-      this._ensureTemplatized();
-      for (var i = 0; i < size; i++) {
-        var inst = this.stamp(null);
-        physicalItems[i] = inst.root.querySelector('*');
-        Polymer.dom(this).appendChild(inst.root);
-      }
-      return physicalItems;
-    },
-    _increasePoolIfNeeded: function() {
-      if (this._viewportHeight === 0) {
-        return false;
-      }
-      var self = this;
-      var isClientFull = this._physicalBottom >= this._scrollBottom && this._physicalTop <= this._scrollPosition;
-      if (this._physicalSize >= this._optPhysicalSize && isClientFull) {
-        return false;
-      }
-      var maxPoolSize = Math.round(this._physicalCount * .5);
-      if (!isClientFull) {
-        this._debounceTemplate(this._increasePool.bind(this, maxPoolSize));
-        return true;
-      }
-      this._yield(function() {
-        self._increasePool(Math.min(maxPoolSize, Math.max(1, Math.round(50 / self._templateCost))));
-      });
-      return true;
-    },
-    _yield: function(cb) {
-      var g = window;
-      var handle = g.requestIdleCallback ? g.requestIdleCallback(cb) : g.setTimeout(cb, 16);
-      Polymer.dom.addDebouncer({
-        complete: function() {
-          g.cancelIdleCallback ? g.cancelIdleCallback(handle) : g.clearTimeout(handle);
-          cb();
-        }
-      });
-    },
-    _increasePool: function(missingItems) {
-      var nextPhysicalCount = Math.min(this._physicalCount + missingItems, this._virtualCount - this._virtualStart, Math.max(this.maxPhysicalCount, DEFAULT_PHYSICAL_COUNT));
-      var prevPhysicalCount = this._physicalCount;
-      var delta = nextPhysicalCount - prevPhysicalCount;
-      var ts = window.performance.now();
-      if (delta <= 0) {
-        return;
-      }
-      [].push.apply(this._physicalItems, this._createPool(delta));
-      [].push.apply(this._physicalSizes, new Array(delta));
-      this._physicalCount = prevPhysicalCount + delta;
-      if (this._physicalStart > this._physicalEnd && this._isIndexRendered(this._focusedIndex) && this._getPhysicalIndex(this._focusedIndex) < this._physicalEnd) {
-        this._physicalStart = this._physicalStart + delta;
-      }
-      this._update();
-      this._templateCost = (window.performance.now() - ts) / delta;
-    },
-    _render: function() {
-      if (this.isAttached && this._isVisible) {
-        if (this._physicalCount === 0) {
-          this._increasePool(DEFAULT_PHYSICAL_COUNT);
-        } else {
-          this._update();
-        }
-      }
-    },
-    _ensureTemplatized: function() {
-      if (!this.ctor) {
-        var props = {};
-        props.__key__ = true;
-        props[this.as] = true;
-        props[this.indexAs] = true;
-        props[this.selectedAs] = true;
-        props.tabIndex = true;
-        this._instanceProps = props;
-        this._userTemplate = Polymer.dom(this).querySelector('template');
-        if (this._userTemplate) {
-          this.templatize(this._userTemplate);
-        } else {
-          console.warn('iron-list requires a template to be provided in light-dom');
-        }
-      }
-    },
-    _getStampedChildren: function() {
-      return this._physicalItems;
-    },
-    _forwardInstancePath: function(inst, path, value) {
-      if (path.indexOf(this.as + '.') === 0) {
-        this.notifyPath('items.' + inst.__key__ + '.' + path.slice(this.as.length + 1), value);
-      }
-    },
-    _forwardParentProp: function(prop, value) {
-      if (this._physicalItems) {
-        this._physicalItems.forEach(function(item) {
-          item._templateInstance[prop] = value;
-        }, this);
-      }
-    },
-    _forwardParentPath: function(path, value) {
-      if (this._physicalItems) {
-        this._physicalItems.forEach(function(item) {
-          item._templateInstance.notifyPath(path, value, true);
-        }, this);
-      }
-    },
-    _forwardItemPath: function(path, value) {
-      if (!this._physicalIndexForKey) {
-        return;
-      }
-      var dot = path.indexOf('.');
-      var key = path.substring(0, dot < 0 ? path.length : dot);
-      var idx = this._physicalIndexForKey[key];
-      var offscreenItem = this._offscreenFocusedItem;
-      var el = offscreenItem && offscreenItem._templateInstance.__key__ === key ? offscreenItem : this._physicalItems[idx];
-      if (!el || el._templateInstance.__key__ !== key) {
-        return;
-      }
-      if (dot >= 0) {
-        path = this.as + '.' + path.substring(dot + 1);
-        el._templateInstance.notifyPath(path, value, true);
-      } else {
-        var currentItem = el._templateInstance[this.as];
-        if (Array.isArray(this.selectedItems)) {
-          for (var i = 0; i < this.selectedItems.length; i++) {
-            if (this.selectedItems[i] === currentItem) {
-              this.set('selectedItems.' + i, value);
-              break;
-            }
-          }
-        } else if (this.selectedItem === currentItem) {
-          this.set('selectedItem', value);
-        }
-        el._templateInstance[this.as] = value;
-      }
-    },
-    _itemsChanged: function(change) {
-      if (change.path === 'items') {
-        this._virtualStart = 0;
-        this._physicalTop = 0;
-        this._virtualCount = this.items ? this.items.length : 0;
-        this._collection = this.items ? Polymer.Collection.get(this.items) : null;
-        this._physicalIndexForKey = {};
-        this._firstVisibleIndexVal = null;
-        this._lastVisibleIndexVal = null;
-        this._physicalCount = this._physicalCount || 0;
-        this._physicalItems = this._physicalItems || [];
-        this._physicalSizes = this._physicalSizes || [];
-        this._physicalStart = 0;
-        this._resetScrollPosition(0);
-        this._removeFocusedItem();
-        this._debounceTemplate(this._render);
-      } else if (change.path === 'items.splices') {
-        this._adjustVirtualIndex(change.value.indexSplices);
-        this._virtualCount = this.items ? this.items.length : 0;
-        this._debounceTemplate(this._render);
-      } else {
-        this._forwardItemPath(change.path.split('.').slice(1).join('.'), change.value);
-      }
-    },
-    _adjustVirtualIndex: function(splices) {
-      splices.forEach(function(splice) {
-        splice.removed.forEach(this._removeItem, this);
-        if (splice.index < this._virtualStart) {
-          var delta = Math.max(splice.addedCount - splice.removed.length, splice.index - this._virtualStart);
-          this._virtualStart = this._virtualStart + delta;
-          if (this._focusedIndex >= 0) {
-            this._focusedIndex = this._focusedIndex + delta;
-          }
-        }
-      }, this);
-    },
-    _removeItem: function(item) {
-      this.$.selector.deselect(item);
-      if (this._focusedItem && this._focusedItem._templateInstance[this.as] === item) {
-        this._removeFocusedItem();
-      }
-    },
-    _iterateItems: function(fn, itemSet) {
-      var pidx, vidx, rtn, i;
-      if (arguments.length === 2 && itemSet) {
-        for (i = 0; i < itemSet.length; i++) {
-          pidx = itemSet[i];
-          vidx = this._computeVidx(pidx);
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-      } else {
-        pidx = this._physicalStart;
-        vidx = this._virtualStart;
-        for (;pidx < this._physicalCount; pidx++, vidx++) {
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-        for (pidx = 0; pidx < this._physicalStart; pidx++, vidx++) {
-          if ((rtn = fn.call(this, pidx, vidx)) != null) {
-            return rtn;
-          }
-        }
-      }
-    },
-    _computeVidx: function(pidx) {
-      if (pidx >= this._physicalStart) {
-        return this._virtualStart + (pidx - this._physicalStart);
-      }
-      return this._virtualStart + (this._physicalCount - this._physicalStart) + pidx;
-    },
-    _assignModels: function(itemSet) {
-      this._iterateItems(function(pidx, vidx) {
-        var el = this._physicalItems[pidx];
-        var inst = el._templateInstance;
-        var item = this.items && this.items[vidx];
-        if (item != null) {
-          inst[this.as] = item;
-          inst.__key__ = this._collection.getKey(item);
-          inst[this.selectedAs] = this.$.selector.isSelected(item);
-          inst[this.indexAs] = vidx;
-          inst.tabIndex = this._focusedIndex === vidx ? 0 : -1;
-          this._physicalIndexForKey[inst.__key__] = pidx;
-          el.removeAttribute('hidden');
-        } else {
-          inst.__key__ = null;
-          el.setAttribute('hidden', '');
-        }
-      }, itemSet);
-    },
-    _updateMetrics: function(itemSet) {
-      Polymer.dom.flush();
-      var newPhysicalSize = 0;
-      var oldPhysicalSize = 0;
-      var prevAvgCount = this._physicalAverageCount;
-      var prevPhysicalAvg = this._physicalAverage;
-      this._iterateItems(function(pidx, vidx) {
-        oldPhysicalSize += this._physicalSizes[pidx] || 0;
-        this._physicalSizes[pidx] = this._physicalItems[pidx].offsetHeight;
-        newPhysicalSize += this._physicalSizes[pidx];
-        this._physicalAverageCount += this._physicalSizes[pidx] ? 1 : 0;
-      }, itemSet);
-      this._viewportHeight = this._scrollTargetHeight;
-      if (this.grid) {
-        this._updateGridMetrics();
-        this._physicalSize = Math.ceil(this._physicalCount / this._itemsPerRow) * this._rowHeight;
-      } else {
-        this._physicalSize = this._physicalSize + newPhysicalSize - oldPhysicalSize;
-      }
-      if (this._physicalAverageCount !== prevAvgCount) {
-        this._physicalAverage = Math.round((prevPhysicalAvg * prevAvgCount + newPhysicalSize) / this._physicalAverageCount);
-      }
-    },
-    _updateGridMetrics: function() {
-      this._viewportWidth = this.$.items.offsetWidth;
-      this._itemWidth = this._physicalCount > 0 ? this._physicalItems[0].getBoundingClientRect().width : DEFAULT_GRID_SIZE;
-      this._rowHeight = this._physicalCount > 0 ? this._physicalItems[0].offsetHeight : DEFAULT_GRID_SIZE;
-      this._itemsPerRow = this._itemWidth ? Math.floor(this._viewportWidth / this._itemWidth) : this._itemsPerRow;
-    },
-    _positionItems: function() {
-      this._adjustScrollPosition();
-      var y = this._physicalTop;
-      if (this.grid) {
-        var totalItemWidth = this._itemsPerRow * this._itemWidth;
-        var rowOffset = (this._viewportWidth - totalItemWidth) / 2;
-        this._iterateItems(function(pidx, vidx) {
-          var modulus = vidx % this._itemsPerRow;
-          var x = Math.floor(modulus * this._itemWidth + rowOffset);
-          this.translate3d(x + 'px', y + 'px', 0, this._physicalItems[pidx]);
-          if (this._shouldRenderNextRow(vidx)) {
-            y += this._rowHeight;
-          }
-        });
-      } else {
-        this._iterateItems(function(pidx, vidx) {
-          this.translate3d(0, y + 'px', 0, this._physicalItems[pidx]);
-          y += this._physicalSizes[pidx];
-        });
-      }
-    },
-    _getPhysicalSizeIncrement: function(pidx) {
-      if (!this.grid) {
-        return this._physicalSizes[pidx];
-      }
-      if (this._computeVidx(pidx) % this._itemsPerRow !== this._itemsPerRow - 1) {
-        return 0;
-      }
-      return this._rowHeight;
-    },
-    _shouldRenderNextRow: function(vidx) {
-      return vidx % this._itemsPerRow === this._itemsPerRow - 1;
-    },
-    _adjustScrollPosition: function() {
-      var deltaHeight = this._virtualStart === 0 ? this._physicalTop : Math.min(this._scrollPosition + this._physicalTop, 0);
-      if (deltaHeight) {
-        this._physicalTop = this._physicalTop - deltaHeight;
-        if (!IOS_TOUCH_SCROLLING && this._physicalTop !== 0) {
-          this._resetScrollPosition(this._scrollTop - deltaHeight);
-        }
-      }
-    },
-    _resetScrollPosition: function(pos) {
-      if (this.scrollTarget) {
-        this._scrollTop = pos;
-        this._scrollPosition = this._scrollTop;
-      }
-    },
-    _updateScrollerSize: function(forceUpdate) {
-      if (this.grid) {
-        this._estScrollHeight = this._virtualRowCount * this._rowHeight;
-      } else {
-        this._estScrollHeight = this._physicalBottom + Math.max(this._virtualCount - this._physicalCount - this._virtualStart, 0) * this._physicalAverage;
-      }
-      forceUpdate = forceUpdate || this._scrollHeight === 0;
-      forceUpdate = forceUpdate || this._scrollPosition >= this._estScrollHeight - this._physicalSize;
-      forceUpdate = forceUpdate || this.grid && this.$.items.style.height < this._estScrollHeight;
-      if (forceUpdate || Math.abs(this._estScrollHeight - this._scrollHeight) >= this._optPhysicalSize) {
-        this.$.items.style.height = this._estScrollHeight + 'px';
-        this._scrollHeight = this._estScrollHeight;
-      }
-    },
-    scrollToItem: function(item) {
-      return this.scrollToIndex(this.items.indexOf(item));
-    },
-    scrollToIndex: function(idx) {
-      if (typeof idx !== 'number' || idx < 0 || idx > this.items.length - 1) {
-        return;
-      }
-      Polymer.dom.flush();
-      if (this._physicalCount === 0) {
-        return;
-      }
-      idx = Math.min(Math.max(idx, 0), this._virtualCount - 1);
-      if (!this._isIndexRendered(idx) || idx >= this._maxVirtualStart) {
-        this._virtualStart = this.grid ? idx - this._itemsPerRow * 2 : idx - 1;
-      }
-      this._manageFocus();
-      this._assignModels();
-      this._updateMetrics();
-      this._physicalTop = Math.floor(this._virtualStart / this._itemsPerRow) * this._physicalAverage;
-      var currentTopItem = this._physicalStart;
-      var currentVirtualItem = this._virtualStart;
-      var targetOffsetTop = 0;
-      var hiddenContentSize = this._hiddenContentSize;
-      while (currentVirtualItem < idx && targetOffsetTop <= hiddenContentSize) {
-        targetOffsetTop = targetOffsetTop + this._getPhysicalSizeIncrement(currentTopItem);
-        currentTopItem = (currentTopItem + 1) % this._physicalCount;
-        currentVirtualItem++;
-      }
-      this._updateScrollerSize(true);
-      this._positionItems();
-      this._resetScrollPosition(this._physicalTop + this._scrollerPaddingTop + targetOffsetTop);
-      this._increasePoolIfNeeded();
-      this._firstVisibleIndexVal = null;
-      this._lastVisibleIndexVal = null;
-    },
-    _resetAverage: function() {
-      this._physicalAverage = 0;
-      this._physicalAverageCount = 0;
-    },
-    _resizeHandler: function() {
-      if (IOS && Math.abs(this._viewportHeight - this._scrollTargetHeight) < 100) {
-        return;
-      }
-      Polymer.dom.addDebouncer(this.debounce('_debounceTemplate', function() {
-        this.updateViewportBoundaries();
-        this._render();
-        if (this._physicalCount > 0 && this._isVisible) {
-          this._resetAverage();
-          this.scrollToIndex(this.firstVisibleIndex);
-        }
-      }.bind(this), 1));
-    },
-    _getModelFromItem: function(item) {
-      var key = this._collection.getKey(item);
-      var pidx = this._physicalIndexForKey[key];
-      if (pidx != null) {
-        return this._physicalItems[pidx]._templateInstance;
-      }
-      return null;
-    },
-    _getNormalizedItem: function(item) {
-      if (this._collection.getKey(item) === undefined) {
-        if (typeof item === 'number') {
-          item = this.items[item];
-          if (!item) {
-            throw new RangeError('<item> not found');
-          }
-          return item;
-        }
-        throw new TypeError('<item> should be a valid item');
-      }
-      return item;
-    },
-    selectItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var model = this._getModelFromItem(item);
-      if (!this.multiSelection && this.selectedItem) {
-        this.deselectItem(this.selectedItem);
-      }
-      if (model) {
-        model[this.selectedAs] = true;
-      }
-      this.$.selector.select(item);
-      this.updateSizeForItem(item);
-    },
-    deselectItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var model = this._getModelFromItem(item);
-      if (model) {
-        model[this.selectedAs] = false;
-      }
-      this.$.selector.deselect(item);
-      this.updateSizeForItem(item);
-    },
-    toggleSelectionForItem: function(item) {
-      item = this._getNormalizedItem(item);
-      if (this.$.selector.isSelected(item)) {
-        this.deselectItem(item);
-      } else {
-        this.selectItem(item);
-      }
-    },
-    clearSelection: function() {
-      function unselect(item) {
-        var model = this._getModelFromItem(item);
-        if (model) {
-          model[this.selectedAs] = false;
-        }
-      }
-      if (Array.isArray(this.selectedItems)) {
-        this.selectedItems.forEach(unselect, this);
-      } else if (this.selectedItem) {
-        unselect.call(this, this.selectedItem);
-      }
-      this.$.selector.clearSelection();
-    },
-    _selectionEnabledChanged: function(selectionEnabled) {
-      var handler = selectionEnabled ? this.listen : this.unlisten;
-      handler.call(this, this, 'tap', '_selectionHandler');
-    },
-    _selectionHandler: function(e) {
-      var model = this.modelForElement(e.target);
-      if (!model) {
-        return;
-      }
-      var modelTabIndex, activeElTabIndex;
-      var target = Polymer.dom(e).path[0];
-      var activeEl = Polymer.dom(this.domHost ? this.domHost.root : document).activeElement;
-      var physicalItem = this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];
-      if (target.localName === 'input' || target.localName === 'button' || target.localName === 'select') {
-        return;
-      }
-      modelTabIndex = model.tabIndex;
-      model.tabIndex = SECRET_TABINDEX;
-      activeElTabIndex = activeEl ? activeEl.tabIndex : -1;
-      model.tabIndex = modelTabIndex;
-      if (activeEl && physicalItem !== activeEl && physicalItem.contains(activeEl) && activeElTabIndex !== SECRET_TABINDEX) {
-        return;
-      }
-      this.toggleSelectionForItem(model[this.as]);
-    },
-    _multiSelectionChanged: function(multiSelection) {
-      this.clearSelection();
-      this.$.selector.multi = multiSelection;
-    },
-    updateSizeForItem: function(item) {
-      item = this._getNormalizedItem(item);
-      var key = this._collection.getKey(item);
-      var pidx = this._physicalIndexForKey[key];
-      if (pidx != null) {
-        this._updateMetrics([ pidx ]);
-        this._positionItems();
-      }
-    },
-    _manageFocus: function() {
-      var fidx = this._focusedIndex;
-      if (fidx >= 0 && fidx < this._virtualCount) {
-        if (this._isIndexRendered(fidx)) {
-          this._restoreFocusedItem();
-        } else {
-          this._createFocusBackfillItem();
-        }
-      } else if (this._virtualCount > 0 && this._physicalCount > 0) {
-        this._focusedIndex = this._virtualStart;
-        this._focusedItem = this._physicalItems[this._physicalStart];
-      }
-    },
-    _isIndexRendered: function(idx) {
-      return idx >= this._virtualStart && idx <= this._virtualEnd;
-    },
-    _isIndexVisible: function(idx) {
-      return idx >= this.firstVisibleIndex && idx <= this.lastVisibleIndex;
-    },
-    _getPhysicalIndex: function(idx) {
-      return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))];
-    },
-    _focusPhysicalItem: function(idx) {
-      if (idx < 0 || idx >= this._virtualCount) {
-        return;
-      }
-      this._restoreFocusedItem();
-      if (!this._isIndexRendered(idx)) {
-        this.scrollToIndex(idx);
-      }
-      var physicalItem = this._physicalItems[this._getPhysicalIndex(idx)];
-      var model = physicalItem._templateInstance;
-      var focusable;
-      model.tabIndex = SECRET_TABINDEX;
-      if (physicalItem.tabIndex === SECRET_TABINDEX) {
-        focusable = physicalItem;
-      }
-      if (!focusable) {
-        focusable = Polymer.dom(physicalItem).querySelector('[tabindex="' + SECRET_TABINDEX + '"]');
-      }
-      model.tabIndex = 0;
-      this._focusedIndex = idx;
-      focusable && focusable.focus();
-    },
-    _removeFocusedItem: function() {
-      if (this._offscreenFocusedItem) {
-        Polymer.dom(this).removeChild(this._offscreenFocusedItem);
-      }
-      this._offscreenFocusedItem = null;
-      this._focusBackfillItem = null;
-      this._focusedItem = null;
-      this._focusedIndex = -1;
-    },
-    _createFocusBackfillItem: function() {
-      var pidx, fidx = this._focusedIndex;
-      if (this._offscreenFocusedItem || fidx < 0) {
-        return;
-      }
-      if (!this._focusBackfillItem) {
-        var stampedTemplate = this.stamp(null);
-        this._focusBackfillItem = stampedTemplate.root.querySelector('*');
-        Polymer.dom(this).appendChild(stampedTemplate.root);
-      }
-      pidx = this._getPhysicalIndex(fidx);
-      if (pidx != null) {
-        this._offscreenFocusedItem = this._physicalItems[pidx];
-        this._physicalItems[pidx] = this._focusBackfillItem;
-        this.translate3d(0, HIDDEN_Y, 0, this._offscreenFocusedItem);
-      }
-    },
-    _restoreFocusedItem: function() {
-      var pidx, fidx = this._focusedIndex;
-      if (!this._offscreenFocusedItem || this._focusedIndex < 0) {
-        return;
-      }
-      this._assignModels();
-      pidx = this._getPhysicalIndex(fidx);
-      if (pidx != null) {
-        this._focusBackfillItem = this._physicalItems[pidx];
-        this._physicalItems[pidx] = this._offscreenFocusedItem;
-        this._offscreenFocusedItem = null;
-        this.translate3d(0, HIDDEN_Y, 0, this._focusBackfillItem);
-      }
-    },
-    _didFocus: function(e) {
-      var targetModel = this.modelForElement(e.target);
-      var focusedModel = this._focusedItem ? this._focusedItem._templateInstance : null;
-      var hasOffscreenFocusedItem = this._offscreenFocusedItem !== null;
-      var fidx = this._focusedIndex;
-      if (!targetModel || !focusedModel) {
-        return;
-      }
-      if (focusedModel === targetModel) {
-        if (!this._isIndexVisible(fidx)) {
-          this.scrollToIndex(fidx);
-        }
-      } else {
-        this._restoreFocusedItem();
-        focusedModel.tabIndex = -1;
-        targetModel.tabIndex = 0;
-        fidx = targetModel[this.indexAs];
-        this._focusedIndex = fidx;
-        this._focusedItem = this._physicalItems[this._getPhysicalIndex(fidx)];
-        if (hasOffscreenFocusedItem && !this._offscreenFocusedItem) {
-          this._update();
-        }
-      }
-    },
-    _didMoveUp: function() {
-      this._focusPhysicalItem(this._focusedIndex - 1);
-    },
-    _didMoveDown: function(e) {
-      e.detail.keyboardEvent.preventDefault();
-      this._focusPhysicalItem(this._focusedIndex + 1);
-    },
-    _didEnter: function(e) {
-      this._focusPhysicalItem(this._focusedIndex);
-      this._selectionHandler(e.detail.keyboardEvent);
-    }
-  });
-})();
-
-Polymer({
-  is: 'iron-scroll-threshold',
-  properties: {
-    upperThreshold: {
-      type: Number,
-      value: 100
-    },
-    lowerThreshold: {
-      type: Number,
-      value: 100
-    },
-    upperTriggered: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      readOnly: true
-    },
-    lowerTriggered: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      readOnly: true
-    },
-    horizontal: {
-      type: Boolean,
-      value: false
-    }
-  },
-  behaviors: [ Polymer.IronScrollTargetBehavior ],
-  observers: [ '_setOverflow(scrollTarget)', '_initCheck(horizontal, isAttached)' ],
-  get _defaultScrollTarget() {
-    return this;
-  },
-  _setOverflow: function(scrollTarget) {
-    this.style.overflow = scrollTarget === this ? 'auto' : '';
-  },
-  _scrollHandler: function() {
-    var THROTTLE_THRESHOLD = 200;
-    if (!this.isDebouncerActive('_checkTheshold')) {
-      this.debounce('_checkTheshold', function() {
-        this.checkScrollThesholds();
-      }, THROTTLE_THRESHOLD);
-    }
-  },
-  _initCheck: function(horizontal, isAttached) {
-    if (isAttached) {
-      this.debounce('_init', function() {
-        this.clearTriggers();
-        this.checkScrollThesholds();
-      });
-    }
-  },
-  checkScrollThesholds: function() {
-    if (!this.scrollTarget || this.lowerTriggered && this.upperTriggered) {
-      return;
-    }
-    var upperScrollValue = this.horizontal ? this._scrollLeft : this._scrollTop;
-    var lowerScrollValue = this.horizontal ? this.scrollTarget.scrollWidth - this._scrollTargetWidth - this._scrollLeft : this.scrollTarget.scrollHeight - this._scrollTargetHeight - this._scrollTop;
-    if (upperScrollValue <= this.upperThreshold && !this.upperTriggered) {
-      this._setUpperTriggered(true);
-      this.fire('upper-threshold');
-    }
-    if (lowerScrollValue <= this.lowerThreshold && !this.lowerTriggered) {
-      this._setLowerTriggered(true);
-      this.fire('lower-threshold');
-    }
-  },
-  clearTriggers: function() {
-    this._setUpperTriggered(false);
-    this._setLowerTriggered(false);
-  }
-});
-
+Polymer({is:"history-toolbar",properties:{count:{type:Number,value:0,observer:"changeToolbarView_"},itemsSelected_:{type:Boolean,value:false,reflectToAttribute:true},searchTerm:{type:String,observer:"searchTermChanged_",notify:true},spinnerActive:{type:Boolean,value:false},hasDrawer:{type:Boolean,observer:"hasDrawerChanged_",reflectToAttribute:true},showSyncNotice:Boolean,isGroupedMode:{type:Boolean,reflectToAttribute:true},groupedRange:{type:Number,value:0,reflectToAttribute:true,notify:true},queryStartTime:String,queryEndTime:String,showMenuPromo_:{type:Boolean,value:function(){return loadTimeData.getBoolean("showMenuPromo")}}},get searchField(){return this.$["main-toolbar"].getSearchField()},showSearchField:function(){this.searchField.showAndFocus()},changeToolbarView_:function(){this.itemsSelected_=this.count>0},searchTermChanged_:function(){if(this.searchField.getValue()!=this.searchTerm){this.searchField.showAndFocus();this.searchField.setValue(this.searchTerm)}},onMenuPromoShown_:function(){md_history.BrowserService.getInstance().menuPromoShown()},onSearchChanged_:function(event){this.searchTerm=event.detail},onInfoButtonTap_:function(){var dropdown=this.$.syncNotice.get();dropdown.positionTarget=this.$$("#info-button-icon");if(dropdown.style.display=="none")dropdown.open()},onClearSelectionTap_:function(){this.fire("unselect-all")},onDeleteTap_:function(){this.fire("delete-selected")},deletingAllowed_:function(){return loadTimeData.getBoolean("allowDeletingHistory")},numberOfItemsSelected_:function(count){return count>0?loadTimeData.getStringF("itemsSelected",count):""},getHistoryInterval_:function(queryStartTime,queryEndTime){return loadTimeData.getStringF("historyInterval",queryStartTime,queryEndTime)},hasDrawerChanged_:function(){this.updateStyles()}});(function(){var IOS=navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);var IOS_TOUCH_SCROLLING=IOS&&IOS[1]>=8;var DEFAULT_PHYSICAL_COUNT=3;var HIDDEN_Y="-10000px";var DEFAULT_GRID_SIZE=200;var SECRET_TABINDEX=-100;Polymer({is:"iron-list",properties:{items:{type:Array},maxPhysicalCount:{type:Number,value:500},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},selectedAs:{type:String,value:"selected"},grid:{type:Boolean,value:false,reflectToAttribute:true},selectionEnabled:{type:Boolean,value:false},selectedItem:{type:Object,notify:true},selectedItems:{type:Object,notify:true},multiSelection:{type:Boolean,value:false}},observers:["_itemsChanged(items.*)","_selectionEnabledChanged(selectionEnabled)","_multiSelectionChanged(multiSelection)","_setOverflow(scrollTarget)"],behaviors:[Polymer.Templatizer,Polymer.IronResizableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronScrollTargetBehavior],keyBindings:{up:"_didMoveUp",down:"_didMoveDown",enter:"_didEnter"},_ratio:.5,_scrollerPaddingTop:0,_scrollPosition:0,_physicalSize:0,_physicalAverage:0,_physicalAverageCount:0,_physicalTop:0,_virtualCount:0,_physicalIndexForKey:null,_estScrollHeight:0,_scrollHeight:0,_viewportHeight:0,_viewportWidth:0,_physicalItems:null,_physicalSizes:null,_firstVisibleIndexVal:null,_lastVisibleIndexVal:null,_collection:null,_maxPages:3,_focusedItem:null,_focusedIndex:-1,_offscreenFocusedItem:null,_focusBackfillItem:null,_itemsPerRow:1,_itemWidth:0,_rowHeight:0,_templateCost:0,get _physicalBottom(){return this._physicalTop+this._physicalSize},get _scrollBottom(){return this._scrollPosition+this._viewportHeight},get _virtualEnd(){return this._virtualStart+this._physicalCount-1},get _hiddenContentSize(){var size=this.grid?this._physicalRows*this._rowHeight:this._physicalSize;return size-this._viewportHeight},get _maxScrollTop(){return this._estScrollHeight-this._viewportHeight+this._scrollerPaddingTop},_minVirtualStart:0,get _maxVirtualStart(){return Math.max(0,this._virtualCount-this._physicalCount)},_virtualStartVal:0,set _virtualStart(val){this._virtualStartVal=Math.min(this._maxVirtualStart,Math.max(this._minVirtualStart,val))},get _virtualStart(){return this._virtualStartVal||0},_physicalStartVal:0,set _physicalStart(val){this._physicalStartVal=val%this._physicalCount;if(this._physicalStartVal<0){this._physicalStartVal=this._physicalCount+this._physicalStartVal}this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalStart(){return this._physicalStartVal||0},_physicalCountVal:0,set _physicalCount(val){this._physicalCountVal=val;this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalCount(){return this._physicalCountVal},_physicalEnd:0,get _optPhysicalSize(){if(this.grid){return this._estRowsInView*this._rowHeight*this._maxPages}return this._viewportHeight*this._maxPages},get _optPhysicalCount(){return this._estRowsInView*this._itemsPerRow*this._maxPages},get _isVisible(){return Boolean(this.offsetWidth||this.offsetHeight)},get firstVisibleIndex(){if(this._firstVisibleIndexVal===null){var physicalOffset=Math.floor(this._physicalTop+this._scrollerPaddingTop);this._firstVisibleIndexVal=this._iterateItems(function(pidx,vidx){physicalOffset+=this._getPhysicalSizeIncrement(pidx);if(physicalOffset>this._scrollPosition){return this.grid?vidx-vidx%this._itemsPerRow:vidx}if(this.grid&&this._virtualCount-1===vidx){return vidx-vidx%this._itemsPerRow}})||0}return this._firstVisibleIndexVal},get lastVisibleIndex(){if(this._lastVisibleIndexVal===null){if(this.grid){var lastIndex=this.firstVisibleIndex+this._estRowsInView*this._itemsPerRow-1;this._lastVisibleIndexVal=Math.min(this._virtualCount,lastIndex)}else{var physicalOffset=this._physicalTop;this._iterateItems(function(pidx,vidx){if(physicalOffset<this._scrollBottom){this._lastVisibleIndexVal=vidx}else{return true}physicalOffset+=this._getPhysicalSizeIncrement(pidx)})}}return this._lastVisibleIndexVal},get _defaultScrollTarget(){return this},get _virtualRowCount(){return Math.ceil(this._virtualCount/this._itemsPerRow)},get _estRowsInView(){return Math.ceil(this._viewportHeight/this._rowHeight)},get _physicalRows(){return Math.ceil(this._physicalCount/this._itemsPerRow)},ready:function(){this.addEventListener("focus",this._didFocus.bind(this),true)},attached:function(){this.updateViewportBoundaries();if(this._physicalCount===0){this._debounceTemplate(this._render)}this.listen(this,"iron-resize","_resizeHandler")},detached:function(){this.unlisten(this,"iron-resize","_resizeHandler")},_setOverflow:function(scrollTarget){this.style.webkitOverflowScrolling=scrollTarget===this?"touch":"";this.style.overflow=scrollTarget===this?"auto":""},updateViewportBoundaries:function(){this._scrollerPaddingTop=this.scrollTarget===this?0:parseInt(window.getComputedStyle(this)["padding-top"],10);this._viewportHeight=this._scrollTargetHeight;if(this.grid){this._updateGridMetrics()}},_scrollHandler:function(){var scrollTop=Math.max(0,Math.min(this._maxScrollTop,this._scrollTop));var delta=scrollTop-this._scrollPosition;var tileHeight,tileTop,kth,recycledTileSet,scrollBottom,physicalBottom;var ratio=this._ratio;var recycledTiles=0;var hiddenContentSize=this._hiddenContentSize;var currentRatio=ratio;var movingUp=[];this._scrollPosition=scrollTop;this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;scrollBottom=this._scrollBottom;physicalBottom=this._physicalBottom;if(Math.abs(delta)>this._physicalSize){this._physicalTop+=delta;recycledTiles=Math.round(delta/this._physicalAverage)}else if(delta<0){var topSpace=scrollTop-this._physicalTop;var virtualStart=this._virtualStart;recycledTileSet=[];kth=this._physicalEnd;currentRatio=topSpace/hiddenContentSize;while(currentRatio<ratio&&recycledTiles<this._physicalCount&&virtualStart-recycledTiles>0&&physicalBottom-this._getPhysicalSizeIncrement(kth)>scrollBottom){tileHeight=this._getPhysicalSizeIncrement(kth);currentRatio+=tileHeight/hiddenContentSize;physicalBottom-=tileHeight;recycledTileSet.push(kth);recycledTiles++;kth=kth===0?this._physicalCount-1:kth-1}movingUp=recycledTileSet;recycledTiles=-recycledTiles}else if(delta>0){var bottomSpace=physicalBottom-scrollBottom;var virtualEnd=this._virtualEnd;var lastVirtualItemIndex=this._virtualCount-1;recycledTileSet=[];kth=this._physicalStart;currentRatio=bottomSpace/hiddenContentSize;while(currentRatio<ratio&&recycledTiles<this._physicalCount&&virtualEnd+recycledTiles<lastVirtualItemIndex&&this._physicalTop+this._getPhysicalSizeIncrement(kth)<scrollTop){tileHeight=this._getPhysicalSizeIncrement(kth);currentRatio+=tileHeight/hiddenContentSize;this._physicalTop+=tileHeight;recycledTileSet.push(kth);recycledTiles++;kth=(kth+1)%this._physicalCount}}if(recycledTiles===0){if(physicalBottom<scrollBottom||this._physicalTop>scrollTop){this._increasePoolIfNeeded()}}else{this._virtualStart=this._virtualStart+recycledTiles;this._physicalStart=this._physicalStart+recycledTiles;this._update(recycledTileSet,movingUp)}},_update:function(itemSet,movingUp){this._manageFocus();this._assignModels(itemSet);this._updateMetrics(itemSet);if(movingUp){while(movingUp.length){var idx=movingUp.pop();this._physicalTop-=this._getPhysicalSizeIncrement(idx)}}this._positionItems();this._updateScrollerSize();this._increasePoolIfNeeded()},_createPool:function(size){var physicalItems=new Array(size);this._ensureTemplatized();for(var i=0;i<size;i++){var inst=this.stamp(null);physicalItems[i]=inst.root.querySelector("*");Polymer.dom(this).appendChild(inst.root)}return physicalItems},_increasePoolIfNeeded:function(){if(this._viewportHeight===0){return false}var self=this;var isClientFull=this._physicalBottom>=this._scrollBottom&&this._physicalTop<=this._scrollPosition;if(this._physicalSize>=this._optPhysicalSize&&isClientFull){return false}var maxPoolSize=Math.round(this._physicalCount*.5);if(!isClientFull){this._debounceTemplate(this._increasePool.bind(this,maxPoolSize));return true}this._yield(function(){self._increasePool(Math.min(maxPoolSize,Math.max(1,Math.round(50/self._templateCost))))});return true},_yield:function(cb){var g=window;var handle=g.requestIdleCallback?g.requestIdleCallback(cb):g.setTimeout(cb,16);Polymer.dom.addDebouncer({complete:function(){g.cancelIdleCallback?g.cancelIdleCallback(handle):g.clearTimeout(handle);cb()}})},_increasePool:function(missingItems){var nextPhysicalCount=Math.min(this._physicalCount+missingItems,this._virtualCount-this._virtualStart,Math.max(this.maxPhysicalCount,DEFAULT_PHYSICAL_COUNT));var prevPhysicalCount=this._physicalCount;var delta=nextPhysicalCount-prevPhysicalCount;var ts=window.performance.now();if(delta<=0){return}[].push.apply(this._physicalItems,this._createPool(delta));[].push.apply(this._physicalSizes,new Array(delta));this._physicalCount=prevPhysicalCount+delta;if(this._physicalStart>this._physicalEnd&&this._isIndexRendered(this._focusedIndex)&&this._getPhysicalIndex(this._focusedIndex)<this._physicalEnd){this._physicalStart=this._physicalStart+delta}this._update();this._templateCost=(window.performance.now()-ts)/delta},_render:function(){if(this.isAttached&&this._isVisible){if(this._physicalCount===0){this._increasePool(DEFAULT_PHYSICAL_COUNT)}else{this._update()}}},_ensureTemplatized:function(){if(!this.ctor){var props={};props.__key__=true;props[this.as]=true;props[this.indexAs]=true;props[this.selectedAs]=true;props.tabIndex=true;this._instanceProps=props;this._userTemplate=Polymer.dom(this).querySelector("template");if(this._userTemplate){this.templatize(this._userTemplate)}else{console.warn("iron-list requires a template to be provided in light-dom")}}},_getStampedChildren:function(){return this._physicalItems},_forwardInstancePath:function(inst,path,value){if(path.indexOf(this.as+".")===0){this.notifyPath("items."+inst.__key__+"."+path.slice(this.as.length+1),value)}},_forwardParentProp:function(prop,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance[prop]=value},this)}},_forwardParentPath:function(path,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance.notifyPath(path,value,true)},this)}},_forwardItemPath:function(path,value){if(!this._physicalIndexForKey){return}var dot=path.indexOf(".");var key=path.substring(0,dot<0?path.length:dot);var idx=this._physicalIndexForKey[key];var offscreenItem=this._offscreenFocusedItem;var el=offscreenItem&&offscreenItem._templateInstance.__key__===key?offscreenItem:this._physicalItems[idx];if(!el||el._templateInstance.__key__!==key){return}if(dot>=0){path=this.as+"."+path.substring(dot+1);el._templateInstance.notifyPath(path,value,true)}else{var currentItem=el._templateInstance[this.as];if(Array.isArray(this.selectedItems)){for(var i=0;i<this.selectedItems.length;i++){if(this.selectedItems[i]===currentItem){this.set("selectedItems."+i,value);break}}}else if(this.selectedItem===currentItem){this.set("selectedItem",value)}el._templateInstance[this.as]=value}},_itemsChanged:function(change){if(change.path==="items"){this._virtualStart=0;this._physicalTop=0;this._virtualCount=this.items?this.items.length:0;this._collection=this.items?Polymer.Collection.get(this.items):null;this._physicalIndexForKey={};this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;this._physicalCount=this._physicalCount||0;this._physicalItems=this._physicalItems||[];this._physicalSizes=this._physicalSizes||[];this._physicalStart=0;this._resetScrollPosition(0);this._removeFocusedItem();this._debounceTemplate(this._render)}else if(change.path==="items.splices"){this._adjustVirtualIndex(change.value.indexSplices);this._virtualCount=this.items?this.items.length:0;this._debounceTemplate(this._render)}else{this._forwardItemPath(change.path.split(".").slice(1).join("."),change.value)}},_adjustVirtualIndex:function(splices){splices.forEach(function(splice){splice.removed.forEach(this._removeItem,this);if(splice.index<this._virtualStart){var delta=Math.max(splice.addedCount-splice.removed.length,splice.index-this._virtualStart);this._virtualStart=this._virtualStart+delta;if(this._focusedIndex>=0){this._focusedIndex=this._focusedIndex+delta}}},this)},_removeItem:function(item){this.$.selector.deselect(item);if(this._focusedItem&&this._focusedItem._templateInstance[this.as]===item){this._removeFocusedItem()}},_iterateItems:function(fn,itemSet){var pidx,vidx,rtn,i;if(arguments.length===2&&itemSet){for(i=0;i<itemSet.length;i++){pidx=itemSet[i];vidx=this._computeVidx(pidx);if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}else{pidx=this._physicalStart;vidx=this._virtualStart;for(;pidx<this._physicalCount;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}for(pidx=0;pidx<this._physicalStart;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}},_computeVidx:function(pidx){if(pidx>=this._physicalStart){return this._virtualStart+(pidx-this._physicalStart)}return this._virtualStart+(this._physicalCount-this._physicalStart)+pidx},_assignModels:function(itemSet){this._iterateItems(function(pidx,vidx){var el=this._physicalItems[pidx];var inst=el._templateInstance;var item=this.items&&this.items[vidx];if(item!=null){inst[this.as]=item;inst.__key__=this._collection.getKey(item);inst[this.selectedAs]=this.$.selector.isSelected(item);inst[this.indexAs]=vidx;inst.tabIndex=this._focusedIndex===vidx?0:-1;this._physicalIndexForKey[inst.__key__]=pidx;el.removeAttribute("hidden")}else{inst.__key__=null;el.setAttribute("hidden","")}},itemSet)},_updateMetrics:function(itemSet){Polymer.dom.flush();var newPhysicalSize=0;var oldPhysicalSize=0;var prevAvgCount=this._physicalAverageCount;var prevPhysicalAvg=this._physicalAverage;this._iterateItems(function(pidx,vidx){oldPhysicalSize+=this._physicalSizes[pidx]||0;this._physicalSizes[pidx]=this._physicalItems[pidx].offsetHeight;newPhysicalSize+=this._physicalSizes[pidx];this._physicalAverageCount+=this._physicalSizes[pidx]?1:0},itemSet);this._viewportHeight=this._scrollTargetHeight;if(this.grid){this._updateGridMetrics();this._physicalSize=Math.ceil(this._physicalCount/this._itemsPerRow)*this._rowHeight}else{this._physicalSize=this._physicalSize+newPhysicalSize-oldPhysicalSize}if(this._physicalAverageCount!==prevAvgCount){this._physicalAverage=Math.round((prevPhysicalAvg*prevAvgCount+newPhysicalSize)/this._physicalAverageCount)}},_updateGridMetrics:function(){this._viewportWidth=this.$.items.offsetWidth;this._itemWidth=this._physicalCount>0?this._physicalItems[0].getBoundingClientRect().width:DEFAULT_GRID_SIZE;this._rowHeight=this._physicalCount>0?this._physicalItems[0].offsetHeight:DEFAULT_GRID_SIZE;this._itemsPerRow=this._itemWidth?Math.floor(this._viewportWidth/this._itemWidth):this._itemsPerRow},_positionItems:function(){this._adjustScrollPosition();var y=this._physicalTop;if(this.grid){var totalItemWidth=this._itemsPerRow*this._itemWidth;var rowOffset=(this._viewportWidth-totalItemWidth)/2;this._iterateItems(function(pidx,vidx){var modulus=vidx%this._itemsPerRow;var x=Math.floor(modulus*this._itemWidth+rowOffset);this.translate3d(x+"px",y+"px",0,this._physicalItems[pidx]);if(this._shouldRenderNextRow(vidx)){y+=this._rowHeight}})}else{this._iterateItems(function(pidx,vidx){this.translate3d(0,y+"px",0,this._physicalItems[pidx]);y+=this._physicalSizes[pidx]})}},_getPhysicalSizeIncrement:function(pidx){if(!this.grid){return this._physicalSizes[pidx]}if(this._computeVidx(pidx)%this._itemsPerRow!==this._itemsPerRow-1){return 0}return this._rowHeight},_shouldRenderNextRow:function(vidx){return vidx%this._itemsPerRow===this._itemsPerRow-1},_adjustScrollPosition:function(){var deltaHeight=this._virtualStart===0?this._physicalTop:Math.min(this._scrollPosition+this._physicalTop,0);if(deltaHeight){this._physicalTop=this._physicalTop-deltaHeight;if(!IOS_TOUCH_SCROLLING&&this._physicalTop!==0){this._resetScrollPosition(this._scrollTop-deltaHeight)}}},_resetScrollPosition:function(pos){if(this.scrollTarget){this._scrollTop=pos;this._scrollPosition=this._scrollTop}},_updateScrollerSize:function(forceUpdate){if(this.grid){this._estScrollHeight=this._virtualRowCount*this._rowHeight}else{this._estScrollHeight=this._physicalBottom+Math.max(this._virtualCount-this._physicalCount-this._virtualStart,0)*this._physicalAverage}forceUpdate=forceUpdate||this._scrollHeight===0;forceUpdate=forceUpdate||this._scrollPosition>=this._estScrollHeight-this._physicalSize;forceUpdate=forceUpdate||this.grid&&this.$.items.style.height<this._estScrollHeight;if(forceUpdate||Math.abs(this._estScrollHeight-this._scrollHeight)>=this._optPhysicalSize){this.$.items.style.height=this._estScrollHeight+"px";this._scrollHeight=this._estScrollHeight}},scrollToItem:function(item){return this.scrollToIndex(this.items.indexOf(item))},scrollToIndex:function(idx){if(typeof idx!=="number"||idx<0||idx>this.items.length-1){return}Polymer.dom.flush();if(this._physicalCount===0){return}idx=Math.min(Math.max(idx,0),this._virtualCount-1);if(!this._isIndexRendered(idx)||idx>=this._maxVirtualStart){this._virtualStart=this.grid?idx-this._itemsPerRow*2:idx-1}this._manageFocus();this._assignModels();this._updateMetrics();this._physicalTop=Math.floor(this._virtualStart/this._itemsPerRow)*this._physicalAverage;var currentTopItem=this._physicalStart;var currentVirtualItem=this._virtualStart;var targetOffsetTop=0;var hiddenContentSize=this._hiddenContentSize;while(currentVirtualItem<idx&&targetOffsetTop<=hiddenContentSize){targetOffsetTop=targetOffsetTop+this._getPhysicalSizeIncrement(currentTopItem);currentTopItem=(currentTopItem+1)%this._physicalCount;currentVirtualItem++}this._updateScrollerSize(true);this._positionItems();this._resetScrollPosition(this._physicalTop+this._scrollerPaddingTop+targetOffsetTop);this._increasePoolIfNeeded();this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null},_resetAverage:function(){this._physicalAverage=0;this._physicalAverageCount=0},_resizeHandler:function(){if(IOS&&Math.abs(this._viewportHeight-this._scrollTargetHeight)<100){return}Polymer.dom.addDebouncer(this.debounce("_debounceTemplate",function(){this.updateViewportBoundaries();this._render();if(this._physicalCount>0&&this._isVisible){this._resetAverage();this.scrollToIndex(this.firstVisibleIndex)}}.bind(this),1))},_getModelFromItem:function(item){var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){return this._physicalItems[pidx]._templateInstance}return null},_getNormalizedItem:function(item){if(this._collection.getKey(item)===undefined){if(typeof item==="number"){item=this.items[item];if(!item){throw new RangeError("<item> not found")}return item}throw new TypeError("<item> should be a valid item")}return item},selectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(!this.multiSelection&&this.selectedItem){this.deselectItem(this.selectedItem)}if(model){model[this.selectedAs]=true}this.$.selector.select(item);this.updateSizeForItem(item)},deselectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}this.$.selector.deselect(item);this.updateSizeForItem(item)},toggleSelectionForItem:function(item){item=this._getNormalizedItem(item);if(this.$.selector.isSelected(item)){this.deselectItem(item)}else{this.selectItem(item)}},clearSelection:function(){function unselect(item){var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}}if(Array.isArray(this.selectedItems)){this.selectedItems.forEach(unselect,this)}else if(this.selectedItem){unselect.call(this,this.selectedItem)}this.$.selector.clearSelection()},_selectionEnabledChanged:function(selectionEnabled){var handler=selectionEnabled?this.listen:this.unlisten;handler.call(this,this,"tap","_selectionHandler")},_selectionHandler:function(e){var model=this.modelForElement(e.target);if(!model){return}var modelTabIndex,activeElTabIndex;var target=Polymer.dom(e).path[0];var activeEl=Polymer.dom(this.domHost?this.domHost.root:document).activeElement;var physicalItem=this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];if(target.localName==="input"||target.localName==="button"||target.localName==="select"){return}modelTabIndex=model.tabIndex;model.tabIndex=SECRET_TABINDEX;activeElTabIndex=activeEl?activeEl.tabIndex:-1;model.tabIndex=modelTabIndex;if(activeEl&&physicalItem!==activeEl&&physicalItem.contains(activeEl)&&activeElTabIndex!==SECRET_TABINDEX){return}this.toggleSelectionForItem(model[this.as])},_multiSelectionChanged:function(multiSelection){this.clearSelection();this.$.selector.multi=multiSelection},updateSizeForItem:function(item){item=this._getNormalizedItem(item);var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){this._updateMetrics([pidx]);this._positionItems()}},_manageFocus:function(){var fidx=this._focusedIndex;if(fidx>=0&&fidx<this._virtualCount){if(this._isIndexRendered(fidx)){this._restoreFocusedItem()}else{this._createFocusBackfillItem()}}else if(this._virtualCount>0&&this._physicalCount>0){this._focusedIndex=this._virtualStart;this._focusedItem=this._physicalItems[this._physicalStart]}},_isIndexRendered:function(idx){return idx>=this._virtualStart&&idx<=this._virtualEnd},_isIndexVisible:function(idx){return idx>=this.firstVisibleIndex&&idx<=this.lastVisibleIndex},_getPhysicalIndex:function(idx){return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))]},_focusPhysicalItem:function(idx){if(idx<0||idx>=this._virtualCount){return}this._restoreFocusedItem();if(!this._isIndexRendered(idx)){this.scrollToIndex(idx)}var physicalItem=this._physicalItems[this._getPhysicalIndex(idx)];var model=physicalItem._templateInstance;var focusable;model.tabIndex=SECRET_TABINDEX;if(physicalItem.tabIndex===SECRET_TABINDEX){focusable=physicalItem}if(!focusable){focusable=Polymer.dom(physicalItem).querySelector('[tabindex="'+SECRET_TABINDEX+'"]')}model.tabIndex=0;this._focusedIndex=idx;focusable&&focusable.focus()},_removeFocusedItem:function(){if(this._offscreenFocusedItem){Polymer.dom(this).removeChild(this._offscreenFocusedItem)}this._offscreenFocusedItem=null;this._focusBackfillItem=null;this._focusedItem=null;this._focusedIndex=-1},_createFocusBackfillItem:function(){var pidx,fidx=this._focusedIndex;if(this._offscreenFocusedItem||fidx<0){return}if(!this._focusBackfillItem){var stampedTemplate=this.stamp(null);this._focusBackfillItem=stampedTemplate.root.querySelector("*");Polymer.dom(this).appendChild(stampedTemplate.root)}pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._offscreenFocusedItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._focusBackfillItem;this.translate3d(0,HIDDEN_Y,0,this._offscreenFocusedItem)}},_restoreFocusedItem:function(){var pidx,fidx=this._focusedIndex;if(!this._offscreenFocusedItem||this._focusedIndex<0){return}this._assignModels();pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._focusBackfillItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._offscreenFocusedItem;this._offscreenFocusedItem=null;this.translate3d(0,HIDDEN_Y,0,this._focusBackfillItem)}},_didFocus:function(e){var targetModel=this.modelForElement(e.target);var focusedModel=this._focusedItem?this._focusedItem._templateInstance:null;var hasOffscreenFocusedItem=this._offscreenFocusedItem!==null;var fidx=this._focusedIndex;if(!targetModel||!focusedModel){return}if(focusedModel===targetModel){if(!this._isIndexVisible(fidx)){this.scrollToIndex(fidx)}}else{this._restoreFocusedItem();focusedModel.tabIndex=-1;targetModel.tabIndex=0;fidx=targetModel[this.indexAs];this._focusedIndex=fidx;this._focusedItem=this._physicalItems[this._getPhysicalIndex(fidx)];if(hasOffscreenFocusedItem&&!this._offscreenFocusedItem){this._update()}}},_didMoveUp:function(){this._focusPhysicalItem(this._focusedIndex-1)},_didMoveDown:function(e){e.detail.keyboardEvent.preventDefault();this._focusPhysicalItem(this._focusedIndex+1)},_didEnter:function(e){this._focusPhysicalItem(this._focusedIndex);this._selectionHandler(e.detail.keyboardEvent)}})})();Polymer({is:"iron-scroll-threshold",properties:{upperThreshold:{type:Number,value:100},lowerThreshold:{type:Number,value:100},upperTriggered:{type:Boolean,value:false,notify:true,readOnly:true},lowerTriggered:{type:Boolean,value:false,notify:true,readOnly:true},horizontal:{type:Boolean,value:false}},behaviors:[Polymer.IronScrollTargetBehavior],observers:["_setOverflow(scrollTarget)","_initCheck(horizontal, isAttached)"],get _defaultScrollTarget(){return this},_setOverflow:function(scrollTarget){this.style.overflow=scrollTarget===this?"auto":""},_scrollHandler:function(){var THROTTLE_THRESHOLD=200;if(!this.isDebouncerActive("_checkTheshold")){this.debounce("_checkTheshold",function(){this.checkScrollThesholds()},THROTTLE_THRESHOLD)}},_initCheck:function(horizontal,isAttached){if(isAttached){this.debounce("_init",function(){this.clearTriggers();this.checkScrollThesholds()})}},checkScrollThesholds:function(){if(!this.scrollTarget||this.lowerTriggered&&this.upperTriggered){return}var upperScrollValue=this.horizontal?this._scrollLeft:this._scrollTop;var lowerScrollValue=this.horizontal?this.scrollTarget.scrollWidth-this._scrollTargetWidth-this._scrollLeft:this.scrollTarget.scrollHeight-this._scrollTargetHeight-this._scrollTop;if(upperScrollValue<=this.upperThreshold&&!this.upperTriggered){this._setUpperTriggered(true);this.fire("upper-threshold")}if(lowerScrollValue<=this.lowerThreshold&&!this.lowerTriggered){this._setLowerTriggered(true);this.fire("lower-threshold")}},clearTriggers:function(){this._setUpperTriggered(false);this._setLowerTriggered(false)}});
 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-var EventTrackerEntry;
-
-function EventTracker() {
-  this.listeners_ = [];
-}
-
-EventTracker.prototype = {
-  add: function(target, eventType, listener, opt_capture) {
-    var capture = !!opt_capture;
-    var h = {
-      target: target,
-      eventType: eventType,
-      listener: listener,
-      capture: capture
-    };
-    this.listeners_.push(h);
-    target.addEventListener(eventType, listener, capture);
-  },
-  remove: function(target, eventType) {
-    this.listeners_ = this.listeners_.filter(function(h) {
-      if (h.target == target && (!eventType || h.eventType == eventType)) {
-        EventTracker.removeEventListener_(h);
-        return false;
-      }
-      return true;
-    });
-  },
-  removeAll: function() {
-    this.listeners_.forEach(EventTracker.removeEventListener_);
-    this.listeners_ = [];
-  }
-};
-
-EventTracker.removeEventListener_ = function(h) {
-  h.target.removeEventListener(h.eventType, h.listener, h.capture);
-};
-
+var EventTrackerEntry;function EventTracker(){this.listeners_=[]}EventTracker.prototype={add:function(target,eventType,listener,opt_capture){var capture=!!opt_capture;var h={target:target,eventType:eventType,listener:listener,capture:capture};this.listeners_.push(h);target.addEventListener(eventType,listener,capture)},remove:function(target,eventType){this.listeners_=this.listeners_.filter(function(h){if(h.target==target&&(!eventType||h.eventType==eventType)){EventTracker.removeEventListener_(h);return false}return true})},removeAll:function(){this.listeners_.forEach(EventTracker.removeEventListener_);this.listeners_=[]}};EventTracker.removeEventListener_=function(h){h.target.removeEventListener(h.eventType,h.listener,h.capture)};
 // 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.
-cr.define('cr.ui', function() {
-  function FocusRow(root, boundary, opt_delegate) {
-    this.root = root;
-    this.boundary_ = boundary || document.documentElement;
-    this.delegate = opt_delegate;
-    this.eventTracker = new EventTracker();
-  }
-  FocusRow.Delegate = function() {};
-  FocusRow.Delegate.prototype = {
-    onKeydown: assertNotReached,
-    onFocus: assertNotReached
-  };
-  FocusRow.ACTIVE_CLASS = 'focus-row-active';
-  FocusRow.isFocusable = function(element) {
-    if (!element || element.disabled) return false;
-    function isVisible(element) {
-      assertInstanceof(element, Element);
-      var style = window.getComputedStyle(element);
-      if (style.visibility == 'hidden' || style.display == 'none') return false;
-      var parent = element.parentNode;
-      if (!parent) return false;
-      if (parent == element.ownerDocument || parent instanceof DocumentFragment) return true;
-      return isVisible(parent);
-    }
-    return isVisible(element);
-  };
-  FocusRow.prototype = {
-    addItem: function(type, query) {
-      assert(type);
-      var element = this.root.querySelector(query);
-      if (!element) return false;
-      element.setAttribute('focus-type', type);
-      element.tabIndex = this.isActive() ? 0 : -1;
-      this.eventTracker.add(element, 'blur', this.onBlur_.bind(this));
-      this.eventTracker.add(element, 'focus', this.onFocus_.bind(this));
-      this.eventTracker.add(element, 'keydown', this.onKeydown_.bind(this));
-      this.eventTracker.add(element, 'mousedown', this.onMousedown_.bind(this));
-      return true;
-    },
-    destroy: function() {
-      this.eventTracker.removeAll();
-    },
-    getCustomEquivalent: function(sampleElement) {
-      return assert(this.getFirstFocusable());
-    },
-    getElements: function() {
-      var elements = this.root.querySelectorAll('[focus-type]');
-      return Array.prototype.slice.call(elements);
-    },
-    getEquivalentElement: function(sampleElement) {
-      if (this.getFocusableElements().indexOf(sampleElement) >= 0) return sampleElement;
-      var sampleFocusType = this.getTypeForElement(sampleElement);
-      if (sampleFocusType) {
-        var sameType = this.getFirstFocusable(sampleFocusType);
-        if (sameType) return sameType;
-      }
-      return this.getCustomEquivalent(sampleElement);
-    },
-    getFirstFocusable: function(opt_type) {
-      var filter = opt_type ? '="' + opt_type + '"' : '';
-      var elements = this.root.querySelectorAll('[focus-type' + filter + ']');
-      for (var i = 0; i < elements.length; ++i) {
-        if (cr.ui.FocusRow.isFocusable(elements[i])) return elements[i];
-      }
-      return null;
-    },
-    getFocusableElements: function() {
-      return this.getElements().filter(cr.ui.FocusRow.isFocusable);
-    },
-    getTypeForElement: function(element) {
-      return element.getAttribute('focus-type') || '';
-    },
-    isActive: function() {
-      return this.root.classList.contains(FocusRow.ACTIVE_CLASS);
-    },
-    makeActive: function(active) {
-      if (active == this.isActive()) return;
-      this.getElements().forEach(function(element) {
-        element.tabIndex = active ? 0 : -1;
-      });
-      this.root.classList.toggle(FocusRow.ACTIVE_CLASS, active);
-    },
-    onBlur_: function(e) {
-      if (!this.boundary_.contains(e.relatedTarget)) return;
-      var currentTarget = e.currentTarget;
-      if (this.getFocusableElements().indexOf(currentTarget) >= 0) this.makeActive(false);
-    },
-    onFocus_: function(e) {
-      if (this.delegate) this.delegate.onFocus(this, e);
-    },
-    onMousedown_: function(e) {
-      if (e.button) return;
-      if (!e.currentTarget.disabled) e.currentTarget.tabIndex = 0;
-    },
-    onKeydown_: function(e) {
-      var elements = this.getFocusableElements();
-      var currentElement = e.currentTarget;
-      var elementIndex = elements.indexOf(currentElement);
-      assert(elementIndex >= 0);
-      if (this.delegate && this.delegate.onKeydown(this, e)) return;
-      if (e.altKey || e.ctrlKey || e.metaKey || e.shiftKey) return;
-      var index = -1;
-      if (e.key == 'ArrowLeft') index = elementIndex + (isRTL() ? 1 : -1); else if (e.key == 'ArrowRight') index = elementIndex + (isRTL() ? -1 : 1); else if (e.key == 'Home') index = 0; else if (e.key == 'End') index = elements.length - 1;
-      var elementToFocus = elements[index];
-      if (elementToFocus) {
-        this.getEquivalentElement(elementToFocus).focus();
-        e.preventDefault();
-      }
-    }
-  };
-  return {
-    FocusRow: FocusRow
-  };
-});
-
+cr.define("cr.ui",function(){function FocusRow(root,boundary,opt_delegate){this.root=root;this.boundary_=boundary||document.documentElement;this.delegate=opt_delegate;this.eventTracker=new EventTracker}FocusRow.Delegate=function(){};FocusRow.Delegate.prototype={onKeydown:assertNotReached,onFocus:assertNotReached};FocusRow.ACTIVE_CLASS="focus-row-active";FocusRow.isFocusable=function(element){if(!element||element.disabled)return false;function isVisible(element){assertInstanceof(element,Element);var style=window.getComputedStyle(element);if(style.visibility=="hidden"||style.display=="none")return false;var parent=element.parentNode;if(!parent)return false;if(parent==element.ownerDocument||parent instanceof DocumentFragment)return true;return isVisible(parent)}return isVisible(element)};FocusRow.prototype={addItem:function(type,query){assert(type);var element=this.root.querySelector(query);if(!element)return false;element.setAttribute("focus-type",type);element.tabIndex=this.isActive()?0:-1;this.eventTracker.add(element,"blur",this.onBlur_.bind(this));this.eventTracker.add(element,"focus",this.onFocus_.bind(this));this.eventTracker.add(element,"keydown",this.onKeydown_.bind(this));this.eventTracker.add(element,"mousedown",this.onMousedown_.bind(this));return true},destroy:function(){this.eventTracker.removeAll()},getCustomEquivalent:function(sampleElement){return assert(this.getFirstFocusable())},getElements:function(){var elements=this.root.querySelectorAll("[focus-type]");return Array.prototype.slice.call(elements)},getEquivalentElement:function(sampleElement){if(this.getFocusableElements().indexOf(sampleElement)>=0)return sampleElement;var sampleFocusType=this.getTypeForElement(sampleElement);if(sampleFocusType){var sameType=this.getFirstFocusable(sampleFocusType);if(sameType)return sameType}return this.getCustomEquivalent(sampleElement)},getFirstFocusable:function(opt_type){var filter=opt_type?'="'+opt_type+'"':"";var elements=this.root.querySelectorAll("[focus-type"+filter+"]");for(var i=0;i<elements.length;++i){if(cr.ui.FocusRow.isFocusable(elements[i]))return elements[i]}return null},getFocusableElements:function(){return this.getElements().filter(cr.ui.FocusRow.isFocusable)},getTypeForElement:function(element){return element.getAttribute("focus-type")||""},isActive:function(){return this.root.classList.contains(FocusRow.ACTIVE_CLASS)},makeActive:function(active){if(active==this.isActive())return;this.getElements().forEach(function(element){element.tabIndex=active?0:-1});this.root.classList.toggle(FocusRow.ACTIVE_CLASS,active)},onBlur_:function(e){if(!this.boundary_.contains(e.relatedTarget))return;var currentTarget=e.currentTarget;if(this.getFocusableElements().indexOf(currentTarget)>=0)this.makeActive(false)},onFocus_:function(e){if(this.delegate)this.delegate.onFocus(this,e)},onMousedown_:function(e){if(e.button)return;if(!e.currentTarget.disabled)e.currentTarget.tabIndex=0},onKeydown_:function(e){var elements=this.getFocusableElements();var currentElement=e.currentTarget;var elementIndex=elements.indexOf(currentElement);assert(elementIndex>=0);if(this.delegate&&this.delegate.onKeydown(this,e))return;if(e.altKey||e.ctrlKey||e.metaKey||e.shiftKey)return;var index=-1;if(e.key=="ArrowLeft")index=elementIndex+(isRTL()?1:-1);else if(e.key=="ArrowRight")index=elementIndex+(isRTL()?-1:1);else if(e.key=="Home")index=0;else if(e.key=="End")index=elements.length-1;var elementToFocus=elements[index];if(elementToFocus){this.getEquivalentElement(elementToFocus).focus();e.preventDefault()}}};return{FocusRow:FocusRow}});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-cr.define('cr.icon', function() {
-  function getSupportedScaleFactors() {
-    var supportedScaleFactors = [];
-    if (!cr.isIOS) {
-      supportedScaleFactors.push(1);
-    }
-    if (cr.isMac || cr.isChromeOS || cr.isWindows || cr.isLinux) {
-      supportedScaleFactors.push(2);
-    } else {
-      supportedScaleFactors.push(window.devicePixelRatio);
-    }
-    return supportedScaleFactors;
-  }
-  function getImageSet(path) {
-    var supportedScaleFactors = getSupportedScaleFactors();
-    var replaceStartIndex = path.indexOf('scalefactor');
-    if (replaceStartIndex < 0) return url(path);
-    var s = '';
-    for (var i = 0; i < supportedScaleFactors.length; ++i) {
-      var scaleFactor = supportedScaleFactors[i];
-      var pathWithScaleFactor = path.substr(0, replaceStartIndex) + scaleFactor + path.substr(replaceStartIndex + 'scalefactor'.length);
-      s += url(pathWithScaleFactor) + ' ' + scaleFactor + 'x';
-      if (i != supportedScaleFactors.length - 1) s += ', ';
-    }
-    return '-webkit-image-set(' + s + ')';
-  }
-  function getImage(path) {
-    var chromeThemePath = 'chrome://theme';
-    var isChromeThemeUrl = path.slice(0, chromeThemePath.length) == chromeThemePath;
-    return isChromeThemeUrl ? getImageSet(path + '@scalefactorx') : url(path);
-  }
-  var FAVICON_URL_REGEX = /\.ico$/i;
-  function getFavicon(url, opt_size, opt_type) {
-    var size = opt_size || 16;
-    var type = opt_type || 'favicon';
-    return getImageSet('chrome://' + type + '/size/' + size + '@scalefactorx/' + (FAVICON_URL_REGEX.test(url) ? 'iconurl/' : '') + url);
-  }
-  return {
-    getImage: getImage,
-    getFavicon: getFavicon
-  };
-});
-
+cr.define("cr.icon",function(){function getSupportedScaleFactors(){var supportedScaleFactors=[];if(!cr.isIOS){supportedScaleFactors.push(1)}if(cr.isMac||cr.isChromeOS||cr.isWindows||cr.isLinux){supportedScaleFactors.push(2)}else{supportedScaleFactors.push(window.devicePixelRatio)}return supportedScaleFactors}function getImageSet(path){var supportedScaleFactors=getSupportedScaleFactors();var replaceStartIndex=path.indexOf("scalefactor");if(replaceStartIndex<0)return url(path);var s="";for(var i=0;i<supportedScaleFactors.length;++i){var scaleFactor=supportedScaleFactors[i];var pathWithScaleFactor=path.substr(0,replaceStartIndex)+scaleFactor+path.substr(replaceStartIndex+"scalefactor".length);s+=url(pathWithScaleFactor)+" "+scaleFactor+"x";if(i!=supportedScaleFactors.length-1)s+=", "}return"-webkit-image-set("+s+")"}function getImage(path){var chromeThemePath="chrome://theme";var isChromeThemeUrl=path.slice(0,chromeThemePath.length)==chromeThemePath;return isChromeThemeUrl?getImageSet(path+"@scalefactorx"):url(path)}var FAVICON_URL_REGEX=/\.ico$/i;function getFavicon(url,opt_size,opt_type){var size=opt_size||16;var type=opt_type||"favicon";return getImageSet("chrome://"+type+"/size/"+size+"@scalefactorx/"+(FAVICON_URL_REGEX.test(url)?"iconurl/":"")+url)}return{getImage:getImage,getFavicon:getFavicon}});
 // Copyright 2016 The Chromium 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({
-  is: 'history-searched-label',
-  properties: {
-    title: String,
-    searchTerm: String
-  },
-  observers: [ 'setSearchedTextToBold_(title, searchTerm)' ],
-  setSearchedTextToBold_: function() {
-    var i = 0;
-    var titleText = this.title;
-    if (this.searchTerm == '' || this.searchTerm == null) {
-      this.textContent = titleText;
-      return;
-    }
-    var re = new RegExp(quoteString(this.searchTerm), 'gim');
-    var match;
-    this.textContent = '';
-    while (match = re.exec(titleText)) {
-      if (match.index > i) this.appendChild(document.createTextNode(titleText.slice(i, match.index)));
-      i = re.lastIndex;
-      var b = document.createElement('b');
-      b.textContent = titleText.substring(match.index, i);
-      this.appendChild(b);
-    }
-    if (i < titleText.length) this.appendChild(document.createTextNode(titleText.slice(i)));
-  }
-});
-
+Polymer({is:"history-searched-label",properties:{title:String,searchTerm:String},observers:["setSearchedTextToBold_(title, searchTerm)"],setSearchedTextToBold_:function(){var i=0;var titleText=this.title;if(this.searchTerm==""||this.searchTerm==null){this.textContent=titleText;return}var re=new RegExp(quoteString(this.searchTerm),"gim");var match;this.textContent="";while(match=re.exec(titleText)){if(match.index>i)this.appendChild(document.createTextNode(titleText.slice(i,match.index)));i=re.lastIndex;var b=document.createElement("b");b.textContent=titleText.substring(match.index,i);this.appendChild(b)}if(i<titleText.length)this.appendChild(document.createTextNode(titleText.slice(i)))}});
 // 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 HistoryFocusRow(root, boundary, delegate) {
-  cr.ui.FocusRow.call(this, root, boundary, delegate);
-  this.addItems();
-}
-
-HistoryFocusRow.prototype = {
-  __proto__: cr.ui.FocusRow.prototype,
-  getCustomEquivalent: function(sampleElement) {
-    var equivalent;
-    if (this.getTypeForElement(sampleElement) == 'star') equivalent = this.getFirstFocusable('title');
-    return equivalent || cr.ui.FocusRow.prototype.getCustomEquivalent.call(this, sampleElement);
-  },
-  addItems: function() {
-    this.destroy();
-    assert(this.addItem('checkbox', '#checkbox'));
-    assert(this.addItem('title', '#title'));
-    assert(this.addItem('menu-button', '#menu-button'));
-    this.addItem('star', '#bookmark-star');
-  }
-};
-
-cr.define('md_history', function() {
-  function FocusRowDelegate(historyItemElement) {
-    this.historyItemElement = historyItemElement;
-  }
-  FocusRowDelegate.prototype = {
-    onFocus: function(row, e) {
-      this.historyItemElement.lastFocused = e.path[0];
-    },
-    onKeydown: function(row, e) {
-      if (e.key == 'Enter') e.stopPropagation();
-      return false;
-    }
-  };
-  var HistoryItem = Polymer({
-    is: 'history-item',
-    properties: {
-      item: {
-        type: Object,
-        observer: 'showIcon_'
-      },
-      searchTerm: {
-        type: String
-      },
-      selected: {
-        type: Boolean,
-        reflectToAttribute: true
-      },
-      isCardStart: {
-        type: Boolean,
-        reflectToAttribute: true
-      },
-      isCardEnd: {
-        type: Boolean,
-        reflectToAttribute: true
-      },
-      embedded: {
-        type: Boolean,
-        reflectToAttribute: true
-      },
-      hasTimeGap: {
-        type: Boolean
-      },
-      numberOfItems: {
-        type: Number
-      },
-      path: String,
-      index: Number,
-      lastFocused: {
-        type: Object,
-        notify: true
-      },
-      ironListTabIndex: {
-        type: Number,
-        observer: 'ironListTabIndexChanged_'
-      }
-    },
-    row_: null,
-    attached: function() {
-      Polymer.RenderStatus.afterNextRender(this, function() {
-        this.row_ = new HistoryFocusRow(this.$['sizing-container'], null, new FocusRowDelegate(this));
-        this.row_.makeActive(this.ironListTabIndex == 0);
-        this.listen(this, 'focus', 'onFocus_');
-        this.listen(this, 'dom-change', 'onDomChange_');
-      });
-    },
-    detached: function() {
-      this.unlisten(this, 'focus', 'onFocus_');
-      this.unlisten(this, 'dom-change', 'onDomChange_');
-      if (this.row_) this.row_.destroy();
-    },
-    onFocus_: function() {
-      if (this.lastFocused) this.row_.getEquivalentElement(this.lastFocused).focus(); else this.row_.getFirstFocusable().focus();
-      this.tabIndex = -1;
-    },
-    ironListTabIndexChanged_: function() {
-      if (this.row_) this.row_.makeActive(this.ironListTabIndex == 0);
-    },
-    onDomChange_: function() {
-      if (this.row_) this.row_.addItems();
-    },
-    onCheckboxSelected_: function(e) {
-      this.fire('history-checkbox-select', {
-        element: this,
-        shiftKey: e.shiftKey
-      });
-      e.preventDefault();
-    },
-    onCheckboxMousedown_: function(e) {
-      if (e.shiftKey) e.preventDefault();
-    },
-    getEntrySummary_: function() {
-      var item = this.item;
-      return loadTimeData.getStringF('entrySummary', item.dateTimeOfDay, item.starred ? loadTimeData.getString('bookmarked') : '', item.title, item.domain);
-    },
-    getAriaChecked_: function(selected) {
-      return selected ? 'true' : 'false';
-    },
-    onRemoveBookmarkTap_: function() {
-      if (!this.item.starred) return;
-      if (this.$$('#bookmark-star') == this.root.activeElement) this.$['menu-button'].focus();
-      var browserService = md_history.BrowserService.getInstance();
-      browserService.removeBookmark(this.item.url);
-      browserService.recordAction('BookmarkStarClicked');
-      this.fire('remove-bookmark-stars', this.item.url);
-    },
-    onMenuButtonTap_: function(e) {
-      this.fire('toggle-menu', {
-        target: Polymer.dom(e).localTarget,
-        index: this.index,
-        item: this.item,
-        path: this.path
-      });
-      e.stopPropagation();
-    },
-    onLinkClick_: function() {
-      var browserService = md_history.BrowserService.getInstance();
-      browserService.recordAction('EntryLinkClick');
-      if (this.searchTerm) browserService.recordAction('SearchResultClick');
-      if (this.index == undefined) return;
-      browserService.recordHistogram('HistoryPage.ClickPosition', this.index, UMA_MAX_BUCKET_VALUE);
-      if (this.index <= UMA_MAX_SUBSET_BUCKET_VALUE) {
-        browserService.recordHistogram('HistoryPage.ClickPositionSubset', this.index, UMA_MAX_SUBSET_BUCKET_VALUE);
-      }
-    },
-    onLinkRightClick_: function() {
-      md_history.BrowserService.getInstance().recordAction('EntryLinkRightClick');
-    },
-    showIcon_: function() {
-      this.$.icon.style.backgroundImage = cr.icon.getFavicon(this.item.url);
-    },
-    selectionNotAllowed_: function() {
-      return !loadTimeData.getBoolean('allowDeletingHistory');
-    },
-    cardTitle_: function(numberOfItems, historyDate, search) {
-      if (!search) return this.item.dateRelativeDay;
-      var resultId = numberOfItems == 1 ? 'searchResult' : 'searchResults';
-      return loadTimeData.getStringF('foundSearchResults', numberOfItems, loadTimeData.getString(resultId), search);
-    }
-  });
-  HistoryItem.needsTimeGap = function(visits, currentIndex, searchedTerm) {
-    if (currentIndex >= visits.length - 1 || visits.length == 0) return false;
-    var currentItem = visits[currentIndex];
-    var nextItem = visits[currentIndex + 1];
-    if (searchedTerm) return currentItem.dateShort != nextItem.dateShort;
-    return currentItem.time - nextItem.time > BROWSING_GAP_TIME && currentItem.dateRelativeDay == nextItem.dateRelativeDay;
-  };
-  return {
-    HistoryItem: HistoryItem
-  };
-});
-
+function HistoryFocusRow(root,boundary,delegate){cr.ui.FocusRow.call(this,root,boundary,delegate);this.addItems()}HistoryFocusRow.prototype={__proto__:cr.ui.FocusRow.prototype,getCustomEquivalent:function(sampleElement){var equivalent;if(this.getTypeForElement(sampleElement)=="star")equivalent=this.getFirstFocusable("title");return equivalent||cr.ui.FocusRow.prototype.getCustomEquivalent.call(this,sampleElement)},addItems:function(){this.destroy();assert(this.addItem("checkbox","#checkbox"));assert(this.addItem("title","#title"));assert(this.addItem("menu-button","#menu-button"));this.addItem("star","#bookmark-star")}};cr.define("md_history",function(){function FocusRowDelegate(historyItemElement){this.historyItemElement=historyItemElement}FocusRowDelegate.prototype={onFocus:function(row,e){this.historyItemElement.lastFocused=e.path[0]},onKeydown:function(row,e){if(e.key=="Enter")e.stopPropagation();return false}};var HistoryItem=Polymer({is:"history-item",properties:{item:{type:Object,observer:"showIcon_"},searchTerm:{type:String},selected:{type:Boolean,reflectToAttribute:true},isCardStart:{type:Boolean,reflectToAttribute:true},isCardEnd:{type:Boolean,reflectToAttribute:true},embedded:{type:Boolean,reflectToAttribute:true},hasTimeGap:{type:Boolean},numberOfItems:{type:Number},path:String,index:Number,lastFocused:{type:Object,notify:true},ironListTabIndex:{type:Number,observer:"ironListTabIndexChanged_"}},row_:null,attached:function(){Polymer.RenderStatus.afterNextRender(this,function(){this.row_=new HistoryFocusRow(this.$["sizing-container"],null,new FocusRowDelegate(this));this.row_.makeActive(this.ironListTabIndex==0);this.listen(this,"focus","onFocus_");this.listen(this,"dom-change","onDomChange_")})},detached:function(){this.unlisten(this,"focus","onFocus_");this.unlisten(this,"dom-change","onDomChange_");if(this.row_)this.row_.destroy()},onFocus_:function(){if(this.lastFocused)this.row_.getEquivalentElement(this.lastFocused).focus();else this.row_.getFirstFocusable().focus();this.tabIndex=-1},ironListTabIndexChanged_:function(){if(this.row_)this.row_.makeActive(this.ironListTabIndex==0)},onDomChange_:function(){if(this.row_)this.row_.addItems()},onCheckboxSelected_:function(e){this.fire("history-checkbox-select",{element:this,shiftKey:e.shiftKey});e.preventDefault()},onCheckboxMousedown_:function(e){if(e.shiftKey)e.preventDefault()},getEntrySummary_:function(){var item=this.item;return loadTimeData.getStringF("entrySummary",item.dateTimeOfDay,item.starred?loadTimeData.getString("bookmarked"):"",item.title,item.domain)},getAriaChecked_:function(selected){return selected?"true":"false"},onRemoveBookmarkTap_:function(){if(!this.item.starred)return;if(this.$$("#bookmark-star")==this.root.activeElement)this.$["menu-button"].focus();var browserService=md_history.BrowserService.getInstance();browserService.removeBookmark(this.item.url);browserService.recordAction("BookmarkStarClicked");this.fire("remove-bookmark-stars",this.item.url)},onMenuButtonTap_:function(e){this.fire("toggle-menu",{target:Polymer.dom(e).localTarget,index:this.index,item:this.item,path:this.path});e.stopPropagation()},onLinkClick_:function(){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("EntryLinkClick");if(this.searchTerm)browserService.recordAction("SearchResultClick");if(this.index==undefined)return;browserService.recordHistogram("HistoryPage.ClickPosition",this.index,UMA_MAX_BUCKET_VALUE);if(this.index<=UMA_MAX_SUBSET_BUCKET_VALUE){browserService.recordHistogram("HistoryPage.ClickPositionSubset",this.index,UMA_MAX_SUBSET_BUCKET_VALUE)}},onLinkRightClick_:function(){md_history.BrowserService.getInstance().recordAction("EntryLinkRightClick")},showIcon_:function(){this.$.icon.style.backgroundImage=cr.icon.getFavicon(this.item.url)},selectionNotAllowed_:function(){return!loadTimeData.getBoolean("allowDeletingHistory")},cardTitle_:function(numberOfItems,historyDate,search){if(!search)return this.item.dateRelativeDay;var resultId=numberOfItems==1?"searchResult":"searchResults";return loadTimeData.getStringF("foundSearchResults",numberOfItems,loadTimeData.getString(resultId),search)}});HistoryItem.needsTimeGap=function(visits,currentIndex,searchedTerm){if(currentIndex>=visits.length-1||visits.length==0)return false;var currentItem=visits[currentIndex];var nextItem=visits[currentIndex+1];if(searchedTerm)return currentItem.dateShort!=nextItem.dateShort;return currentItem.time-nextItem.time>BROWSING_GAP_TIME&&currentItem.dateRelativeDay==nextItem.dateRelativeDay};return{HistoryItem:HistoryItem}});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-var SelectionTreeNode = function(currentPath) {
-  this.currentPath = currentPath;
-  this.leaf = false;
-  this.indexes = [];
-  this.children = [];
-};
-
-SelectionTreeNode.prototype.addChild = function(index, path) {
-  this.indexes.push(index);
-  this.children[index] = new SelectionTreeNode(path);
-};
-
-var HistoryListBehavior = {
-  properties: {
-    selectedPaths: {
-      type: Object,
-      value: function() {
-        return new Set();
-      }
-    },
-    lastSelectedPath: String
-  },
-  listeners: {
-    'history-checkbox-select': 'itemSelected_'
-  },
-  hasResults: function(historyDataLength) {
-    return historyDataLength > 0;
-  },
-  noResultsMessage: function(searchedTerm, isLoading) {
-    if (isLoading) return '';
-    var messageId = searchedTerm !== '' ? 'noSearchResults' : 'noResults';
-    return loadTimeData.getString(messageId);
-  },
-  unselectAllItems: function() {
-    this.selectedPaths.forEach(function(path) {
-      this.set(path + '.selected', false);
-    }.bind(this));
-    this.selectedPaths.clear();
-  },
-  deleteSelected: function() {
-    var toBeRemoved = Array.from(this.selectedPaths.values()).map(function(path) {
-      return this.get(path);
-    }.bind(this));
-    md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(function() {
-      this.removeItemsByPath(Array.from(this.selectedPaths));
-      this.fire('unselect-all');
-    }.bind(this));
-  },
-  removeItemsByPath: function(paths) {
-    if (paths.length == 0) return;
-    this.removeItemsBeneathNode_(this.buildRemovalTree_(paths));
-  },
-  buildRemovalTree_: function(paths) {
-    var rootNode = new SelectionTreeNode(paths[0].split('.')[0]);
-    paths.forEach(function(path) {
-      var components = path.split('.');
-      var node = rootNode;
-      components.shift();
-      while (components.length > 1) {
-        var index = Number(components.shift());
-        var arrayName = components.shift();
-        if (!node.children[index]) node.addChild(index, [ node.currentPath, index, arrayName ].join('.'));
-        node = node.children[index];
-      }
-      node.leaf = true;
-      node.indexes.push(Number(components.shift()));
-    });
-    return rootNode;
-  },
-  removeItemsBeneathNode_: function(node) {
-    var array = this.get(node.currentPath);
-    var splices = [];
-    node.indexes.sort(function(a, b) {
-      return b - a;
-    });
-    node.indexes.forEach(function(index) {
-      if (node.leaf || this.removeItemsBeneathNode_(node.children[index])) {
-        var item = array.splice(index, 1)[0];
-        splices.push({
-          index: index,
-          removed: [ item ],
-          addedCount: 0,
-          object: array,
-          type: 'splice'
-        });
-      }
-    }.bind(this));
-    if (array.length == 0 && node.currentPath.indexOf('.') != -1) return true;
-    this.notifySplices(node.currentPath, splices);
-    return false;
-  },
-  itemSelected_: function(e) {
-    var item = e.detail.element;
-    var paths = [];
-    var itemPath = item.path;
-    if (e.detail.shiftKey && this.lastSelectedPath) {
-      var itemPathComponents = itemPath.split('.');
-      var itemIndex = Number(itemPathComponents.pop());
-      var itemArrayPath = itemPathComponents.join('.');
-      var lastItemPathComponents = this.lastSelectedPath.split('.');
-      var lastItemIndex = Number(lastItemPathComponents.pop());
-      if (itemArrayPath == lastItemPathComponents.join('.')) {
-        for (var i = Math.min(itemIndex, lastItemIndex); i <= Math.max(itemIndex, lastItemIndex); i++) {
-          paths.push(itemArrayPath + '.' + i);
-        }
-      }
-    }
-    if (paths.length == 0) paths.push(item.path);
-    var selected = !this.selectedPaths.has(item.path);
-    paths.forEach(function(path) {
-      this.set(path + '.selected', selected);
-      if (selected) {
-        this.selectedPaths.add(path);
-        return;
-      }
-      this.selectedPaths.delete(path);
-    }.bind(this));
-    this.lastSelectedPath = itemPath;
-  }
-};
-
+var SelectionTreeNode=function(currentPath){this.currentPath=currentPath;this.leaf=false;this.indexes=[];this.children=[]};SelectionTreeNode.prototype.addChild=function(index,path){this.indexes.push(index);this.children[index]=new SelectionTreeNode(path)};var HistoryListBehavior={properties:{selectedPaths:{type:Object,value:function(){return new Set}},lastSelectedPath:String},listeners:{"history-checkbox-select":"itemSelected_"},hasResults:function(historyDataLength){return historyDataLength>0},noResultsMessage:function(searchedTerm,isLoading){if(isLoading)return"";var messageId=searchedTerm!==""?"noSearchResults":"noResults";return loadTimeData.getString(messageId)},unselectAllItems:function(){this.selectedPaths.forEach(function(path){this.set(path+".selected",false)}.bind(this));this.selectedPaths.clear()},deleteSelected:function(){var toBeRemoved=Array.from(this.selectedPaths.values()).map(function(path){return this.get(path)}.bind(this));md_history.BrowserService.getInstance().deleteItems(toBeRemoved).then(function(){this.removeItemsByPath(Array.from(this.selectedPaths));this.fire("unselect-all")}.bind(this))},removeItemsByPath:function(paths){if(paths.length==0)return;this.removeItemsBeneathNode_(this.buildRemovalTree_(paths))},buildRemovalTree_:function(paths){var rootNode=new SelectionTreeNode(paths[0].split(".")[0]);paths.forEach(function(path){var components=path.split(".");var node=rootNode;components.shift();while(components.length>1){var index=Number(components.shift());var arrayName=components.shift();if(!node.children[index])node.addChild(index,[node.currentPath,index,arrayName].join("."));node=node.children[index]}node.leaf=true;node.indexes.push(Number(components.shift()))});return rootNode},removeItemsBeneathNode_:function(node){var array=this.get(node.currentPath);var splices=[];node.indexes.sort(function(a,b){return b-a});node.indexes.forEach(function(index){if(node.leaf||this.removeItemsBeneathNode_(node.children[index])){var item=array.splice(index,1)[0];splices.push({index:index,removed:[item],addedCount:0,object:array,type:"splice"})}}.bind(this));if(array.length==0&&node.currentPath.indexOf(".")!=-1)return true;this.notifySplices(node.currentPath,splices);return false},itemSelected_:function(e){var item=e.detail.element;var paths=[];var itemPath=item.path;if(e.detail.shiftKey&&this.lastSelectedPath){var itemPathComponents=itemPath.split(".");var itemIndex=Number(itemPathComponents.pop());var itemArrayPath=itemPathComponents.join(".");var lastItemPathComponents=this.lastSelectedPath.split(".");var lastItemIndex=Number(lastItemPathComponents.pop());if(itemArrayPath==lastItemPathComponents.join(".")){for(var i=Math.min(itemIndex,lastItemIndex);i<=Math.max(itemIndex,lastItemIndex);i++){paths.push(itemArrayPath+"."+i)}}}if(paths.length==0)paths.push(item.path);var selected=!this.selectedPaths.has(item.path);paths.forEach(function(path){this.set(path+".selected",selected);if(selected){this.selectedPaths.add(path);return}this.selectedPaths.delete(path)}.bind(this));this.lastSelectedPath=itemPath}};
 // 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({
-  is: 'history-list',
-  behaviors: [ HistoryListBehavior ],
-  properties: {
-    searchedTerm: {
-      type: String,
-      value: ''
-    },
-    querying: Boolean,
-    historyData_: Array,
-    resultLoadingDisabled_: {
-      type: Boolean,
-      value: false
-    },
-    lastFocused_: Object
-  },
-  listeners: {
-    scroll: 'notifyListScroll_',
-    'remove-bookmark-stars': 'removeBookmarkStars_'
-  },
-  attached: function() {
-    this.$['infinite-list'].notifyResize();
-    this.$['infinite-list'].scrollTarget = this;
-    this.$['scroll-threshold'].scrollTarget = this;
-  },
-  removeBookmarkStars_: function(e) {
-    var url = e.detail;
-    if (this.historyData_ === undefined) return;
-    for (var i = 0; i < this.historyData_.length; i++) {
-      if (this.historyData_[i].url == url) this.set('historyData_.' + i + '.starred', false);
-    }
-  },
-  disableResultLoading: function() {
-    this.resultLoadingDisabled_ = true;
-  },
-  addNewResults: function(historyResults, incremental) {
-    var results = historyResults.slice();
-    this.$['scroll-threshold'].clearTriggers();
-    if (!incremental) {
-      this.resultLoadingDisabled_ = false;
-      if (this.historyData_) this.splice('historyData_', 0, this.historyData_.length);
-      this.fire('unselect-all');
-    }
-    if (this.historyData_) {
-      results.unshift('historyData_');
-      this.push.apply(this, results);
-    } else {
-      this.set('historyData_', results);
-    }
-  },
-  loadMoreData_: function() {
-    if (this.resultLoadingDisabled_ || this.querying) return;
-    this.fire('load-more-history');
-  },
-  needsTimeGap_: function(item, index, length) {
-    return md_history.HistoryItem.needsTimeGap(this.historyData_, index, this.searchedTerm);
-  },
-  isCardStart_: function(item, i, length) {
-    if (length == 0 || i > length - 1) return false;
-    return i == 0 || this.historyData_[i].dateRelativeDay != this.historyData_[i - 1].dateRelativeDay;
-  },
-  isCardEnd_: function(item, i, length) {
-    if (length == 0 || i > length - 1) return false;
-    return i == length - 1 || this.historyData_[i].dateRelativeDay != this.historyData_[i + 1].dateRelativeDay;
-  },
-  notifyListScroll_: function() {
-    this.fire('history-list-scrolled');
-  },
-  pathForItem_: function(index) {
-    return 'historyData_.' + index;
-  }
-});
-
+Polymer({is:"history-list",behaviors:[HistoryListBehavior],properties:{searchedTerm:{type:String,value:""},querying:Boolean,historyData_:Array,resultLoadingDisabled_:{type:Boolean,value:false},lastFocused_:Object},listeners:{scroll:"notifyListScroll_","remove-bookmark-stars":"removeBookmarkStars_"},attached:function(){this.$["infinite-list"].notifyResize();this.$["infinite-list"].scrollTarget=this;this.$["scroll-threshold"].scrollTarget=this},removeBookmarkStars_:function(e){var url=e.detail;if(this.historyData_===undefined)return;for(var i=0;i<this.historyData_.length;i++){if(this.historyData_[i].url==url)this.set("historyData_."+i+".starred",false)}},disableResultLoading:function(){this.resultLoadingDisabled_=true},addNewResults:function(historyResults,incremental){var results=historyResults.slice();this.$["scroll-threshold"].clearTriggers();if(!incremental){this.resultLoadingDisabled_=false;if(this.historyData_)this.splice("historyData_",0,this.historyData_.length);this.fire("unselect-all")}if(this.historyData_){results.unshift("historyData_");this.push.apply(this,results)}else{this.set("historyData_",results)}},loadMoreData_:function(){if(this.resultLoadingDisabled_||this.querying)return;this.fire("load-more-history")},needsTimeGap_:function(item,index,length){return md_history.HistoryItem.needsTimeGap(this.historyData_,index,this.searchedTerm)},isCardStart_:function(item,i,length){if(length==0||i>length-1)return false;return i==0||this.historyData_[i].dateRelativeDay!=this.historyData_[i-1].dateRelativeDay},isCardEnd_:function(item,i,length){if(length==0||i>length-1)return false;return i==length-1||this.historyData_[i].dateRelativeDay!=this.historyData_[i+1].dateRelativeDay},notifyListScroll_:function(){this.fire("history-list-scrolled")},pathForItem_:function(index){return"historyData_."+index}});
 // Copyright 2016 The Chromium 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({
-  is: 'history-list-container',
-  properties: {
-    selectedPage_: String,
-    grouped: Boolean,
-    groupedRange: {
-      type: Number,
-      observer: 'groupedRangeChanged_'
-    },
-    queryState: Object,
-    queryResult: Object
-  },
-  observers: [ 'searchTermChanged_(queryState.searchTerm)' ],
-  listeners: {
-    'history-list-scrolled': 'closeMenu_',
-    'load-more-history': 'loadMoreHistory_',
-    'toggle-menu': 'toggleMenu_'
-  },
-  historyResult: function(info, results) {
-    this.initializeResults_(info, results);
-    this.closeMenu_();
-    if (this.selectedPage_ == 'grouped-list') {
-      this.$$('#grouped-list').historyData = results;
-      return;
-    }
-    var list = this.$['infinite-list'];
-    list.addNewResults(results, this.queryState.incremental);
-    if (info.finished) list.disableResultLoading();
-  },
-  queryHistory: function(incremental) {
-    var queryState = this.queryState;
-    var noResults = !this.queryResult || this.queryResult.results == null;
-    if (queryState.queryingDisabled || !this.queryState.searchTerm && noResults) {
-      return;
-    }
-    var dialog = this.$.dialog.getIfExists();
-    if (!incremental && dialog && dialog.open) dialog.close();
-    this.set('queryState.querying', true);
-    this.set('queryState.incremental', incremental);
-    var lastVisitTime = 0;
-    if (incremental) {
-      var lastVisit = this.queryResult.results.slice(-1)[0];
-      lastVisitTime = lastVisit ? lastVisit.time : 0;
-    }
-    var maxResults = this.groupedRange == HistoryRange.ALL_TIME ? RESULTS_PER_PAGE : 0;
-    chrome.send('queryHistory', [ queryState.searchTerm, queryState.groupedOffset, queryState.range, lastVisitTime, maxResults ]);
-  },
-  historyDeleted: function() {
-    if (this.getSelectedItemCount() > 0) return;
-    this.queryHistory(false);
-  },
-  getContentScrollTarget: function() {
-    return this.getSelectedList_();
-  },
-  getSelectedItemCount: function() {
-    return this.getSelectedList_().selectedPaths.size;
-  },
-  unselectAllItems: function(count) {
-    var selectedList = this.getSelectedList_();
-    if (selectedList) selectedList.unselectAllItems(count);
-  },
-  deleteSelectedWithPrompt: function() {
-    if (!loadTimeData.getBoolean('allowDeletingHistory')) return;
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordAction('RemoveSelected');
-    if (this.queryState.searchTerm != '') browserService.recordAction('SearchResultRemove');
-    this.$.dialog.get().showModal();
-  },
-  groupedRangeChanged_: function(range, oldRange) {
-    this.selectedPage_ = range == HistoryRange.ALL_TIME ? 'infinite-list' : 'grouped-list';
-    if (oldRange == undefined) return;
-    this.queryHistory(false);
-    this.fire('history-view-changed');
-  },
-  searchTermChanged_: function() {
-    this.queryHistory(false);
-    if (this.queryState.searchTerm) md_history.BrowserService.getInstance().recordAction('Search');
-  },
-  loadMoreHistory_: function() {
-    this.queryHistory(true);
-  },
-  initializeResults_: function(info, results) {
-    if (results.length == 0) return;
-    var currentDate = results[0].dateRelativeDay;
-    for (var i = 0; i < results.length; i++) {
-      results[i].selected = false;
-      results[i].readableTimestamp = info.term == '' ? results[i].dateTimeOfDay : results[i].dateShort;
-      if (results[i].dateRelativeDay != currentDate) {
-        currentDate = results[i].dateRelativeDay;
-      }
-    }
-  },
-  onDialogConfirmTap_: function() {
-    md_history.BrowserService.getInstance().recordAction('ConfirmRemoveSelected');
-    this.getSelectedList_().deleteSelected();
-    var dialog = assert(this.$.dialog.getIfExists());
-    dialog.close();
-  },
-  onDialogCancelTap_: function() {
-    md_history.BrowserService.getInstance().recordAction('CancelRemoveSelected');
-    var dialog = assert(this.$.dialog.getIfExists());
-    dialog.close();
-  },
-  closeMenu_: function() {
-    var menu = this.$.sharedMenu.getIfExists();
-    if (menu) menu.closeMenu();
-  },
-  toggleMenu_: function(e) {
-    var target = e.detail.target;
-    var menu = this.$.sharedMenu.get();
-    menu.toggleMenu(target, e.detail);
-  },
-  onMoreFromSiteTap_: function() {
-    md_history.BrowserService.getInstance().recordAction('EntryMenuShowMoreFromSite');
-    var menu = assert(this.$.sharedMenu.getIfExists());
-    this.set('queryState.searchTerm', menu.itemData.item.domain);
-    menu.closeMenu();
-  },
-  onRemoveFromHistoryTap_: function() {
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordAction('EntryMenuRemoveFromHistory');
-    var menu = assert(this.$.sharedMenu.getIfExists());
-    var itemData = menu.itemData;
-    browserService.deleteItems([ itemData.item ]).then(function(items) {
-      this.getSelectedList_().removeItemsByPath([ itemData.path ]);
-      this.fire('unselect-all');
-      var index = itemData.index;
-      if (index == undefined) return;
-      var browserService = md_history.BrowserService.getInstance();
-      browserService.recordHistogram('HistoryPage.RemoveEntryPosition', index, UMA_MAX_BUCKET_VALUE);
-      if (index <= UMA_MAX_SUBSET_BUCKET_VALUE) {
-        browserService.recordHistogram('HistoryPage.RemoveEntryPositionSubset', index, UMA_MAX_SUBSET_BUCKET_VALUE);
-      }
-    }.bind(this));
-    menu.closeMenu();
-  },
-  getSelectedList_: function() {
-    return this.$.content.selectedItem;
-  }
-});
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-location',
-    properties: {
-      path: {
-        type: String,
-        notify: true,
-        value: function() {
-          return window.decodeURIComponent(window.location.pathname);
-        }
-      },
-      query: {
-        type: String,
-        notify: true,
-        value: function() {
-          return window.decodeURIComponent(window.location.search.slice(1));
-        }
-      },
-      hash: {
-        type: String,
-        notify: true,
-        value: function() {
-          return window.decodeURIComponent(window.location.hash.slice(1));
-        }
-      },
-      dwellTime: {
-        type: Number,
-        value: 2e3
-      },
-      urlSpaceRegex: {
-        type: String,
-        value: ''
-      },
-      _urlSpaceRegExp: {
-        computed: '_makeRegExp(urlSpaceRegex)'
-      },
-      _lastChangedAt: {
-        type: Number
-      },
-      _initialized: {
-        type: Boolean,
-        value: false
-      }
-    },
-    hostAttributes: {
-      hidden: true
-    },
-    observers: [ '_updateUrl(path, query, hash)' ],
-    attached: function() {
-      this.listen(window, 'hashchange', '_hashChanged');
-      this.listen(window, 'location-changed', '_urlChanged');
-      this.listen(window, 'popstate', '_urlChanged');
-      this.listen(document.body, 'click', '_globalOnClick');
-      this._lastChangedAt = window.performance.now() - (this.dwellTime - 200);
-      this._initialized = true;
-      this._urlChanged();
-    },
-    detached: function() {
-      this.unlisten(window, 'hashchange', '_hashChanged');
-      this.unlisten(window, 'location-changed', '_urlChanged');
-      this.unlisten(window, 'popstate', '_urlChanged');
-      this.unlisten(document.body, 'click', '_globalOnClick');
-      this._initialized = false;
-    },
-    _hashChanged: function() {
-      this.hash = window.decodeURIComponent(window.location.hash.substring(1));
-    },
-    _urlChanged: function() {
-      this._dontUpdateUrl = true;
-      this._hashChanged();
-      this.path = window.decodeURIComponent(window.location.pathname);
-      this.query = window.decodeURIComponent(window.location.search.substring(1));
-      this._dontUpdateUrl = false;
-      this._updateUrl();
-    },
-    _getUrl: function() {
-      var partiallyEncodedPath = window.encodeURI(this.path).replace(/\#/g, '%23').replace(/\?/g, '%3F');
-      var partiallyEncodedQuery = '';
-      if (this.query) {
-        partiallyEncodedQuery = '?' + window.encodeURI(this.query).replace(/\#/g, '%23');
-      }
-      var partiallyEncodedHash = '';
-      if (this.hash) {
-        partiallyEncodedHash = '#' + window.encodeURI(this.hash);
-      }
-      return partiallyEncodedPath + partiallyEncodedQuery + partiallyEncodedHash;
-    },
-    _updateUrl: function() {
-      if (this._dontUpdateUrl || !this._initialized) {
-        return;
-      }
-      if (this.path === window.decodeURIComponent(window.location.pathname) && this.query === window.decodeURIComponent(window.location.search.substring(1)) && this.hash === window.decodeURIComponent(window.location.hash.substring(1))) {
-        return;
-      }
-      var newUrl = this._getUrl();
-      var fullNewUrl = new URL(newUrl, window.location.protocol + '//' + window.location.host).href;
-      var now = window.performance.now();
-      var shouldReplace = this._lastChangedAt + this.dwellTime > now;
-      this._lastChangedAt = now;
-      if (shouldReplace) {
-        window.history.replaceState({}, '', fullNewUrl);
-      } else {
-        window.history.pushState({}, '', fullNewUrl);
-      }
-      this.fire('location-changed', {}, {
-        node: window
-      });
-    },
-    _globalOnClick: function(event) {
-      if (event.defaultPrevented) {
-        return;
-      }
-      var href = this._getSameOriginLinkHref(event);
-      if (!href) {
-        return;
-      }
-      event.preventDefault();
-      if (href === window.location.href) {
-        return;
-      }
-      window.history.pushState({}, '', href);
-      this.fire('location-changed', {}, {
-        node: window
-      });
-    },
-    _getSameOriginLinkHref: function(event) {
-      if (event.button !== 0) {
-        return null;
-      }
-      if (event.metaKey || event.ctrlKey) {
-        return null;
-      }
-      var eventPath = Polymer.dom(event).path;
-      var anchor = null;
-      for (var i = 0; i < eventPath.length; i++) {
-        var element = eventPath[i];
-        if (element.tagName === 'A' && element.href) {
-          anchor = element;
-          break;
-        }
-      }
-      if (!anchor) {
-        return null;
-      }
-      if (anchor.target === '_blank') {
-        return null;
-      }
-      if ((anchor.target === '_top' || anchor.target === '_parent') && window.top !== window) {
-        return null;
-      }
-      var href = anchor.href;
-      var url;
-      if (document.baseURI != null) {
-        url = new URL(href, document.baseURI);
-      } else {
-        url = new URL(href);
-      }
-      var origin;
-      if (window.location.origin) {
-        origin = window.location.origin;
-      } else {
-        origin = window.location.protocol + '//' + window.location.hostname;
-        if (window.location.port) {
-          origin += ':' + window.location.port;
-        }
-      }
-      if (url.origin !== origin) {
-        return null;
-      }
-      var normalizedHref = url.pathname + url.search + url.hash;
-      if (this._urlSpaceRegExp && !this._urlSpaceRegExp.test(normalizedHref)) {
-        return null;
-      }
-      var fullNormalizedHref = new URL(normalizedHref, window.location.href).href;
-      return fullNormalizedHref;
-    },
-    _makeRegExp: function(urlSpaceRegex) {
-      return RegExp(urlSpaceRegex);
-    }
-  });
-})();
-
-'use strict';
-
-Polymer({
-  is: 'iron-query-params',
-  properties: {
-    paramsString: {
-      type: String,
-      notify: true,
-      observer: 'paramsStringChanged'
-    },
-    paramsObject: {
-      type: Object,
-      notify: true,
-      value: function() {
-        return {};
-      }
-    },
-    _dontReact: {
-      type: Boolean,
-      value: false
-    }
-  },
-  hostAttributes: {
-    hidden: true
-  },
-  observers: [ 'paramsObjectChanged(paramsObject.*)' ],
-  paramsStringChanged: function() {
-    this._dontReact = true;
-    this.paramsObject = this._decodeParams(this.paramsString);
-    this._dontReact = false;
-  },
-  paramsObjectChanged: function() {
-    if (this._dontReact) {
-      return;
-    }
-    this.paramsString = this._encodeParams(this.paramsObject);
-  },
-  _encodeParams: function(params) {
-    var encodedParams = [];
-    for (var key in params) {
-      var value = params[key];
-      if (value === '') {
-        encodedParams.push(encodeURIComponent(key));
-      } else if (value) {
-        encodedParams.push(encodeURIComponent(key) + '=' + encodeURIComponent(value.toString()));
-      }
-    }
-    return encodedParams.join('&');
-  },
-  _decodeParams: function(paramString) {
-    var params = {};
-    paramString = (paramString || '').replace(/\+/g, '%20');
-    var paramList = paramString.split('&');
-    for (var i = 0; i < paramList.length; i++) {
-      var param = paramList[i].split('=');
-      if (param[0]) {
-        params[decodeURIComponent(param[0])] = decodeURIComponent(param[1] || '');
-      }
-    }
-    return params;
-  }
-});
-
+Polymer({is:"history-list-container",properties:{selectedPage_:String,grouped:Boolean,groupedRange:{type:Number,observer:"groupedRangeChanged_"},queryState:Object,queryResult:Object},observers:["searchTermChanged_(queryState.searchTerm)"],listeners:{"history-list-scrolled":"closeMenu_","load-more-history":"loadMoreHistory_","toggle-menu":"toggleMenu_"},historyResult:function(info,results){this.initializeResults_(info,results);this.closeMenu_();if(this.selectedPage_=="grouped-list"){this.$$("#grouped-list").historyData=results;return}var list=this.$["infinite-list"];list.addNewResults(results,this.queryState.incremental);if(info.finished)list.disableResultLoading()},queryHistory:function(incremental){var queryState=this.queryState;var noResults=!this.queryResult||this.queryResult.results==null;if(queryState.queryingDisabled||!this.queryState.searchTerm&&noResults){return}var dialog=this.$.dialog.getIfExists();if(!incremental&&dialog&&dialog.open)dialog.close();this.set("queryState.querying",true);this.set("queryState.incremental",incremental);var lastVisitTime=0;if(incremental){var lastVisit=this.queryResult.results.slice(-1)[0];lastVisitTime=lastVisit?lastVisit.time:0}var maxResults=this.groupedRange==HistoryRange.ALL_TIME?RESULTS_PER_PAGE:0;chrome.send("queryHistory",[queryState.searchTerm,queryState.groupedOffset,queryState.range,lastVisitTime,maxResults])},historyDeleted:function(){if(this.getSelectedItemCount()>0)return;this.queryHistory(false)},getContentScrollTarget:function(){return this.getSelectedList_()},getSelectedItemCount:function(){return this.getSelectedList_().selectedPaths.size},unselectAllItems:function(count){var selectedList=this.getSelectedList_();if(selectedList)selectedList.unselectAllItems(count)},deleteSelectedWithPrompt:function(){if(!loadTimeData.getBoolean("allowDeletingHistory"))return;var browserService=md_history.BrowserService.getInstance();browserService.recordAction("RemoveSelected");if(this.queryState.searchTerm!="")browserService.recordAction("SearchResultRemove");this.$.dialog.get().showModal()},groupedRangeChanged_:function(range,oldRange){this.selectedPage_=range==HistoryRange.ALL_TIME?"infinite-list":"grouped-list";if(oldRange==undefined)return;this.queryHistory(false);this.fire("history-view-changed")},searchTermChanged_:function(){this.queryHistory(false);if(this.queryState.searchTerm)md_history.BrowserService.getInstance().recordAction("Search")},loadMoreHistory_:function(){this.queryHistory(true)},initializeResults_:function(info,results){if(results.length==0)return;var currentDate=results[0].dateRelativeDay;for(var i=0;i<results.length;i++){results[i].selected=false;results[i].readableTimestamp=info.term==""?results[i].dateTimeOfDay:results[i].dateShort;if(results[i].dateRelativeDay!=currentDate){currentDate=results[i].dateRelativeDay}}},onDialogConfirmTap_:function(){md_history.BrowserService.getInstance().recordAction("ConfirmRemoveSelected");this.getSelectedList_().deleteSelected();var dialog=assert(this.$.dialog.getIfExists());dialog.close()},onDialogCancelTap_:function(){md_history.BrowserService.getInstance().recordAction("CancelRemoveSelected");var dialog=assert(this.$.dialog.getIfExists());dialog.close()},closeMenu_:function(){var menu=this.$.sharedMenu.getIfExists();if(menu)menu.closeMenu()},toggleMenu_:function(e){var target=e.detail.target;var menu=this.$.sharedMenu.get();menu.toggleMenu(target,e.detail)},onMoreFromSiteTap_:function(){md_history.BrowserService.getInstance().recordAction("EntryMenuShowMoreFromSite");var menu=assert(this.$.sharedMenu.getIfExists());this.set("queryState.searchTerm",menu.itemData.item.domain);menu.closeMenu()},onRemoveFromHistoryTap_:function(){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("EntryMenuRemoveFromHistory");var menu=assert(this.$.sharedMenu.getIfExists());var itemData=menu.itemData;browserService.deleteItems([itemData.item]).then(function(items){this.getSelectedList_().removeItemsByPath([itemData.path]);this.fire("unselect-all");var index=itemData.index;if(index==undefined)return;var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram("HistoryPage.RemoveEntryPosition",index,UMA_MAX_BUCKET_VALUE);if(index<=UMA_MAX_SUBSET_BUCKET_VALUE){browserService.recordHistogram("HistoryPage.RemoveEntryPositionSubset",index,UMA_MAX_SUBSET_BUCKET_VALUE)}}.bind(this));menu.closeMenu()},getSelectedList_:function(){return this.$.content.selectedItem}});(function(){"use strict";Polymer({is:"iron-location",properties:{path:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.pathname)}},query:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.search.slice(1))}},hash:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.hash.slice(1))}},dwellTime:{type:Number,value:2e3},urlSpaceRegex:{type:String,value:""},_urlSpaceRegExp:{computed:"_makeRegExp(urlSpaceRegex)"},_lastChangedAt:{type:Number},_initialized:{type:Boolean,value:false}},hostAttributes:{hidden:true},observers:["_updateUrl(path, query, hash)"],attached:function(){this.listen(window,"hashchange","_hashChanged");this.listen(window,"location-changed","_urlChanged");this.listen(window,"popstate","_urlChanged");this.listen(document.body,"click","_globalOnClick");this._lastChangedAt=window.performance.now()-(this.dwellTime-200);this._initialized=true;this._urlChanged()},detached:function(){this.unlisten(window,"hashchange","_hashChanged");this.unlisten(window,"location-changed","_urlChanged");this.unlisten(window,"popstate","_urlChanged");this.unlisten(document.body,"click","_globalOnClick");this._initialized=false},_hashChanged:function(){this.hash=window.decodeURIComponent(window.location.hash.substring(1))},_urlChanged:function(){this._dontUpdateUrl=true;this._hashChanged();this.path=window.decodeURIComponent(window.location.pathname);this.query=window.decodeURIComponent(window.location.search.substring(1));this._dontUpdateUrl=false;this._updateUrl()},_getUrl:function(){var partiallyEncodedPath=window.encodeURI(this.path).replace(/\#/g,"%23").replace(/\?/g,"%3F");var partiallyEncodedQuery="";if(this.query){partiallyEncodedQuery="?"+window.encodeURI(this.query).replace(/\#/g,"%23")}var partiallyEncodedHash="";if(this.hash){partiallyEncodedHash="#"+window.encodeURI(this.hash)}return partiallyEncodedPath+partiallyEncodedQuery+partiallyEncodedHash},_updateUrl:function(){if(this._dontUpdateUrl||!this._initialized){return}if(this.path===window.decodeURIComponent(window.location.pathname)&&this.query===window.decodeURIComponent(window.location.search.substring(1))&&this.hash===window.decodeURIComponent(window.location.hash.substring(1))){return}var newUrl=this._getUrl();var fullNewUrl=new URL(newUrl,window.location.protocol+"//"+window.location.host).href;var now=window.performance.now();var shouldReplace=this._lastChangedAt+this.dwellTime>now;this._lastChangedAt=now;if(shouldReplace){window.history.replaceState({},"",fullNewUrl)}else{window.history.pushState({},"",fullNewUrl)}this.fire("location-changed",{},{node:window})},_globalOnClick:function(event){if(event.defaultPrevented){return}var href=this._getSameOriginLinkHref(event);if(!href){return}event.preventDefault();if(href===window.location.href){return}window.history.pushState({},"",href);this.fire("location-changed",{},{node:window})},_getSameOriginLinkHref:function(event){if(event.button!==0){return null}if(event.metaKey||event.ctrlKey){return null}var eventPath=Polymer.dom(event).path;var anchor=null;for(var i=0;i<eventPath.length;i++){var element=eventPath[i];if(element.tagName==="A"&&element.href){anchor=element;break}}if(!anchor){return null}if(anchor.target==="_blank"){return null}if((anchor.target==="_top"||anchor.target==="_parent")&&window.top!==window){return null}var href=anchor.href;var url;if(document.baseURI!=null){url=new URL(href,document.baseURI)}else{url=new URL(href)}var origin;if(window.location.origin){origin=window.location.origin}else{origin=window.location.protocol+"//"+window.location.hostname;if(window.location.port){origin+=":"+window.location.port}}if(url.origin!==origin){return null}var normalizedHref=url.pathname+url.search+url.hash;if(this._urlSpaceRegExp&&!this._urlSpaceRegExp.test(normalizedHref)){return null}var fullNormalizedHref=new URL(normalizedHref,window.location.href).href;return fullNormalizedHref},_makeRegExp:function(urlSpaceRegex){return RegExp(urlSpaceRegex)}})})();"use strict";Polymer({is:"iron-query-params",properties:{paramsString:{type:String,notify:true,observer:"paramsStringChanged"},paramsObject:{type:Object,notify:true,value:function(){return{}}},_dontReact:{type:Boolean,value:false}},hostAttributes:{hidden:true},observers:["paramsObjectChanged(paramsObject.*)"],paramsStringChanged:function(){this._dontReact=true;this.paramsObject=this._decodeParams(this.paramsString);this._dontReact=false},paramsObjectChanged:function(){if(this._dontReact){return}this.paramsString=this._encodeParams(this.paramsObject)},_encodeParams:function(params){var encodedParams=[];for(var key in params){var value=params[key];if(value===""){encodedParams.push(encodeURIComponent(key))}else if(value){encodedParams.push(encodeURIComponent(key)+"="+encodeURIComponent(value.toString()))}}return encodedParams.join("&")},_decodeParams:function(paramString){var params={};paramString=(paramString||"").replace(/\+/g,"%20");var paramList=paramString.split("&");for(var i=0;i<paramList.length;i++){var param=paramList[i].split("=");if(param[0]){params[decodeURIComponent(param[0])]=decodeURIComponent(param[1]||"")}}return params}});
 // Copyright 2016 The Chromium 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({
-  is: 'history-router',
-  properties: {
-    selectedPage: {
-      type: String,
-      observer: 'serializePath_',
-      notify: true
-    },
-    queryState: {
-      type: Object,
-      notify: true
-    },
-    path_: {
-      type: String,
-      observer: 'pathChanged_'
-    },
-    queryParams_: Object
-  },
-  observers: [ 'queryParamsChanged_(queryParams_.*)', 'searchTermChanged_(queryState.searchTerm)' ],
-  attached: function() {
-    if (window.location.hash) {
-      window.location.href = window.location.href.split('#')[0] + '?' + window.location.hash.substr(1);
-    }
-  },
-  serializePath_: function() {
-    var page = this.selectedPage == 'history' ? '' : this.selectedPage;
-    this.path_ = '/' + page;
-  },
-  pathChanged_: function() {
-    var sections = this.path_.substr(1).split('/');
-    this.selectedPage = sections[0] || 'history';
-  },
-  queryParamsChanged_: function() {
-    this.set('queryState.searchTerm', this.queryParams_.q || '');
-  },
-  searchTermChanged_: function() {
-    this.set('queryParams_.q', this.queryState.searchTerm || null);
-  }
-});
-
-Polymer.IronMultiSelectableBehaviorImpl = {
-  properties: {
-    multi: {
-      type: Boolean,
-      value: false,
-      observer: 'multiChanged'
-    },
-    selectedValues: {
-      type: Array,
-      notify: true
-    },
-    selectedItems: {
-      type: Array,
-      readOnly: true,
-      notify: true
-    }
-  },
-  observers: [ '_updateSelected(selectedValues.splices)' ],
-  select: function(value) {
-    if (this.multi) {
-      if (this.selectedValues) {
-        this._toggleSelected(value);
-      } else {
-        this.selectedValues = [ value ];
-      }
-    } else {
-      this.selected = value;
-    }
-  },
-  multiChanged: function(multi) {
-    this._selection.multi = multi;
-  },
-  get _shouldUpdateSelection() {
-    return this.selected != null || this.selectedValues != null && this.selectedValues.length;
-  },
-  _updateAttrForSelected: function() {
-    if (!this.multi) {
-      Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this);
-    } else if (this._shouldUpdateSelection) {
-      this.selectedValues = this.selectedItems.map(function(selectedItem) {
-        return this._indexToValue(this.indexOf(selectedItem));
-      }, this).filter(function(unfilteredValue) {
-        return unfilteredValue != null;
-      }, this);
-    }
-  },
-  _updateSelected: function() {
-    if (this.multi) {
-      this._selectMulti(this.selectedValues);
-    } else {
-      this._selectSelected(this.selected);
-    }
-  },
-  _selectMulti: function(values) {
-    if (values) {
-      var selectedItems = this._valuesToItems(values);
-      this._selection.clear(selectedItems);
-      for (var i = 0; i < selectedItems.length; i++) {
-        this._selection.setItemSelected(selectedItems[i], true);
-      }
-      if (this.fallbackSelection && this.items.length && !this._selection.get().length) {
-        var fallback = this._valueToItem(this.fallbackSelection);
-        if (fallback) {
-          this.selectedValues = [ this.fallbackSelection ];
-        }
-      }
-    } else {
-      this._selection.clear();
-    }
-  },
-  _selectionChange: function() {
-    var s = this._selection.get();
-    if (this.multi) {
-      this._setSelectedItems(s);
-    } else {
-      this._setSelectedItems([ s ]);
-      this._setSelectedItem(s);
-    }
-  },
-  _toggleSelected: function(value) {
-    var i = this.selectedValues.indexOf(value);
-    var unselected = i < 0;
-    if (unselected) {
-      this.push('selectedValues', value);
-    } else {
-      this.splice('selectedValues', i, 1);
-    }
-  },
-  _valuesToItems: function(values) {
-    return values == null ? null : values.map(function(value) {
-      return this._valueToItem(value);
-    }, this);
-  }
-};
-
-Polymer.IronMultiSelectableBehavior = [ Polymer.IronSelectableBehavior, Polymer.IronMultiSelectableBehaviorImpl ];
-
-Polymer({
-  is: 'iron-selector',
-  behaviors: [ Polymer.IronMultiSelectableBehavior ]
-});
-
+Polymer({is:"history-router",properties:{selectedPage:{type:String,observer:"serializePath_",notify:true},queryState:{type:Object,notify:true},path_:{type:String,observer:"pathChanged_"},queryParams_:Object},observers:["queryParamsChanged_(queryParams_.*)","searchTermChanged_(queryState.searchTerm)"],attached:function(){if(window.location.hash){window.location.href=window.location.href.split("#")[0]+"?"+window.location.hash.substr(1)}},serializePath_:function(){var page=this.selectedPage=="history"?"":this.selectedPage;this.path_="/"+page},pathChanged_:function(){var sections=this.path_.substr(1).split("/");this.selectedPage=sections[0]||"history"},queryParamsChanged_:function(){this.set("queryState.searchTerm",this.queryParams_.q||"")},searchTermChanged_:function(){this.set("queryParams_.q",this.queryState.searchTerm||null)}});Polymer.IronMultiSelectableBehaviorImpl={properties:{multi:{type:Boolean,value:false,observer:"multiChanged"},selectedValues:{type:Array,notify:true},selectedItems:{type:Array,readOnly:true,notify:true}},observers:["_updateSelected(selectedValues.splices)"],select:function(value){if(this.multi){if(this.selectedValues){this._toggleSelected(value)}else{this.selectedValues=[value]}}else{this.selected=value}},multiChanged:function(multi){this._selection.multi=multi},get _shouldUpdateSelection(){return this.selected!=null||this.selectedValues!=null&&this.selectedValues.length},_updateAttrForSelected:function(){if(!this.multi){Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this)}else if(this._shouldUpdateSelection){this.selectedValues=this.selectedItems.map(function(selectedItem){return this._indexToValue(this.indexOf(selectedItem))},this).filter(function(unfilteredValue){return unfilteredValue!=null},this)}},_updateSelected:function(){if(this.multi){this._selectMulti(this.selectedValues)}else{this._selectSelected(this.selected)}},_selectMulti:function(values){if(values){var selectedItems=this._valuesToItems(values);this._selection.clear(selectedItems);for(var i=0;i<selectedItems.length;i++){this._selection.setItemSelected(selectedItems[i],true)}if(this.fallbackSelection&&this.items.length&&!this._selection.get().length){var fallback=this._valueToItem(this.fallbackSelection);if(fallback){this.selectedValues=[this.fallbackSelection]}}}else{this._selection.clear()}},_selectionChange:function(){var s=this._selection.get();if(this.multi){this._setSelectedItems(s)}else{this._setSelectedItems([s]);this._setSelectedItem(s)}},_toggleSelected:function(value){var i=this.selectedValues.indexOf(value);var unselected=i<0;if(unselected){this.push("selectedValues",value)}else{this.splice("selectedValues",i,1)}},_valuesToItems:function(values){return values==null?null:values.map(function(value){return this._valueToItem(value)},this)}};Polymer.IronMultiSelectableBehavior=[Polymer.IronSelectableBehavior,Polymer.IronMultiSelectableBehaviorImpl];Polymer({is:"iron-selector",behaviors:[Polymer.IronMultiSelectableBehavior]});
 // Copyright 2016 The Chromium 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({
-  is: 'history-side-bar',
-  behaviors: [ Polymer.IronA11yKeysBehavior ],
-  properties: {
-    selectedPage: {
-      type: String,
-      notify: true
-    },
-    showFooter: Boolean,
-    drawer: {
-      type: Boolean,
-      reflectToAttribute: true
-    }
-  },
-  keyBindings: {
-    'space:keydown': 'onSpacePressed_'
-  },
-  onSpacePressed_: function(e) {
-    e.detail.keyboardEvent.path[0].click();
-  },
-  onSelectorActivate_: function() {
-    this.fire('history-close-drawer');
-  },
-  onClearBrowsingDataTap_: function(e) {
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordAction('InitClearBrowsingData');
-    browserService.openClearBrowsingData();
-    this.$['cbd-ripple'].upAction();
-    e.preventDefault();
-  },
-  onItemClick_: function(e) {
-    e.preventDefault();
-  }
-});
-
+Polymer({is:"history-side-bar",behaviors:[Polymer.IronA11yKeysBehavior],properties:{selectedPage:{type:String,notify:true},showFooter:Boolean,drawer:{type:Boolean,reflectToAttribute:true}},keyBindings:{"space:keydown":"onSpacePressed_"},onSpacePressed_:function(e){e.detail.keyboardEvent.path[0].click()},onSelectorActivate_:function(){this.fire("history-close-drawer")},onClearBrowsingDataTap_:function(e){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("InitClearBrowsingData");browserService.openClearBrowsingData();this.$["cbd-ripple"].upAction();e.preventDefault()},onItemClick_:function(e){e.preventDefault()}});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-cr.define('md_history', function() {
-  var lazyLoadPromise = null;
-  function ensureLazyLoaded() {
-    if (!lazyLoadPromise) {
-      lazyLoadPromise = new Promise(function(resolve, reject) {
-        Polymer.Base.importHref('chrome://history/lazy_load.html', resolve, reject, true);
-      });
-    }
-    return lazyLoadPromise;
-  }
-  return {
-    ensureLazyLoaded: ensureLazyLoaded
-  };
-});
-
-Polymer({
-  is: 'history-app',
-  behaviors: [ Polymer.IronScrollTargetBehavior ],
-  properties: {
-    showSidebarFooter: Boolean,
-    hasSyncedResults: Boolean,
-    selectedPage_: {
-      type: String,
-      observer: 'selectedPageChanged_'
-    },
-    grouped_: {
-      type: Boolean,
-      reflectToAttribute: true
-    },
-    queryState_: {
-      type: Object,
-      value: function() {
-        return {
-          incremental: false,
-          querying: true,
-          queryingDisabled: false,
-          _range: HistoryRange.ALL_TIME,
-          searchTerm: '',
-          groupedOffset: 0,
-          set range(val) {
-            this._range = Number(val);
-          },
-          get range() {
-            return this._range;
-          }
-        };
-      }
-    },
-    queryResult_: {
-      type: Object,
-      value: function() {
-        return {
-          info: null,
-          results: null,
-          sessionList: null
-        };
-      }
-    },
-    hasDrawer_: Boolean,
-    isUserSignedIn_: {
-      type: Boolean,
-      value: loadTimeData.getBoolean('isUserSignedIn')
-    },
-    toolbarShadow_: {
-      type: Boolean,
-      reflectToAttribute: true,
-      notify: true
-    }
-  },
-  listeners: {
-    'cr-menu-tap': 'onMenuTap_',
-    'history-checkbox-select': 'checkboxSelected',
-    'unselect-all': 'unselectAll',
-    'delete-selected': 'deleteSelected',
-    'history-close-drawer': 'closeDrawer_',
-    'history-view-changed': 'historyViewChanged_'
-  },
-  ready: function() {
-    this.grouped_ = loadTimeData.getBoolean('groupByDomain');
-    cr.ui.decorate('command', cr.ui.Command);
-    document.addEventListener('canExecute', this.onCanExecute_.bind(this));
-    document.addEventListener('command', this.onCommand_.bind(this));
-  },
-  onFirstRender: function() {
-    setTimeout(function() {
-      chrome.send('metricsHandler:recordTime', [ 'History.ResultsRenderedTime', window.performance.now() ]);
-    });
-    var searchField = this.$.toolbar.searchField;
-    if (!searchField.narrow) {
-      searchField.getSearchInput().focus();
-    }
-    md_history.ensureLazyLoaded();
-  },
-  _scrollHandler: function() {
-    if (this.scrollTarget) this.toolbarShadow_ = this.scrollTarget.scrollTop != 0;
-  },
-  onMenuTap_: function() {
-    var drawer = this.$$('#drawer');
-    if (drawer) drawer.toggle();
-  },
-  checkboxSelected: function(e) {
-    var toolbar = this.$.toolbar;
-    toolbar.count = this.$.history.getSelectedItemCount();
-  },
-  unselectAll: function() {
-    var listContainer = this.$.history;
-    var toolbar = this.$.toolbar;
-    listContainer.unselectAllItems(toolbar.count);
-    toolbar.count = 0;
-  },
-  deleteSelected: function() {
-    this.$.history.deleteSelectedWithPrompt();
-  },
-  historyResult: function(info, results) {
-    this.set('queryState_.querying', false);
-    this.set('queryResult_.info', info);
-    this.set('queryResult_.results', results);
-    var listContainer = this.$['history'];
-    listContainer.historyResult(info, results);
-  },
-  focusToolbarSearchField: function() {
-    this.$.toolbar.showSearchField();
-  },
-  onCanExecute_: function(e) {
-    e = e;
-    switch (e.command.id) {
-     case 'find-command':
-      e.canExecute = true;
-      break;
-
-     case 'slash-command':
-      e.canExecute = !this.$.toolbar.searchField.isSearchFocused();
-      break;
-
-     case 'delete-command':
-      e.canExecute = this.$.toolbar.count > 0;
-      break;
-    }
-  },
-  onCommand_: function(e) {
-    if (e.command.id == 'find-command' || e.command.id == 'slash-command') this.focusToolbarSearchField();
-    if (e.command.id == 'delete-command') this.deleteSelected();
-  },
-  setForeignSessions: function(sessionList, isTabSyncEnabled) {
-    if (!isTabSyncEnabled) {
-      var syncedDeviceManagerElem = this.$$('history-synced-device-manager');
-      if (syncedDeviceManagerElem) syncedDeviceManagerElem.tabSyncDisabled();
-      return;
-    }
-    this.set('queryResult_.sessionList', sessionList);
-  },
-  historyDeleted: function() {
-    this.$.history.historyDeleted();
-  },
-  updateSignInState: function(isUserSignedIn) {
-    this.isUserSignedIn_ = isUserSignedIn;
-  },
-  syncedTabsSelected_: function(selectedPage) {
-    return selectedPage == 'syncedTabs';
-  },
-  shouldShowSpinner_: function(querying, incremental, searchTerm) {
-    return querying && !incremental && searchTerm != '';
-  },
-  showSyncNotice_: function(hasSyncedResults, selectedPage) {
-    return hasSyncedResults && selectedPage != 'syncedTabs';
-  },
-  selectedPageChanged_: function() {
-    this.unselectAll();
-    this.historyViewChanged_();
-  },
-  historyViewChanged_: function() {
-    requestAnimationFrame(function() {
-      if (!this.$.content.selectedItem) return;
-      this.scrollTarget = this.$.content.selectedItem.getContentScrollTarget();
-      this._scrollHandler();
-    }.bind(this));
-    this.recordHistoryPageView_();
-  },
-  getSelectedPage_: function(selectedPage, items) {
-    return selectedPage;
-  },
-  closeDrawer_: function() {
-    var drawer = this.$$('#drawer');
-    if (drawer) drawer.close();
-  },
-  recordHistoryPageView_: function() {
-    var histogramValue = HistoryPageViewHistogram.END;
-    switch (this.selectedPage_) {
-     case 'syncedTabs':
-      histogramValue = this.isUserSignedIn_ ? HistoryPageViewHistogram.SYNCED_TABS : HistoryPageViewHistogram.SIGNIN_PROMO;
-      break;
-
-     default:
-      switch (this.queryState_.range) {
-       case HistoryRange.ALL_TIME:
-        histogramValue = HistoryPageViewHistogram.HISTORY;
-        break;
-
-       case HistoryRange.WEEK:
-        histogramValue = HistoryPageViewHistogram.GROUPED_WEEK;
-        break;
-
-       case HistoryRange.MONTH:
-        histogramValue = HistoryPageViewHistogram.GROUPED_MONTH;
-        break;
-      }
-      break;
-    }
-    md_history.BrowserService.getInstance().recordHistogram('History.HistoryPageView', histogramValue, HistoryPageViewHistogram.END);
-  }
-});
\ No newline at end of file
+cr.define("md_history",function(){var lazyLoadPromise=null;function ensureLazyLoaded(){if(!lazyLoadPromise){lazyLoadPromise=new Promise(function(resolve,reject){Polymer.Base.importHref("chrome://history/lazy_load.html",resolve,reject,true)})}return lazyLoadPromise}return{ensureLazyLoaded:ensureLazyLoaded}});Polymer({is:"history-app",behaviors:[Polymer.IronScrollTargetBehavior],properties:{showSidebarFooter:Boolean,hasSyncedResults:Boolean,selectedPage_:{type:String,observer:"selectedPageChanged_"},grouped_:{type:Boolean,reflectToAttribute:true},queryState_:{type:Object,value:function(){return{incremental:false,querying:true,queryingDisabled:false,_range:HistoryRange.ALL_TIME,searchTerm:"",groupedOffset:0,set range(val){this._range=Number(val)},get range(){return this._range}}}},queryResult_:{type:Object,value:function(){return{info:null,results:null,sessionList:null}}},hasDrawer_:Boolean,isUserSignedIn_:{type:Boolean,value:loadTimeData.getBoolean("isUserSignedIn")},toolbarShadow_:{type:Boolean,reflectToAttribute:true,notify:true}},listeners:{"cr-menu-tap":"onMenuTap_","history-checkbox-select":"checkboxSelected","unselect-all":"unselectAll","delete-selected":"deleteSelected","history-close-drawer":"closeDrawer_","history-view-changed":"historyViewChanged_"},ready:function(){this.grouped_=loadTimeData.getBoolean("groupByDomain");cr.ui.decorate("command",cr.ui.Command);document.addEventListener("canExecute",this.onCanExecute_.bind(this));document.addEventListener("command",this.onCommand_.bind(this))},onFirstRender:function(){setTimeout(function(){chrome.send("metricsHandler:recordTime",["History.ResultsRenderedTime",window.performance.now()])});var searchField=this.$.toolbar.searchField;if(!searchField.narrow){searchField.getSearchInput().focus()}md_history.ensureLazyLoaded()},_scrollHandler:function(){if(this.scrollTarget)this.toolbarShadow_=this.scrollTarget.scrollTop!=0},onMenuTap_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.toggle()},checkboxSelected:function(e){var toolbar=this.$.toolbar;toolbar.count=this.$.history.getSelectedItemCount()},unselectAll:function(){var listContainer=this.$.history;var toolbar=this.$.toolbar;listContainer.unselectAllItems(toolbar.count);toolbar.count=0},deleteSelected:function(){this.$.history.deleteSelectedWithPrompt()},historyResult:function(info,results){this.set("queryState_.querying",false);this.set("queryResult_.info",info);this.set("queryResult_.results",results);var listContainer=this.$["history"];listContainer.historyResult(info,results)},focusToolbarSearchField:function(){this.$.toolbar.showSearchField()},onCanExecute_:function(e){e=e;switch(e.command.id){case"find-command":e.canExecute=true;break;case"slash-command":e.canExecute=!this.$.toolbar.searchField.isSearchFocused();break;case"delete-command":e.canExecute=this.$.toolbar.count>0;break}},onCommand_:function(e){if(e.command.id=="find-command"||e.command.id=="slash-command")this.focusToolbarSearchField();if(e.command.id=="delete-command")this.deleteSelected()},setForeignSessions:function(sessionList,isTabSyncEnabled){if(!isTabSyncEnabled){var syncedDeviceManagerElem=this.$$("history-synced-device-manager");if(syncedDeviceManagerElem)syncedDeviceManagerElem.tabSyncDisabled();return}this.set("queryResult_.sessionList",sessionList)},historyDeleted:function(){this.$.history.historyDeleted()},updateSignInState:function(isUserSignedIn){this.isUserSignedIn_=isUserSignedIn},syncedTabsSelected_:function(selectedPage){return selectedPage=="syncedTabs"},shouldShowSpinner_:function(querying,incremental,searchTerm){return querying&&!incremental&&searchTerm!=""},showSyncNotice_:function(hasSyncedResults,selectedPage){return hasSyncedResults&&selectedPage!="syncedTabs"},selectedPageChanged_:function(){this.unselectAll();this.historyViewChanged_()},historyViewChanged_:function(){requestAnimationFrame(function(){if(!this.$.content.selectedItem)return;this.scrollTarget=this.$.content.selectedItem.getContentScrollTarget();this._scrollHandler()}.bind(this));this.recordHistoryPageView_()},getSelectedPage_:function(selectedPage,items){return selectedPage},closeDrawer_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.close()},recordHistoryPageView_:function(){var histogramValue=HistoryPageViewHistogram.END;switch(this.selectedPage_){case"syncedTabs":histogramValue=this.isUserSignedIn_?HistoryPageViewHistogram.SYNCED_TABS:HistoryPageViewHistogram.SIGNIN_PROMO;break;default:switch(this.queryState_.range){case HistoryRange.ALL_TIME:histogramValue=HistoryPageViewHistogram.HISTORY;break;case HistoryRange.WEEK:histogramValue=HistoryPageViewHistogram.GROUPED_WEEK;break;case HistoryRange.MONTH:histogramValue=HistoryPageViewHistogram.GROUPED_MONTH;break}break}md_history.BrowserService.getInstance().recordHistogram("History.HistoryPageView",histogramValue,HistoryPageViewHistogram.END)}});
\ No newline at end of file
diff --git a/chrome/browser/resources/md_history/app.vulcanized.html b/chrome/browser/resources/md_history/app.vulcanized.html
index 43040c9..2500f4a5 100644
--- a/chrome/browser/resources/md_history/app.vulcanized.html
+++ b/chrome/browser/resources/md_history/app.vulcanized.html
@@ -2836,6 +2836,12 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+.scroll-container {
+  display: flex;
+        flex-direction: column;
+        min-height: 1px;
+}
+
 [selectable]:focus, [selectable] > :focus {
   background-color: var(--cr-selectable-focus_-_background-color); outline: var(--cr-selectable-focus_-_outline);
 }
@@ -3508,6 +3514,12 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+.scroll-container {
+  display: flex;
+        flex-direction: column;
+        min-height: 1px;
+}
+
 [selectable]:focus, [selectable] > :focus {
   background-color: var(--cr-selectable-focus_-_background-color); outline: var(--cr-selectable-focus_-_outline);
 }
diff --git a/chrome/browser/resources/md_history/lazy_load.crisper.js b/chrome/browser/resources/md_history/lazy_load.crisper.js
index cc06fa30..7acffe8 100644
--- a/chrome/browser/resources/md_history/lazy_load.crisper.js
+++ b/chrome/browser/resources/md_history/lazy_load.crisper.js
@@ -1,3295 +1,23 @@
-Polymer({
-  is: 'iron-collapse',
-  behaviors: [ Polymer.IronResizableBehavior ],
-  properties: {
-    horizontal: {
-      type: Boolean,
-      value: false,
-      observer: '_horizontalChanged'
-    },
-    opened: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      observer: '_openedChanged'
-    },
-    noAnimation: {
-      type: Boolean
-    },
-    _desiredSize: {
-      type: String,
-      value: ''
-    }
-  },
-  get dimension() {
-    return this.horizontal ? 'width' : 'height';
-  },
-  get _dimensionMax() {
-    return this.horizontal ? 'maxWidth' : 'maxHeight';
-  },
-  get _dimensionMaxCss() {
-    return this.horizontal ? 'max-width' : 'max-height';
-  },
-  hostAttributes: {
-    role: 'group',
-    'aria-hidden': 'true',
-    'aria-expanded': 'false'
-  },
-  listeners: {
-    transitionend: '_transitionEnd'
-  },
-  attached: function() {
-    this._transitionEnd();
-  },
-  toggle: function() {
-    this.opened = !this.opened;
-  },
-  show: function() {
-    this.opened = true;
-  },
-  hide: function() {
-    this.opened = false;
-  },
-  updateSize: function(size, animated) {
-    size = size === 'auto' ? '' : size;
-    if (this._desiredSize === size) {
-      return;
-    }
-    this._desiredSize = size;
-    this._updateTransition(false);
-    var willAnimate = animated && !this.noAnimation && this._isDisplayed;
-    if (willAnimate) {
-      var startSize = this._calcSize();
-      if (size === '') {
-        this.style[this._dimensionMax] = '';
-        size = this._calcSize();
-      }
-      this.style[this._dimensionMax] = startSize;
-      this.scrollTop = this.scrollTop;
-      this._updateTransition(true);
-      willAnimate = size !== startSize;
-    }
-    this.style[this._dimensionMax] = size;
-    if (!willAnimate) {
-      this._transitionEnd();
-    }
-  },
-  enableTransition: function(enabled) {
-    Polymer.Base._warn('`enableTransition()` is deprecated, use `noAnimation` instead.');
-    this.noAnimation = !enabled;
-  },
-  _updateTransition: function(enabled) {
-    this.style.transitionDuration = enabled && !this.noAnimation ? '' : '0s';
-  },
-  _horizontalChanged: function() {
-    this.style.transitionProperty = this._dimensionMaxCss;
-    var otherDimension = this._dimensionMax === 'maxWidth' ? 'maxHeight' : 'maxWidth';
-    this.style[otherDimension] = '';
-    this.updateSize(this.opened ? 'auto' : '0px', false);
-  },
-  _openedChanged: function() {
-    this.setAttribute('aria-expanded', this.opened);
-    this.setAttribute('aria-hidden', !this.opened);
-    this.toggleClass('iron-collapse-closed', false);
-    this.toggleClass('iron-collapse-opened', false);
-    this.updateSize(this.opened ? 'auto' : '0px', true);
-    if (this.opened) {
-      this.focus();
-    }
-  },
-  _transitionEnd: function() {
-    this.style[this._dimensionMax] = this._desiredSize;
-    this.toggleClass('iron-collapse-closed', !this.opened);
-    this.toggleClass('iron-collapse-opened', this.opened);
-    this._updateTransition(false);
-    this.notifyResize();
-  },
-  get _isDisplayed() {
-    var rect = this.getBoundingClientRect();
-    for (var prop in rect) {
-      if (rect[prop] !== 0) return true;
-    }
-    return false;
-  },
-  _calcSize: function() {
-    return this.getBoundingClientRect()[this.dimension] + 'px';
-  }
-});
-
+Polymer({is:"iron-collapse",behaviors:[Polymer.IronResizableBehavior],properties:{horizontal:{type:Boolean,value:false,observer:"_horizontalChanged"},opened:{type:Boolean,value:false,notify:true,observer:"_openedChanged"},noAnimation:{type:Boolean},_desiredSize:{type:String,value:""}},get dimension(){return this.horizontal?"width":"height"},get _dimensionMax(){return this.horizontal?"maxWidth":"maxHeight"},get _dimensionMaxCss(){return this.horizontal?"max-width":"max-height"},hostAttributes:{role:"group","aria-hidden":"true","aria-expanded":"false"},listeners:{transitionend:"_transitionEnd"},attached:function(){this._transitionEnd()},toggle:function(){this.opened=!this.opened},show:function(){this.opened=true},hide:function(){this.opened=false},updateSize:function(size,animated){size=size==="auto"?"":size;if(this._desiredSize===size){return}this._desiredSize=size;this._updateTransition(false);var willAnimate=animated&&!this.noAnimation&&this._isDisplayed;if(willAnimate){var startSize=this._calcSize();if(size===""){this.style[this._dimensionMax]="";size=this._calcSize()}this.style[this._dimensionMax]=startSize;this.scrollTop=this.scrollTop;this._updateTransition(true);willAnimate=size!==startSize}this.style[this._dimensionMax]=size;if(!willAnimate){this._transitionEnd()}},enableTransition:function(enabled){Polymer.Base._warn("`enableTransition()` is deprecated, use `noAnimation` instead.");this.noAnimation=!enabled},_updateTransition:function(enabled){this.style.transitionDuration=enabled&&!this.noAnimation?"":"0s"},_horizontalChanged:function(){this.style.transitionProperty=this._dimensionMaxCss;var otherDimension=this._dimensionMax==="maxWidth"?"maxHeight":"maxWidth";this.style[otherDimension]="";this.updateSize(this.opened?"auto":"0px",false)},_openedChanged:function(){this.setAttribute("aria-expanded",this.opened);this.setAttribute("aria-hidden",!this.opened);this.toggleClass("iron-collapse-closed",false);this.toggleClass("iron-collapse-opened",false);this.updateSize(this.opened?"auto":"0px",true);if(this.opened){this.focus()}},_transitionEnd:function(){this.style[this._dimensionMax]=this._desiredSize;this.toggleClass("iron-collapse-closed",!this.opened);this.toggleClass("iron-collapse-opened",this.opened);this._updateTransition(false);this.notifyResize()},get _isDisplayed(){var rect=this.getBoundingClientRect();for(var prop in rect){if(rect[prop]!==0)return true}return false},_calcSize:function(){return this.getBoundingClientRect()[this.dimension]+"px"}});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-var HistoryDomain;
+var HistoryDomain;var HistoryGroup;Polymer({is:"history-grouped-list",behaviors:[HistoryListBehavior],properties:{historyData:{type:Array},groupedHistoryData_:{type:Array},searchedTerm:{type:String,value:""},range:{type:Number},queryStartTime:String,queryEndTime:String},observers:["updateGroupedHistoryData_(range, historyData)"],createHistoryDomains_:function(visits){var domainIndexes={};var domains=[];for(var i=0,visit;visit=visits[i];i++){var domain=visit.domain;if(domainIndexes[domain]==undefined){domainIndexes[domain]=domains.length;domains.push({domain:domain,visits:[],expanded:false,rendered:false})}domains[domainIndexes[domain]].visits.push(visit)}var sortByVisits=function(a,b){return b.visits.length-a.visits.length};domains.sort(sortByVisits);return domains},updateGroupedHistoryData_:function(){if(this.historyData.length==0){this.groupedHistoryData_=[];return}if(this.range==HistoryRange.WEEK){var days=[];var currentDayVisits=[this.historyData[0]];var pushCurrentDay=function(){days.push({title:this.searchedTerm?currentDayVisits[0].dateShort:currentDayVisits[0].dateRelativeDay,domains:this.createHistoryDomains_(currentDayVisits)})}.bind(this);var visitsSameDay=function(a,b){if(this.searchedTerm)return a.dateShort==b.dateShort;return a.dateRelativeDay==b.dateRelativeDay}.bind(this);for(var i=1;i<this.historyData.length;i++){var visit=this.historyData[i];if(!visitsSameDay(visit,currentDayVisits[0])){pushCurrentDay();currentDayVisits=[]}currentDayVisits.push(visit)}pushCurrentDay();this.groupedHistoryData_=days}else if(this.range==HistoryRange.MONTH){this.groupedHistoryData_=[{title:this.queryStartTime+" – "+this.queryEndTime,domains:this.createHistoryDomains_(this.historyData)}]}},toggleDomainExpanded_:function(e){var collapse=e.currentTarget.parentNode.querySelector("iron-collapse");e.model.set("domain.rendered",true);setTimeout(function(){collapse.toggle()},0)},needsTimeGap_:function(groupIndex,domainIndex,itemIndex){var visits=this.groupedHistoryData_[groupIndex].domains[domainIndex].visits;return md_history.HistoryItem.needsTimeGap(visits,itemIndex,this.searchedTerm)},pathForItem_:function(groupIndex,domainIndex,itemIndex){return["groupedHistoryData_",groupIndex,"domains",domainIndex,"visits",itemIndex].join(".")},getWebsiteIconStyle_:function(domain){return"background-image: "+cr.icon.getFavicon(domain.visits[0].url)},getDropdownIcon_:function(expanded){return expanded?"cr:expand-less":"cr:expand-more"}});Polymer.PaperButtonBehaviorImpl={properties:{elevation:{type:Number,reflectToAttribute:true,readOnly:true}},observers:["_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)","_computeKeyboardClass(receivedFocusFromKeyboard)"],hostAttributes:{role:"button",tabindex:"0",animated:true},_calculateElevation:function(){var e=1;if(this.disabled){e=0}else if(this.active||this.pressed){e=4}else if(this.receivedFocusFromKeyboard){e=3}this._setElevation(e)},_computeKeyboardClass:function(receivedFocusFromKeyboard){this.toggleClass("keyboard-focus",receivedFocusFromKeyboard)},_spaceKeyDownHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this,event);if(this.hasRipple()&&this.getRipple().ripples.length<1){this._ripple.uiDownAction()}},_spaceKeyUpHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this,event);if(this.hasRipple()){this._ripple.uiUpAction()}}};Polymer.PaperButtonBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperButtonBehaviorImpl];Polymer({is:"paper-button",behaviors:[Polymer.PaperButtonBehavior],properties:{raised:{type:Boolean,reflectToAttribute:true,value:false,observer:"_calculateElevation"}},_calculateElevation:function(){if(!this.raised){this._setElevation(0)}else{Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this)}}});Polymer.PaperItemBehaviorImpl={hostAttributes:{role:"option",tabindex:"0"}};Polymer.PaperItemBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperItemBehaviorImpl];Polymer({is:"paper-item",behaviors:[Polymer.PaperItemBehavior]});Polymer.IronFitBehavior={properties:{sizingTarget:{type:Object,value:function(){return this}},fitInto:{type:Object,value:window},noOverlap:{type:Boolean},positionTarget:{type:Element},horizontalAlign:{type:String},verticalAlign:{type:String},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},autoFitOnAttach:{type:Boolean,value:false},_fitInfo:{type:Object}},get _fitWidth(){var fitWidth;if(this.fitInto===window){fitWidth=this.fitInto.innerWidth}else{fitWidth=this.fitInto.getBoundingClientRect().width}return fitWidth},get _fitHeight(){var fitHeight;if(this.fitInto===window){fitHeight=this.fitInto.innerHeight}else{fitHeight=this.fitInto.getBoundingClientRect().height}return fitHeight},get _fitLeft(){var fitLeft;if(this.fitInto===window){fitLeft=0}else{fitLeft=this.fitInto.getBoundingClientRect().left}return fitLeft},get _fitTop(){var fitTop;if(this.fitInto===window){fitTop=0}else{fitTop=this.fitInto.getBoundingClientRect().top}return fitTop},get _defaultPositionTarget(){var parent=Polymer.dom(this).parentNode;if(parent&&parent.nodeType===Node.DOCUMENT_FRAGMENT_NODE){parent=parent.host}return parent},get _localeHorizontalAlign(){if(this._isRTL){if(this.horizontalAlign==="right"){return"left"}if(this.horizontalAlign==="left"){return"right"}}return this.horizontalAlign},attached:function(){this._isRTL=window.getComputedStyle(this).direction=="rtl";this.positionTarget=this.positionTarget||this._defaultPositionTarget;if(this.autoFitOnAttach){if(window.getComputedStyle(this).display==="none"){setTimeout(function(){this.fit()}.bind(this))}else{this.fit()}}},fit:function(){this.position();this.constrain();this.center()},_discoverInfo:function(){if(this._fitInfo){return}var target=window.getComputedStyle(this);var sizer=window.getComputedStyle(this.sizingTarget);this._fitInfo={inlineStyle:{top:this.style.top||"",left:this.style.left||"",position:this.style.position||""},sizerInlineStyle:{maxWidth:this.sizingTarget.style.maxWidth||"",maxHeight:this.sizingTarget.style.maxHeight||"",boxSizing:this.sizingTarget.style.boxSizing||""},positionedBy:{vertically:target.top!=="auto"?"top":target.bottom!=="auto"?"bottom":null,horizontally:target.left!=="auto"?"left":target.right!=="auto"?"right":null},sizedBy:{height:sizer.maxHeight!=="none",width:sizer.maxWidth!=="none",minWidth:parseInt(sizer.minWidth,10)||0,minHeight:parseInt(sizer.minHeight,10)||0},margin:{top:parseInt(target.marginTop,10)||0,right:parseInt(target.marginRight,10)||0,bottom:parseInt(target.marginBottom,10)||0,left:parseInt(target.marginLeft,10)||0}};if(this.verticalOffset){this._fitInfo.margin.top=this._fitInfo.margin.bottom=this.verticalOffset;this._fitInfo.inlineStyle.marginTop=this.style.marginTop||"";this._fitInfo.inlineStyle.marginBottom=this.style.marginBottom||"";this.style.marginTop=this.style.marginBottom=this.verticalOffset+"px"}if(this.horizontalOffset){this._fitInfo.margin.left=this._fitInfo.margin.right=this.horizontalOffset;this._fitInfo.inlineStyle.marginLeft=this.style.marginLeft||"";this._fitInfo.inlineStyle.marginRight=this.style.marginRight||"";this.style.marginLeft=this.style.marginRight=this.horizontalOffset+"px"}},resetFit:function(){var info=this._fitInfo||{};for(var property in info.sizerInlineStyle){this.sizingTarget.style[property]=info.sizerInlineStyle[property]}for(var property in info.inlineStyle){this.style[property]=info.inlineStyle[property]}this._fitInfo=null},refit:function(){var scrollLeft=this.sizingTarget.scrollLeft;var scrollTop=this.sizingTarget.scrollTop;this.resetFit();this.fit();this.sizingTarget.scrollLeft=scrollLeft;this.sizingTarget.scrollTop=scrollTop},position:function(){if(!this.horizontalAlign&&!this.verticalAlign){return}this._discoverInfo();this.style.position="fixed";this.sizingTarget.style.boxSizing="border-box";this.style.left="0px";this.style.top="0px";var rect=this.getBoundingClientRect();var positionRect=this.__getNormalizedRect(this.positionTarget);var fitRect=this.__getNormalizedRect(this.fitInto);var margin=this._fitInfo.margin;var size={width:rect.width+margin.left+margin.right,height:rect.height+margin.top+margin.bottom};var position=this.__getPosition(this._localeHorizontalAlign,this.verticalAlign,size,positionRect,fitRect);var left=position.left+margin.left;var top=position.top+margin.top;var right=Math.min(fitRect.right-margin.right,left+rect.width);var bottom=Math.min(fitRect.bottom-margin.bottom,top+rect.height);var minWidth=this._fitInfo.sizedBy.minWidth;var minHeight=this._fitInfo.sizedBy.minHeight;if(left<margin.left){left=margin.left;if(right-left<minWidth){left=right-minWidth}}if(top<margin.top){top=margin.top;if(bottom-top<minHeight){top=bottom-minHeight}}this.sizingTarget.style.maxWidth=right-left+"px";this.sizingTarget.style.maxHeight=bottom-top+"px";this.style.left=left-rect.left+"px";this.style.top=top-rect.top+"px"},constrain:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var info=this._fitInfo;if(!info.positionedBy.vertically){this.style.position="fixed";this.style.top="0px"}if(!info.positionedBy.horizontally){this.style.position="fixed";this.style.left="0px"}this.sizingTarget.style.boxSizing="border-box";var rect=this.getBoundingClientRect();if(!info.sizedBy.height){this.__sizeDimension(rect,info.positionedBy.vertically,"top","bottom","Height")}if(!info.sizedBy.width){this.__sizeDimension(rect,info.positionedBy.horizontally,"left","right","Width")}},_sizeDimension:function(rect,positionedBy,start,end,extent){this.__sizeDimension(rect,positionedBy,start,end,extent)},__sizeDimension:function(rect,positionedBy,start,end,extent){var info=this._fitInfo;var fitRect=this.__getNormalizedRect(this.fitInto);var max=extent==="Width"?fitRect.width:fitRect.height;var flip=positionedBy===end;var offset=flip?max-rect[end]:rect[start];var margin=info.margin[flip?start:end];var offsetExtent="offset"+extent;var sizingOffset=this[offsetExtent]-this.sizingTarget[offsetExtent];this.sizingTarget.style["max"+extent]=max-margin-offset-sizingOffset+"px"},center:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var positionedBy=this._fitInfo.positionedBy;if(positionedBy.vertically&&positionedBy.horizontally){return}this.style.position="fixed";if(!positionedBy.vertically){this.style.top="0px"}if(!positionedBy.horizontally){this.style.left="0px"}var rect=this.getBoundingClientRect();var fitRect=this.__getNormalizedRect(this.fitInto);if(!positionedBy.vertically){var top=fitRect.top-rect.top+(fitRect.height-rect.height)/2;this.style.top=top+"px"}if(!positionedBy.horizontally){var left=fitRect.left-rect.left+(fitRect.width-rect.width)/2;this.style.left=left+"px"}},__getNormalizedRect:function(target){if(target===document.documentElement||target===window){return{top:0,left:0,width:window.innerWidth,height:window.innerHeight,right:window.innerWidth,bottom:window.innerHeight}}return target.getBoundingClientRect()},__getCroppedArea:function(position,size,fitRect){var verticalCrop=Math.min(0,position.top)+Math.min(0,fitRect.bottom-(position.top+size.height));var horizontalCrop=Math.min(0,position.left)+Math.min(0,fitRect.right-(position.left+size.width));return Math.abs(verticalCrop)*size.width+Math.abs(horizontalCrop)*size.height},__getPosition:function(hAlign,vAlign,size,positionRect,fitRect){var positions=[{verticalAlign:"top",horizontalAlign:"left",top:positionRect.top,left:positionRect.left},{verticalAlign:"top",horizontalAlign:"right",top:positionRect.top,left:positionRect.right-size.width},{verticalAlign:"bottom",horizontalAlign:"left",top:positionRect.bottom-size.height,left:positionRect.left},{verticalAlign:"bottom",horizontalAlign:"right",top:positionRect.bottom-size.height,left:positionRect.right-size.width}];if(this.noOverlap){for(var i=0,l=positions.length;i<l;i++){var copy={};for(var key in positions[i]){copy[key]=positions[i][key]}positions.push(copy)}positions[0].top=positions[1].top+=positionRect.height;positions[2].top=positions[3].top-=positionRect.height;positions[4].left=positions[6].left+=positionRect.width;positions[5].left=positions[7].left-=positionRect.width}vAlign=vAlign==="auto"?null:vAlign;hAlign=hAlign==="auto"?null:hAlign;var position;for(var i=0;i<positions.length;i++){var pos=positions[i];if(!this.dynamicAlign&&!this.noOverlap&&pos.verticalAlign===vAlign&&pos.horizontalAlign===hAlign){position=pos;break}var alignOk=(!vAlign||pos.verticalAlign===vAlign)&&(!hAlign||pos.horizontalAlign===hAlign);if(!this.dynamicAlign&&!alignOk){continue}position=position||pos;pos.croppedArea=this.__getCroppedArea(pos,size,fitRect);var diff=pos.croppedArea-position.croppedArea;if(diff<0||diff===0&&alignOk){position=pos}if(position.croppedArea===0&&alignOk){break}}return position}};(function(){"use strict";Polymer({is:"iron-overlay-backdrop",properties:{opened:{reflectToAttribute:true,type:Boolean,value:false,observer:"_openedChanged"}},listeners:{transitionend:"_onTransitionend"},created:function(){this.__openedRaf=null},attached:function(){this.opened&&this._openedChanged(this.opened)},prepare:function(){if(this.opened&&!this.parentNode){Polymer.dom(document.body).appendChild(this)}},open:function(){this.opened=true},close:function(){this.opened=false},complete:function(){if(!this.opened&&this.parentNode===document.body){Polymer.dom(this.parentNode).removeChild(this)}},_onTransitionend:function(event){if(event&&event.target===this){this.complete()}},_openedChanged:function(opened){if(opened){this.prepare()}else{var cs=window.getComputedStyle(this);if(cs.transitionDuration==="0s"||cs.opacity==0){this.complete()}}if(!this.isAttached){return}if(this.__openedRaf){window.cancelAnimationFrame(this.__openedRaf);this.__openedRaf=null}this.scrollTop=this.scrollTop;this.__openedRaf=window.requestAnimationFrame(function(){this.__openedRaf=null;this.toggleClass("opened",this.opened)}.bind(this))}})})();Polymer.IronOverlayManagerClass=function(){this._overlays=[];this._minimumZ=101;this._backdropElement=null;Polymer.Gestures.add(document,"tap",this._onCaptureClick.bind(this));document.addEventListener("focus",this._onCaptureFocus.bind(this),true);document.addEventListener("keydown",this._onCaptureKeyDown.bind(this),true)};Polymer.IronOverlayManagerClass.prototype={constructor:Polymer.IronOverlayManagerClass,get backdropElement(){if(!this._backdropElement){this._backdropElement=document.createElement("iron-overlay-backdrop")}return this._backdropElement},get deepActiveElement(){var active=document.activeElement||document.body;while(active.root&&Polymer.dom(active.root).activeElement){active=Polymer.dom(active.root).activeElement}return active},_bringOverlayAtIndexToFront:function(i){var overlay=this._overlays[i];if(!overlay){return}var lastI=this._overlays.length-1;var currentOverlay=this._overlays[lastI];if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){lastI--}if(i>=lastI){return}var minimumZ=Math.max(this.currentOverlayZ(),this._minimumZ);if(this._getZ(overlay)<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}while(i<lastI){this._overlays[i]=this._overlays[i+1];i++}this._overlays[lastI]=overlay},addOrRemoveOverlay:function(overlay){if(overlay.opened){this.addOverlay(overlay)}else{this.removeOverlay(overlay)}},addOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i>=0){this._bringOverlayAtIndexToFront(i);this.trackBackdrop();return}var insertionIndex=this._overlays.length;var currentOverlay=this._overlays[insertionIndex-1];var minimumZ=Math.max(this._getZ(currentOverlay),this._minimumZ);var newZ=this._getZ(overlay);if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){this._applyOverlayZ(currentOverlay,minimumZ);insertionIndex--;var previousOverlay=this._overlays[insertionIndex-1];minimumZ=Math.max(this._getZ(previousOverlay),this._minimumZ)}if(newZ<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}this._overlays.splice(insertionIndex,0,overlay);this.trackBackdrop()},removeOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i===-1){return}this._overlays.splice(i,1);this.trackBackdrop()},currentOverlay:function(){var i=this._overlays.length-1;return this._overlays[i]},currentOverlayZ:function(){return this._getZ(this.currentOverlay())},ensureMinimumZ:function(minimumZ){this._minimumZ=Math.max(this._minimumZ,minimumZ)},focusOverlay:function(){var current=this.currentOverlay();if(current){current._applyFocus()}},trackBackdrop:function(){var overlay=this._overlayWithBackdrop();if(!overlay&&!this._backdropElement){return}this.backdropElement.style.zIndex=this._getZ(overlay)-1;this.backdropElement.opened=!!overlay},getBackdrops:function(){var backdrops=[];for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){backdrops.push(this._overlays[i])}}return backdrops},backdropZ:function(){return this._getZ(this._overlayWithBackdrop())-1},_overlayWithBackdrop:function(){for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){return this._overlays[i]}}},_getZ:function(overlay){var z=this._minimumZ;if(overlay){var z1=Number(overlay.style.zIndex||window.getComputedStyle(overlay).zIndex);if(z1===z1){z=z1}}return z},_setZ:function(element,z){element.style.zIndex=z},_applyOverlayZ:function(overlay,aboveZ){this._setZ(overlay,aboveZ+2)},_overlayInPath:function(path){path=path||[];for(var i=0;i<path.length;i++){if(path[i]._manager===this){return path[i]}}},_onCaptureClick:function(event){var overlay=this.currentOverlay();if(overlay&&this._overlayInPath(Polymer.dom(event).path)!==overlay){overlay._onCaptureClick(event)}},_onCaptureFocus:function(event){var overlay=this.currentOverlay();if(overlay){overlay._onCaptureFocus(event)}},_onCaptureKeyDown:function(event){var overlay=this.currentOverlay();if(overlay){if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"esc")){overlay._onCaptureEsc(event)}else if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"tab")){overlay._onCaptureTab(event)}}},_shouldBeBehindOverlay:function(overlay1,overlay2){return!overlay1.alwaysOnTop&&overlay2.alwaysOnTop}};Polymer.IronOverlayManager=new Polymer.IronOverlayManagerClass;(function(){"use strict";Polymer.IronOverlayBehaviorImpl={properties:{opened:{observer:"_openedChanged",type:Boolean,value:false,notify:true},canceled:{observer:"_canceledChanged",readOnly:true,type:Boolean,value:false},withBackdrop:{observer:"_withBackdropChanged",type:Boolean},noAutoFocus:{type:Boolean,value:false},noCancelOnEscKey:{type:Boolean,value:false},noCancelOnOutsideClick:{type:Boolean,value:false},closingReason:{type:Object},restoreFocusOnClose:{type:Boolean,value:false},alwaysOnTop:{type:Boolean},_manager:{type:Object,value:Polymer.IronOverlayManager},_focusedChild:{type:Object}},listeners:{"iron-resize":"_onIronResize"},get backdropElement(){return this._manager.backdropElement},get _focusNode(){return this._focusedChild||Polymer.dom(this).querySelector("[autofocus]")||this},get _focusableNodes(){var FOCUSABLE_WITH_DISABLED=["a[href]","area[href]","iframe","[tabindex]","[contentEditable=true]"];var FOCUSABLE_WITHOUT_DISABLED=["input","select","textarea","button"];var selector=FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),')+':not([tabindex="-1"]),'+FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),')+':not([disabled]):not([tabindex="-1"])';var focusables=Polymer.dom(this).querySelectorAll(selector);if(this.tabIndex>=0){focusables.splice(0,0,this)}return focusables.sort(function(a,b){if(a.tabIndex===b.tabIndex){return 0}if(a.tabIndex===0||a.tabIndex>b.tabIndex){return 1}return-1})},ready:function(){this.__isAnimating=false;this.__shouldRemoveTabIndex=false;this.__firstFocusableNode=this.__lastFocusableNode=null;this.__raf=null;this.__restoreFocusNode=null;this._ensureSetup()},attached:function(){if(this.opened){this._openedChanged(this.opened)}this._observer=Polymer.dom(this).observeNodes(this._onNodesChange)},detached:function(){Polymer.dom(this).unobserveNodes(this._observer);this._observer=null;if(this.__raf){window.cancelAnimationFrame(this.__raf);this.__raf=null}this._manager.removeOverlay(this)},toggle:function(){this._setCanceled(false);this.opened=!this.opened},open:function(){this._setCanceled(false);this.opened=true},close:function(){this._setCanceled(false);this.opened=false},cancel:function(event){var cancelEvent=this.fire("iron-overlay-canceled",event,{cancelable:true});if(cancelEvent.defaultPrevented){return}this._setCanceled(true);this.opened=false},_ensureSetup:function(){if(this._overlaySetup){return}this._overlaySetup=true;this.style.outline="none";this.style.display="none"},_openedChanged:function(opened){if(opened){this.removeAttribute("aria-hidden")}else{this.setAttribute("aria-hidden","true")}if(!this.isAttached){return}this.__isAnimating=true;this.__onNextAnimationFrame(this.__openedChanged)},_canceledChanged:function(){this.closingReason=this.closingReason||{};this.closingReason.canceled=this.canceled},_withBackdropChanged:function(){if(this.withBackdrop&&!this.hasAttribute("tabindex")){this.setAttribute("tabindex","-1");this.__shouldRemoveTabIndex=true}else if(this.__shouldRemoveTabIndex){this.removeAttribute("tabindex");this.__shouldRemoveTabIndex=false}if(this.opened&&this.isAttached){this._manager.trackBackdrop()}},_prepareRenderOpened:function(){this.__restoreFocusNode=this._manager.deepActiveElement;this._preparePositioning();this.refit();this._finishPositioning();if(this.noAutoFocus&&document.activeElement===this._focusNode){this._focusNode.blur();this.__restoreFocusNode.focus()}},_renderOpened:function(){this._finishRenderOpened()},_renderClosed:function(){this._finishRenderClosed()},_finishRenderOpened:function(){this.notifyResize();this.__isAnimating=false;var focusableNodes=this._focusableNodes;this.__firstFocusableNode=focusableNodes[0];this.__lastFocusableNode=focusableNodes[focusableNodes.length-1];this.fire("iron-overlay-opened")},_finishRenderClosed:function(){this.style.display="none";this.style.zIndex="";this.notifyResize();this.__isAnimating=false;this.fire("iron-overlay-closed",this.closingReason)},_preparePositioning:function(){this.style.transition=this.style.webkitTransition="none";this.style.transform=this.style.webkitTransform="none";this.style.display=""},_finishPositioning:function(){this.style.display="none";this.scrollTop=this.scrollTop;this.style.transition=this.style.webkitTransition="";this.style.transform=this.style.webkitTransform="";this.style.display="";this.scrollTop=this.scrollTop},_applyFocus:function(){if(this.opened){if(!this.noAutoFocus){this._focusNode.focus()}}else{this._focusNode.blur();this._focusedChild=null;if(this.restoreFocusOnClose&&this.__restoreFocusNode){this.__restoreFocusNode.focus()}this.__restoreFocusNode=null;var currentOverlay=this._manager.currentOverlay();if(currentOverlay&&this!==currentOverlay){currentOverlay._applyFocus()}}},_onCaptureClick:function(event){if(!this.noCancelOnOutsideClick){this.cancel(event)}},_onCaptureFocus:function(event){if(!this.withBackdrop){return}var path=Polymer.dom(event).path;if(path.indexOf(this)===-1){event.stopPropagation();this._applyFocus()}else{this._focusedChild=path[0]}},_onCaptureEsc:function(event){if(!this.noCancelOnEscKey){this.cancel(event)}},_onCaptureTab:function(event){if(!this.withBackdrop){return}var shift=event.shiftKey;var nodeToCheck=shift?this.__firstFocusableNode:this.__lastFocusableNode;var nodeToSet=shift?this.__lastFocusableNode:this.__firstFocusableNode;var shouldWrap=false;if(nodeToCheck===nodeToSet){shouldWrap=true}else{var focusedNode=this._manager.deepActiveElement;shouldWrap=focusedNode===nodeToCheck||focusedNode===this}if(shouldWrap){event.preventDefault();this._focusedChild=nodeToSet;this._applyFocus()}},_onIronResize:function(){if(this.opened&&!this.__isAnimating){this.__onNextAnimationFrame(this.refit)}},_onNodesChange:function(){if(this.opened&&!this.__isAnimating){this.notifyResize()}},__openedChanged:function(){if(this.opened){this._prepareRenderOpened();this._manager.addOverlay(this);this._applyFocus();this._renderOpened()}else{this._manager.removeOverlay(this);this._applyFocus();this._renderClosed()}},__onNextAnimationFrame:function(callback){if(this.__raf){window.cancelAnimationFrame(this.__raf)}var self=this;this.__raf=window.requestAnimationFrame(function nextAnimationFrame(){self.__raf=null;callback.call(self)})}};Polymer.IronOverlayBehavior=[Polymer.IronFitBehavior,Polymer.IronResizableBehavior,Polymer.IronOverlayBehaviorImpl]})();Polymer.NeonAnimatableBehavior={properties:{animationConfig:{type:Object},entryAnimation:{observer:"_entryAnimationChanged",type:String},exitAnimation:{observer:"_exitAnimationChanged",type:String}},_entryAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["entry"]=[{name:this.entryAnimation,node:this}]},_exitAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["exit"]=[{name:this.exitAnimation,node:this}]},_copyProperties:function(config1,config2){for(var property in config2){config1[property]=config2[property]}},_cloneConfig:function(config){var clone={isClone:true};this._copyProperties(clone,config);return clone},_getAnimationConfigRecursive:function(type,map,allConfigs){if(!this.animationConfig){return}if(this.animationConfig.value&&typeof this.animationConfig.value==="function"){this._warn(this._logf("playAnimation","Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));return}var thisConfig;if(type){thisConfig=this.animationConfig[type]}else{thisConfig=this.animationConfig}if(!Array.isArray(thisConfig)){thisConfig=[thisConfig]}if(thisConfig){for(var config,index=0;config=thisConfig[index];index++){if(config.animatable){config.animatable._getAnimationConfigRecursive(config.type||type,map,allConfigs)}else{if(config.id){var cachedConfig=map[config.id];if(cachedConfig){if(!cachedConfig.isClone){map[config.id]=this._cloneConfig(cachedConfig);cachedConfig=map[config.id]}this._copyProperties(cachedConfig,config)}else{map[config.id]=config}}else{allConfigs.push(config)}}}}},getAnimationConfig:function(type){var map={};var allConfigs=[];this._getAnimationConfigRecursive(type,map,allConfigs);for(var key in map){allConfigs.push(map[key])}return allConfigs}};Polymer.NeonAnimationRunnerBehaviorImpl={_configureAnimations:function(configs){var results=[];if(configs.length>0){for(var config,index=0;config=configs[index];index++){var neonAnimation=document.createElement(config.name);if(neonAnimation.isNeonAnimation){var result=null;try{result=neonAnimation.configure(config);if(typeof result.cancel!="function"){result=document.timeline.play(result)}}catch(e){result=null;console.warn("Couldnt play","(",config.name,").",e)}if(result){results.push({neonAnimation:neonAnimation,config:config,animation:result})}}else{console.warn(this.is+":",config.name,"not found!")}}}return results},_shouldComplete:function(activeEntries){var finished=true;for(var i=0;i<activeEntries.length;i++){if(activeEntries[i].animation.playState!="finished"){finished=false;break}}return finished},_complete:function(activeEntries){for(var i=0;i<activeEntries.length;i++){activeEntries[i].neonAnimation.complete(activeEntries[i].config)}for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.cancel()}},playAnimation:function(type,cookie){var configs=this.getAnimationConfig(type);if(!configs){return}this._active=this._active||{};if(this._active[type]){this._complete(this._active[type]);delete this._active[type]}var activeEntries=this._configureAnimations(configs);if(activeEntries.length==0){this.fire("neon-animation-finish",cookie,{bubbles:false});return}this._active[type]=activeEntries;for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.onfinish=function(){if(this._shouldComplete(activeEntries)){this._complete(activeEntries);delete this._active[type];this.fire("neon-animation-finish",cookie,{bubbles:false})}}.bind(this)}},cancelAnimation:function(){for(var k in this._animations){this._animations[k].cancel()}this._animations={}}};Polymer.NeonAnimationRunnerBehavior=[Polymer.NeonAnimatableBehavior,Polymer.NeonAnimationRunnerBehaviorImpl];Polymer.NeonAnimationBehavior={properties:{animationTiming:{type:Object,value:function(){return{duration:500,easing:"cubic-bezier(0.4, 0, 0.2, 1)",fill:"both"}}}},isNeonAnimation:true,timingFromConfig:function(config){if(config.timing){for(var property in config.timing){this.animationTiming[property]=config.timing[property]}}return this.animationTiming},setPrefixedProperty:function(node,property,value){var map={transform:["webkitTransform"],transformOrigin:["mozTransformOrigin","webkitTransformOrigin"]};var prefixes=map[property];for(var prefix,index=0;prefix=prefixes[index];index++){node.style[prefix]=value}node.style[property]=value},complete:function(){}};Polymer({is:"opaque-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"1"}],this.timingFromConfig(config));node.style.opacity="0";return this._effect},complete:function(config){config.node.style.opacity=""}});(function(){"use strict";var LAST_TOUCH_POSITION={pageX:0,pageY:0};var ROOT_TARGET=null;var SCROLLABLE_NODES=[];Polymer.IronDropdownScrollManager={get currentLockingElement(){return this._lockingElements[this._lockingElements.length-1]},elementIsScrollLocked:function(element){var currentLockingElement=this.currentLockingElement;if(currentLockingElement===undefined)return false;var scrollLocked;if(this._hasCachedLockedElement(element)){return true}if(this._hasCachedUnlockedElement(element)){return false}scrollLocked=!!currentLockingElement&&currentLockingElement!==element&&!this._composedTreeContains(currentLockingElement,element);if(scrollLocked){this._lockedElementCache.push(element)}else{this._unlockedElementCache.push(element)}return scrollLocked},pushScrollLock:function(element){if(this._lockingElements.indexOf(element)>=0){return}if(this._lockingElements.length===0){this._lockScrollInteractions()}this._lockingElements.push(element);this._lockedElementCache=[];this._unlockedElementCache=[]},removeScrollLock:function(element){var index=this._lockingElements.indexOf(element);if(index===-1){return}this._lockingElements.splice(index,1);this._lockedElementCache=[];this._unlockedElementCache=[];if(this._lockingElements.length===0){this._unlockScrollInteractions()}},_lockingElements:[],_lockedElementCache:null,_unlockedElementCache:null,_hasCachedLockedElement:function(element){return this._lockedElementCache.indexOf(element)>-1},_hasCachedUnlockedElement:function(element){return this._unlockedElementCache.indexOf(element)>-1},_composedTreeContains:function(element,child){var contentElements;var distributedNodes;var contentIndex;var nodeIndex;if(element.contains(child)){return true}contentElements=Polymer.dom(element).querySelectorAll("content");for(contentIndex=0;contentIndex<contentElements.length;++contentIndex){distributedNodes=Polymer.dom(contentElements[contentIndex]).getDistributedNodes();for(nodeIndex=0;nodeIndex<distributedNodes.length;++nodeIndex){if(this._composedTreeContains(distributedNodes[nodeIndex],child)){return true}}}return false},_scrollInteractionHandler:function(event){if(event.cancelable&&this._shouldPreventScrolling(event)){event.preventDefault()}if(event.targetTouches){var touch=event.targetTouches[0];LAST_TOUCH_POSITION.pageX=touch.pageX;LAST_TOUCH_POSITION.pageY=touch.pageY}},_lockScrollInteractions:function(){this._boundScrollHandler=this._boundScrollHandler||this._scrollInteractionHandler.bind(this);document.addEventListener("wheel",this._boundScrollHandler,true);document.addEventListener("mousewheel",this._boundScrollHandler,true);document.addEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.addEventListener("touchstart",this._boundScrollHandler,true);
 
-var HistoryGroup;
-
-Polymer({
-  is: 'history-grouped-list',
-  behaviors: [ HistoryListBehavior ],
-  properties: {
-    historyData: {
-      type: Array
-    },
-    groupedHistoryData_: {
-      type: Array
-    },
-    searchedTerm: {
-      type: String,
-      value: ''
-    },
-    range: {
-      type: Number
-    },
-    queryStartTime: String,
-    queryEndTime: String
-  },
-  observers: [ 'updateGroupedHistoryData_(range, historyData)' ],
-  createHistoryDomains_: function(visits) {
-    var domainIndexes = {};
-    var domains = [];
-    for (var i = 0, visit; visit = visits[i]; i++) {
-      var domain = visit.domain;
-      if (domainIndexes[domain] == undefined) {
-        domainIndexes[domain] = domains.length;
-        domains.push({
-          domain: domain,
-          visits: [],
-          expanded: false,
-          rendered: false
-        });
-      }
-      domains[domainIndexes[domain]].visits.push(visit);
-    }
-    var sortByVisits = function(a, b) {
-      return b.visits.length - a.visits.length;
-    };
-    domains.sort(sortByVisits);
-    return domains;
-  },
-  updateGroupedHistoryData_: function() {
-    if (this.historyData.length == 0) {
-      this.groupedHistoryData_ = [];
-      return;
-    }
-    if (this.range == HistoryRange.WEEK) {
-      var days = [];
-      var currentDayVisits = [ this.historyData[0] ];
-      var pushCurrentDay = function() {
-        days.push({
-          title: this.searchedTerm ? currentDayVisits[0].dateShort : currentDayVisits[0].dateRelativeDay,
-          domains: this.createHistoryDomains_(currentDayVisits)
-        });
-      }.bind(this);
-      var visitsSameDay = function(a, b) {
-        if (this.searchedTerm) return a.dateShort == b.dateShort;
-        return a.dateRelativeDay == b.dateRelativeDay;
-      }.bind(this);
-      for (var i = 1; i < this.historyData.length; i++) {
-        var visit = this.historyData[i];
-        if (!visitsSameDay(visit, currentDayVisits[0])) {
-          pushCurrentDay();
-          currentDayVisits = [];
-        }
-        currentDayVisits.push(visit);
-      }
-      pushCurrentDay();
-      this.groupedHistoryData_ = days;
-    } else if (this.range == HistoryRange.MONTH) {
-      this.groupedHistoryData_ = [ {
-        title: this.queryStartTime + ' – ' + this.queryEndTime,
-        domains: this.createHistoryDomains_(this.historyData)
-      } ];
-    }
-  },
-  toggleDomainExpanded_: function(e) {
-    var collapse = e.currentTarget.parentNode.querySelector('iron-collapse');
-    e.model.set('domain.rendered', true);
-    setTimeout(function() {
-      collapse.toggle();
-    }, 0);
-  },
-  needsTimeGap_: function(groupIndex, domainIndex, itemIndex) {
-    var visits = this.groupedHistoryData_[groupIndex].domains[domainIndex].visits;
-    return md_history.HistoryItem.needsTimeGap(visits, itemIndex, this.searchedTerm);
-  },
-  pathForItem_: function(groupIndex, domainIndex, itemIndex) {
-    return [ 'groupedHistoryData_', groupIndex, 'domains', domainIndex, 'visits', itemIndex ].join('.');
-  },
-  getWebsiteIconStyle_: function(domain) {
-    return 'background-image: ' + cr.icon.getFavicon(domain.visits[0].url);
-  },
-  getDropdownIcon_: function(expanded) {
-    return expanded ? 'cr:expand-less' : 'cr:expand-more';
-  }
-});
-
-Polymer.PaperButtonBehaviorImpl = {
-  properties: {
-    elevation: {
-      type: Number,
-      reflectToAttribute: true,
-      readOnly: true
-    }
-  },
-  observers: [ '_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)', '_computeKeyboardClass(receivedFocusFromKeyboard)' ],
-  hostAttributes: {
-    role: 'button',
-    tabindex: '0',
-    animated: true
-  },
-  _calculateElevation: function() {
-    var e = 1;
-    if (this.disabled) {
-      e = 0;
-    } else if (this.active || this.pressed) {
-      e = 4;
-    } else if (this.receivedFocusFromKeyboard) {
-      e = 3;
-    }
-    this._setElevation(e);
-  },
-  _computeKeyboardClass: function(receivedFocusFromKeyboard) {
-    this.toggleClass('keyboard-focus', receivedFocusFromKeyboard);
-  },
-  _spaceKeyDownHandler: function(event) {
-    Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this, event);
-    if (this.hasRipple() && this.getRipple().ripples.length < 1) {
-      this._ripple.uiDownAction();
-    }
-  },
-  _spaceKeyUpHandler: function(event) {
-    Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this, event);
-    if (this.hasRipple()) {
-      this._ripple.uiUpAction();
-    }
-  }
-};
-
-Polymer.PaperButtonBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperRippleBehavior, Polymer.PaperButtonBehaviorImpl ];
-
-Polymer({
-  is: 'paper-button',
-  behaviors: [ Polymer.PaperButtonBehavior ],
-  properties: {
-    raised: {
-      type: Boolean,
-      reflectToAttribute: true,
-      value: false,
-      observer: '_calculateElevation'
-    }
-  },
-  _calculateElevation: function() {
-    if (!this.raised) {
-      this._setElevation(0);
-    } else {
-      Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this);
-    }
-  }
-});
-
-Polymer.PaperItemBehaviorImpl = {
-  hostAttributes: {
-    role: 'option',
-    tabindex: '0'
-  }
-};
-
-Polymer.PaperItemBehavior = [ Polymer.IronButtonState, Polymer.IronControlState, Polymer.PaperItemBehaviorImpl ];
-
-Polymer({
-  is: 'paper-item',
-  behaviors: [ Polymer.PaperItemBehavior ]
-});
-
-Polymer.IronFitBehavior = {
-  properties: {
-    sizingTarget: {
-      type: Object,
-      value: function() {
-        return this;
-      }
-    },
-    fitInto: {
-      type: Object,
-      value: window
-    },
-    noOverlap: {
-      type: Boolean
-    },
-    positionTarget: {
-      type: Element
-    },
-    horizontalAlign: {
-      type: String
-    },
-    verticalAlign: {
-      type: String
-    },
-    dynamicAlign: {
-      type: Boolean
-    },
-    horizontalOffset: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    verticalOffset: {
-      type: Number,
-      value: 0,
-      notify: true
-    },
-    autoFitOnAttach: {
-      type: Boolean,
-      value: false
-    },
-    _fitInfo: {
-      type: Object
-    }
-  },
-  get _fitWidth() {
-    var fitWidth;
-    if (this.fitInto === window) {
-      fitWidth = this.fitInto.innerWidth;
-    } else {
-      fitWidth = this.fitInto.getBoundingClientRect().width;
-    }
-    return fitWidth;
-  },
-  get _fitHeight() {
-    var fitHeight;
-    if (this.fitInto === window) {
-      fitHeight = this.fitInto.innerHeight;
-    } else {
-      fitHeight = this.fitInto.getBoundingClientRect().height;
-    }
-    return fitHeight;
-  },
-  get _fitLeft() {
-    var fitLeft;
-    if (this.fitInto === window) {
-      fitLeft = 0;
-    } else {
-      fitLeft = this.fitInto.getBoundingClientRect().left;
-    }
-    return fitLeft;
-  },
-  get _fitTop() {
-    var fitTop;
-    if (this.fitInto === window) {
-      fitTop = 0;
-    } else {
-      fitTop = this.fitInto.getBoundingClientRect().top;
-    }
-    return fitTop;
-  },
-  get _defaultPositionTarget() {
-    var parent = Polymer.dom(this).parentNode;
-    if (parent && parent.nodeType === Node.DOCUMENT_FRAGMENT_NODE) {
-      parent = parent.host;
-    }
-    return parent;
-  },
-  get _localeHorizontalAlign() {
-    if (this._isRTL) {
-      if (this.horizontalAlign === 'right') {
-        return 'left';
-      }
-      if (this.horizontalAlign === 'left') {
-        return 'right';
-      }
-    }
-    return this.horizontalAlign;
-  },
-  attached: function() {
-    this._isRTL = window.getComputedStyle(this).direction == 'rtl';
-    this.positionTarget = this.positionTarget || this._defaultPositionTarget;
-    if (this.autoFitOnAttach) {
-      if (window.getComputedStyle(this).display === 'none') {
-        setTimeout(function() {
-          this.fit();
-        }.bind(this));
-      } else {
-        this.fit();
-      }
-    }
-  },
-  fit: function() {
-    this.position();
-    this.constrain();
-    this.center();
-  },
-  _discoverInfo: function() {
-    if (this._fitInfo) {
-      return;
-    }
-    var target = window.getComputedStyle(this);
-    var sizer = window.getComputedStyle(this.sizingTarget);
-    this._fitInfo = {
-      inlineStyle: {
-        top: this.style.top || '',
-        left: this.style.left || '',
-        position: this.style.position || ''
-      },
-      sizerInlineStyle: {
-        maxWidth: this.sizingTarget.style.maxWidth || '',
-        maxHeight: this.sizingTarget.style.maxHeight || '',
-        boxSizing: this.sizingTarget.style.boxSizing || ''
-      },
-      positionedBy: {
-        vertically: target.top !== 'auto' ? 'top' : target.bottom !== 'auto' ? 'bottom' : null,
-        horizontally: target.left !== 'auto' ? 'left' : target.right !== 'auto' ? 'right' : null
-      },
-      sizedBy: {
-        height: sizer.maxHeight !== 'none',
-        width: sizer.maxWidth !== 'none',
-        minWidth: parseInt(sizer.minWidth, 10) || 0,
-        minHeight: parseInt(sizer.minHeight, 10) || 0
-      },
-      margin: {
-        top: parseInt(target.marginTop, 10) || 0,
-        right: parseInt(target.marginRight, 10) || 0,
-        bottom: parseInt(target.marginBottom, 10) || 0,
-        left: parseInt(target.marginLeft, 10) || 0
-      }
-    };
-    if (this.verticalOffset) {
-      this._fitInfo.margin.top = this._fitInfo.margin.bottom = this.verticalOffset;
-      this._fitInfo.inlineStyle.marginTop = this.style.marginTop || '';
-      this._fitInfo.inlineStyle.marginBottom = this.style.marginBottom || '';
-      this.style.marginTop = this.style.marginBottom = this.verticalOffset + 'px';
-    }
-    if (this.horizontalOffset) {
-      this._fitInfo.margin.left = this._fitInfo.margin.right = this.horizontalOffset;
-      this._fitInfo.inlineStyle.marginLeft = this.style.marginLeft || '';
-      this._fitInfo.inlineStyle.marginRight = this.style.marginRight || '';
-      this.style.marginLeft = this.style.marginRight = this.horizontalOffset + 'px';
-    }
-  },
-  resetFit: function() {
-    var info = this._fitInfo || {};
-    for (var property in info.sizerInlineStyle) {
-      this.sizingTarget.style[property] = info.sizerInlineStyle[property];
-    }
-    for (var property in info.inlineStyle) {
-      this.style[property] = info.inlineStyle[property];
-    }
-    this._fitInfo = null;
-  },
-  refit: function() {
-    var scrollLeft = this.sizingTarget.scrollLeft;
-    var scrollTop = this.sizingTarget.scrollTop;
-    this.resetFit();
-    this.fit();
-    this.sizingTarget.scrollLeft = scrollLeft;
-    this.sizingTarget.scrollTop = scrollTop;
-  },
-  position: function() {
-    if (!this.horizontalAlign && !this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    this.style.position = 'fixed';
-    this.sizingTarget.style.boxSizing = 'border-box';
-    this.style.left = '0px';
-    this.style.top = '0px';
-    var rect = this.getBoundingClientRect();
-    var positionRect = this.__getNormalizedRect(this.positionTarget);
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    var margin = this._fitInfo.margin;
-    var size = {
-      width: rect.width + margin.left + margin.right,
-      height: rect.height + margin.top + margin.bottom
-    };
-    var position = this.__getPosition(this._localeHorizontalAlign, this.verticalAlign, size, positionRect, fitRect);
-    var left = position.left + margin.left;
-    var top = position.top + margin.top;
-    var right = Math.min(fitRect.right - margin.right, left + rect.width);
-    var bottom = Math.min(fitRect.bottom - margin.bottom, top + rect.height);
-    var minWidth = this._fitInfo.sizedBy.minWidth;
-    var minHeight = this._fitInfo.sizedBy.minHeight;
-    if (left < margin.left) {
-      left = margin.left;
-      if (right - left < minWidth) {
-        left = right - minWidth;
-      }
-    }
-    if (top < margin.top) {
-      top = margin.top;
-      if (bottom - top < minHeight) {
-        top = bottom - minHeight;
-      }
-    }
-    this.sizingTarget.style.maxWidth = right - left + 'px';
-    this.sizingTarget.style.maxHeight = bottom - top + 'px';
-    this.style.left = left - rect.left + 'px';
-    this.style.top = top - rect.top + 'px';
-  },
-  constrain: function() {
-    if (this.horizontalAlign || this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    var info = this._fitInfo;
-    if (!info.positionedBy.vertically) {
-      this.style.position = 'fixed';
-      this.style.top = '0px';
-    }
-    if (!info.positionedBy.horizontally) {
-      this.style.position = 'fixed';
-      this.style.left = '0px';
-    }
-    this.sizingTarget.style.boxSizing = 'border-box';
-    var rect = this.getBoundingClientRect();
-    if (!info.sizedBy.height) {
-      this.__sizeDimension(rect, info.positionedBy.vertically, 'top', 'bottom', 'Height');
-    }
-    if (!info.sizedBy.width) {
-      this.__sizeDimension(rect, info.positionedBy.horizontally, 'left', 'right', 'Width');
-    }
-  },
-  _sizeDimension: function(rect, positionedBy, start, end, extent) {
-    this.__sizeDimension(rect, positionedBy, start, end, extent);
-  },
-  __sizeDimension: function(rect, positionedBy, start, end, extent) {
-    var info = this._fitInfo;
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    var max = extent === 'Width' ? fitRect.width : fitRect.height;
-    var flip = positionedBy === end;
-    var offset = flip ? max - rect[end] : rect[start];
-    var margin = info.margin[flip ? start : end];
-    var offsetExtent = 'offset' + extent;
-    var sizingOffset = this[offsetExtent] - this.sizingTarget[offsetExtent];
-    this.sizingTarget.style['max' + extent] = max - margin - offset - sizingOffset + 'px';
-  },
-  center: function() {
-    if (this.horizontalAlign || this.verticalAlign) {
-      return;
-    }
-    this._discoverInfo();
-    var positionedBy = this._fitInfo.positionedBy;
-    if (positionedBy.vertically && positionedBy.horizontally) {
-      return;
-    }
-    this.style.position = 'fixed';
-    if (!positionedBy.vertically) {
-      this.style.top = '0px';
-    }
-    if (!positionedBy.horizontally) {
-      this.style.left = '0px';
-    }
-    var rect = this.getBoundingClientRect();
-    var fitRect = this.__getNormalizedRect(this.fitInto);
-    if (!positionedBy.vertically) {
-      var top = fitRect.top - rect.top + (fitRect.height - rect.height) / 2;
-      this.style.top = top + 'px';
-    }
-    if (!positionedBy.horizontally) {
-      var left = fitRect.left - rect.left + (fitRect.width - rect.width) / 2;
-      this.style.left = left + 'px';
-    }
-  },
-  __getNormalizedRect: function(target) {
-    if (target === document.documentElement || target === window) {
-      return {
-        top: 0,
-        left: 0,
-        width: window.innerWidth,
-        height: window.innerHeight,
-        right: window.innerWidth,
-        bottom: window.innerHeight
-      };
-    }
-    return target.getBoundingClientRect();
-  },
-  __getCroppedArea: function(position, size, fitRect) {
-    var verticalCrop = Math.min(0, position.top) + Math.min(0, fitRect.bottom - (position.top + size.height));
-    var horizontalCrop = Math.min(0, position.left) + Math.min(0, fitRect.right - (position.left + size.width));
-    return Math.abs(verticalCrop) * size.width + Math.abs(horizontalCrop) * size.height;
-  },
-  __getPosition: function(hAlign, vAlign, size, positionRect, fitRect) {
-    var positions = [ {
-      verticalAlign: 'top',
-      horizontalAlign: 'left',
-      top: positionRect.top,
-      left: positionRect.left
-    }, {
-      verticalAlign: 'top',
-      horizontalAlign: 'right',
-      top: positionRect.top,
-      left: positionRect.right - size.width
-    }, {
-      verticalAlign: 'bottom',
-      horizontalAlign: 'left',
-      top: positionRect.bottom - size.height,
-      left: positionRect.left
-    }, {
-      verticalAlign: 'bottom',
-      horizontalAlign: 'right',
-      top: positionRect.bottom - size.height,
-      left: positionRect.right - size.width
-    } ];
-    if (this.noOverlap) {
-      for (var i = 0, l = positions.length; i < l; i++) {
-        var copy = {};
-        for (var key in positions[i]) {
-          copy[key] = positions[i][key];
-        }
-        positions.push(copy);
-      }
-      positions[0].top = positions[1].top += positionRect.height;
-      positions[2].top = positions[3].top -= positionRect.height;
-      positions[4].left = positions[6].left += positionRect.width;
-      positions[5].left = positions[7].left -= positionRect.width;
-    }
-    vAlign = vAlign === 'auto' ? null : vAlign;
-    hAlign = hAlign === 'auto' ? null : hAlign;
-    var position;
-    for (var i = 0; i < positions.length; i++) {
-      var pos = positions[i];
-      if (!this.dynamicAlign && !this.noOverlap && pos.verticalAlign === vAlign && pos.horizontalAlign === hAlign) {
-        position = pos;
-        break;
-      }
-      var alignOk = (!vAlign || pos.verticalAlign === vAlign) && (!hAlign || pos.horizontalAlign === hAlign);
-      if (!this.dynamicAlign && !alignOk) {
-        continue;
-      }
-      position = position || pos;
-      pos.croppedArea = this.__getCroppedArea(pos, size, fitRect);
-      var diff = pos.croppedArea - position.croppedArea;
-      if (diff < 0 || diff === 0 && alignOk) {
-        position = pos;
-      }
-      if (position.croppedArea === 0 && alignOk) {
-        break;
-      }
-    }
-    return position;
-  }
-};
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-overlay-backdrop',
-    properties: {
-      opened: {
-        reflectToAttribute: true,
-        type: Boolean,
-        value: false,
-        observer: '_openedChanged'
-      }
-    },
-    listeners: {
-      transitionend: '_onTransitionend'
-    },
-    created: function() {
-      this.__openedRaf = null;
-    },
-    attached: function() {
-      this.opened && this._openedChanged(this.opened);
-    },
-    prepare: function() {
-      if (this.opened && !this.parentNode) {
-        Polymer.dom(document.body).appendChild(this);
-      }
-    },
-    open: function() {
-      this.opened = true;
-    },
-    close: function() {
-      this.opened = false;
-    },
-    complete: function() {
-      if (!this.opened && this.parentNode === document.body) {
-        Polymer.dom(this.parentNode).removeChild(this);
-      }
-    },
-    _onTransitionend: function(event) {
-      if (event && event.target === this) {
-        this.complete();
-      }
-    },
-    _openedChanged: function(opened) {
-      if (opened) {
-        this.prepare();
-      } else {
-        var cs = window.getComputedStyle(this);
-        if (cs.transitionDuration === '0s' || cs.opacity == 0) {
-          this.complete();
-        }
-      }
-      if (!this.isAttached) {
-        return;
-      }
-      if (this.__openedRaf) {
-        window.cancelAnimationFrame(this.__openedRaf);
-        this.__openedRaf = null;
-      }
-      this.scrollTop = this.scrollTop;
-      this.__openedRaf = window.requestAnimationFrame(function() {
-        this.__openedRaf = null;
-        this.toggleClass('opened', this.opened);
-      }.bind(this));
-    }
-  });
-})();
-
-Polymer.IronOverlayManagerClass = function() {
-  this._overlays = [];
-  this._minimumZ = 101;
-  this._backdropElement = null;
-  Polymer.Gestures.add(document, 'tap', this._onCaptureClick.bind(this));
-  document.addEventListener('focus', this._onCaptureFocus.bind(this), true);
-  document.addEventListener('keydown', this._onCaptureKeyDown.bind(this), true);
-};
-
-Polymer.IronOverlayManagerClass.prototype = {
-  constructor: Polymer.IronOverlayManagerClass,
-  get backdropElement() {
-    if (!this._backdropElement) {
-      this._backdropElement = document.createElement('iron-overlay-backdrop');
-    }
-    return this._backdropElement;
-  },
-  get deepActiveElement() {
-    var active = document.activeElement || document.body;
-    while (active.root && Polymer.dom(active.root).activeElement) {
-      active = Polymer.dom(active.root).activeElement;
-    }
-    return active;
-  },
-  _bringOverlayAtIndexToFront: function(i) {
-    var overlay = this._overlays[i];
-    if (!overlay) {
-      return;
-    }
-    var lastI = this._overlays.length - 1;
-    var currentOverlay = this._overlays[lastI];
-    if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
-      lastI--;
-    }
-    if (i >= lastI) {
-      return;
-    }
-    var minimumZ = Math.max(this.currentOverlayZ(), this._minimumZ);
-    if (this._getZ(overlay) <= minimumZ) {
-      this._applyOverlayZ(overlay, minimumZ);
-    }
-    while (i < lastI) {
-      this._overlays[i] = this._overlays[i + 1];
-      i++;
-    }
-    this._overlays[lastI] = overlay;
-  },
-  addOrRemoveOverlay: function(overlay) {
-    if (overlay.opened) {
-      this.addOverlay(overlay);
-    } else {
-      this.removeOverlay(overlay);
-    }
-  },
-  addOverlay: function(overlay) {
-    var i = this._overlays.indexOf(overlay);
-    if (i >= 0) {
-      this._bringOverlayAtIndexToFront(i);
-      this.trackBackdrop();
-      return;
-    }
-    var insertionIndex = this._overlays.length;
-    var currentOverlay = this._overlays[insertionIndex - 1];
-    var minimumZ = Math.max(this._getZ(currentOverlay), this._minimumZ);
-    var newZ = this._getZ(overlay);
-    if (currentOverlay && this._shouldBeBehindOverlay(overlay, currentOverlay)) {
-      this._applyOverlayZ(currentOverlay, minimumZ);
-      insertionIndex--;
-      var previousOverlay = this._overlays[insertionIndex - 1];
-      minimumZ = Math.max(this._getZ(previousOverlay), this._minimumZ);
-    }
-    if (newZ <= minimumZ) {
-      this._applyOverlayZ(overlay, minimumZ);
-    }
-    this._overlays.splice(insertionIndex, 0, overlay);
-    this.trackBackdrop();
-  },
-  removeOverlay: function(overlay) {
-    var i = this._overlays.indexOf(overlay);
-    if (i === -1) {
-      return;
-    }
-    this._overlays.splice(i, 1);
-    this.trackBackdrop();
-  },
-  currentOverlay: function() {
-    var i = this._overlays.length - 1;
-    return this._overlays[i];
-  },
-  currentOverlayZ: function() {
-    return this._getZ(this.currentOverlay());
-  },
-  ensureMinimumZ: function(minimumZ) {
-    this._minimumZ = Math.max(this._minimumZ, minimumZ);
-  },
-  focusOverlay: function() {
-    var current = this.currentOverlay();
-    if (current) {
-      current._applyFocus();
-    }
-  },
-  trackBackdrop: function() {
-    var overlay = this._overlayWithBackdrop();
-    if (!overlay && !this._backdropElement) {
-      return;
-    }
-    this.backdropElement.style.zIndex = this._getZ(overlay) - 1;
-    this.backdropElement.opened = !!overlay;
-  },
-  getBackdrops: function() {
-    var backdrops = [];
-    for (var i = 0; i < this._overlays.length; i++) {
-      if (this._overlays[i].withBackdrop) {
-        backdrops.push(this._overlays[i]);
-      }
-    }
-    return backdrops;
-  },
-  backdropZ: function() {
-    return this._getZ(this._overlayWithBackdrop()) - 1;
-  },
-  _overlayWithBackdrop: function() {
-    for (var i = 0; i < this._overlays.length; i++) {
-      if (this._overlays[i].withBackdrop) {
-        return this._overlays[i];
-      }
-    }
-  },
-  _getZ: function(overlay) {
-    var z = this._minimumZ;
-    if (overlay) {
-      var z1 = Number(overlay.style.zIndex || window.getComputedStyle(overlay).zIndex);
-      if (z1 === z1) {
-        z = z1;
-      }
-    }
-    return z;
-  },
-  _setZ: function(element, z) {
-    element.style.zIndex = z;
-  },
-  _applyOverlayZ: function(overlay, aboveZ) {
-    this._setZ(overlay, aboveZ + 2);
-  },
-  _overlayInPath: function(path) {
-    path = path || [];
-    for (var i = 0; i < path.length; i++) {
-      if (path[i]._manager === this) {
-        return path[i];
-      }
-    }
-  },
-  _onCaptureClick: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay && this._overlayInPath(Polymer.dom(event).path) !== overlay) {
-      overlay._onCaptureClick(event);
-    }
-  },
-  _onCaptureFocus: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay) {
-      overlay._onCaptureFocus(event);
-    }
-  },
-  _onCaptureKeyDown: function(event) {
-    var overlay = this.currentOverlay();
-    if (overlay) {
-      if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'esc')) {
-        overlay._onCaptureEsc(event);
-      } else if (Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event, 'tab')) {
-        overlay._onCaptureTab(event);
-      }
-    }
-  },
-  _shouldBeBehindOverlay: function(overlay1, overlay2) {
-    return !overlay1.alwaysOnTop && overlay2.alwaysOnTop;
-  }
-};
-
-Polymer.IronOverlayManager = new Polymer.IronOverlayManagerClass();
-
-(function() {
-  'use strict';
-  Polymer.IronOverlayBehaviorImpl = {
-    properties: {
-      opened: {
-        observer: '_openedChanged',
-        type: Boolean,
-        value: false,
-        notify: true
-      },
-      canceled: {
-        observer: '_canceledChanged',
-        readOnly: true,
-        type: Boolean,
-        value: false
-      },
-      withBackdrop: {
-        observer: '_withBackdropChanged',
-        type: Boolean
-      },
-      noAutoFocus: {
-        type: Boolean,
-        value: false
-      },
-      noCancelOnEscKey: {
-        type: Boolean,
-        value: false
-      },
-      noCancelOnOutsideClick: {
-        type: Boolean,
-        value: false
-      },
-      closingReason: {
-        type: Object
-      },
-      restoreFocusOnClose: {
-        type: Boolean,
-        value: false
-      },
-      alwaysOnTop: {
-        type: Boolean
-      },
-      _manager: {
-        type: Object,
-        value: Polymer.IronOverlayManager
-      },
-      _focusedChild: {
-        type: Object
-      }
-    },
-    listeners: {
-      'iron-resize': '_onIronResize'
-    },
-    get backdropElement() {
-      return this._manager.backdropElement;
-    },
-    get _focusNode() {
-      return this._focusedChild || Polymer.dom(this).querySelector('[autofocus]') || this;
-    },
-    get _focusableNodes() {
-      var FOCUSABLE_WITH_DISABLED = [ 'a[href]', 'area[href]', 'iframe', '[tabindex]', '[contentEditable=true]' ];
-      var FOCUSABLE_WITHOUT_DISABLED = [ 'input', 'select', 'textarea', 'button' ];
-      var selector = FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),') + ':not([tabindex="-1"]),' + FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),') + ':not([disabled]):not([tabindex="-1"])';
-      var focusables = Polymer.dom(this).querySelectorAll(selector);
-      if (this.tabIndex >= 0) {
-        focusables.splice(0, 0, this);
-      }
-      return focusables.sort(function(a, b) {
-        if (a.tabIndex === b.tabIndex) {
-          return 0;
-        }
-        if (a.tabIndex === 0 || a.tabIndex > b.tabIndex) {
-          return 1;
-        }
-        return -1;
-      });
-    },
-    ready: function() {
-      this.__isAnimating = false;
-      this.__shouldRemoveTabIndex = false;
-      this.__firstFocusableNode = this.__lastFocusableNode = null;
-      this.__raf = null;
-      this.__restoreFocusNode = null;
-      this._ensureSetup();
-    },
-    attached: function() {
-      if (this.opened) {
-        this._openedChanged(this.opened);
-      }
-      this._observer = Polymer.dom(this).observeNodes(this._onNodesChange);
-    },
-    detached: function() {
-      Polymer.dom(this).unobserveNodes(this._observer);
-      this._observer = null;
-      if (this.__raf) {
-        window.cancelAnimationFrame(this.__raf);
-        this.__raf = null;
-      }
-      this._manager.removeOverlay(this);
-    },
-    toggle: function() {
-      this._setCanceled(false);
-      this.opened = !this.opened;
-    },
-    open: function() {
-      this._setCanceled(false);
-      this.opened = true;
-    },
-    close: function() {
-      this._setCanceled(false);
-      this.opened = false;
-    },
-    cancel: function(event) {
-      var cancelEvent = this.fire('iron-overlay-canceled', event, {
-        cancelable: true
-      });
-      if (cancelEvent.defaultPrevented) {
-        return;
-      }
-      this._setCanceled(true);
-      this.opened = false;
-    },
-    _ensureSetup: function() {
-      if (this._overlaySetup) {
-        return;
-      }
-      this._overlaySetup = true;
-      this.style.outline = 'none';
-      this.style.display = 'none';
-    },
-    _openedChanged: function(opened) {
-      if (opened) {
-        this.removeAttribute('aria-hidden');
-      } else {
-        this.setAttribute('aria-hidden', 'true');
-      }
-      if (!this.isAttached) {
-        return;
-      }
-      this.__isAnimating = true;
-      this.__onNextAnimationFrame(this.__openedChanged);
-    },
-    _canceledChanged: function() {
-      this.closingReason = this.closingReason || {};
-      this.closingReason.canceled = this.canceled;
-    },
-    _withBackdropChanged: function() {
-      if (this.withBackdrop && !this.hasAttribute('tabindex')) {
-        this.setAttribute('tabindex', '-1');
-        this.__shouldRemoveTabIndex = true;
-      } else if (this.__shouldRemoveTabIndex) {
-        this.removeAttribute('tabindex');
-        this.__shouldRemoveTabIndex = false;
-      }
-      if (this.opened && this.isAttached) {
-        this._manager.trackBackdrop();
-      }
-    },
-    _prepareRenderOpened: function() {
-      this.__restoreFocusNode = this._manager.deepActiveElement;
-      this._preparePositioning();
-      this.refit();
-      this._finishPositioning();
-      if (this.noAutoFocus && document.activeElement === this._focusNode) {
-        this._focusNode.blur();
-        this.__restoreFocusNode.focus();
-      }
-    },
-    _renderOpened: function() {
-      this._finishRenderOpened();
-    },
-    _renderClosed: function() {
-      this._finishRenderClosed();
-    },
-    _finishRenderOpened: function() {
-      this.notifyResize();
-      this.__isAnimating = false;
-      var focusableNodes = this._focusableNodes;
-      this.__firstFocusableNode = focusableNodes[0];
-      this.__lastFocusableNode = focusableNodes[focusableNodes.length - 1];
-      this.fire('iron-overlay-opened');
-    },
-    _finishRenderClosed: function() {
-      this.style.display = 'none';
-      this.style.zIndex = '';
-      this.notifyResize();
-      this.__isAnimating = false;
-      this.fire('iron-overlay-closed', this.closingReason);
-    },
-    _preparePositioning: function() {
-      this.style.transition = this.style.webkitTransition = 'none';
-      this.style.transform = this.style.webkitTransform = 'none';
-      this.style.display = '';
-    },
-    _finishPositioning: function() {
-      this.style.display = 'none';
-      this.scrollTop = this.scrollTop;
-      this.style.transition = this.style.webkitTransition = '';
-      this.style.transform = this.style.webkitTransform = '';
-      this.style.display = '';
-      this.scrollTop = this.scrollTop;
-    },
-    _applyFocus: function() {
-      if (this.opened) {
-        if (!this.noAutoFocus) {
-          this._focusNode.focus();
-        }
-      } else {
-        this._focusNode.blur();
-        this._focusedChild = null;
-        if (this.restoreFocusOnClose && this.__restoreFocusNode) {
-          this.__restoreFocusNode.focus();
-        }
-        this.__restoreFocusNode = null;
-        var currentOverlay = this._manager.currentOverlay();
-        if (currentOverlay && this !== currentOverlay) {
-          currentOverlay._applyFocus();
-        }
-      }
-    },
-    _onCaptureClick: function(event) {
-      if (!this.noCancelOnOutsideClick) {
-        this.cancel(event);
-      }
-    },
-    _onCaptureFocus: function(event) {
-      if (!this.withBackdrop) {
-        return;
-      }
-      var path = Polymer.dom(event).path;
-      if (path.indexOf(this) === -1) {
-        event.stopPropagation();
-        this._applyFocus();
-      } else {
-        this._focusedChild = path[0];
-      }
-    },
-    _onCaptureEsc: function(event) {
-      if (!this.noCancelOnEscKey) {
-        this.cancel(event);
-      }
-    },
-    _onCaptureTab: function(event) {
-      if (!this.withBackdrop) {
-        return;
-      }
-      var shift = event.shiftKey;
-      var nodeToCheck = shift ? this.__firstFocusableNode : this.__lastFocusableNode;
-      var nodeToSet = shift ? this.__lastFocusableNode : this.__firstFocusableNode;
-      var shouldWrap = false;
-      if (nodeToCheck === nodeToSet) {
-        shouldWrap = true;
-      } else {
-        var focusedNode = this._manager.deepActiveElement;
-        shouldWrap = focusedNode === nodeToCheck || focusedNode === this;
-      }
-      if (shouldWrap) {
-        event.preventDefault();
-        this._focusedChild = nodeToSet;
-        this._applyFocus();
-      }
-    },
-    _onIronResize: function() {
-      if (this.opened && !this.__isAnimating) {
-        this.__onNextAnimationFrame(this.refit);
-      }
-    },
-    _onNodesChange: function() {
-      if (this.opened && !this.__isAnimating) {
-        this.notifyResize();
-      }
-    },
-    __openedChanged: function() {
-      if (this.opened) {
-        this._prepareRenderOpened();
-        this._manager.addOverlay(this);
-        this._applyFocus();
-        this._renderOpened();
-      } else {
-        this._manager.removeOverlay(this);
-        this._applyFocus();
-        this._renderClosed();
-      }
-    },
-    __onNextAnimationFrame: function(callback) {
-      if (this.__raf) {
-        window.cancelAnimationFrame(this.__raf);
-      }
-      var self = this;
-      this.__raf = window.requestAnimationFrame(function nextAnimationFrame() {
-        self.__raf = null;
-        callback.call(self);
-      });
-    }
-  };
-  Polymer.IronOverlayBehavior = [ Polymer.IronFitBehavior, Polymer.IronResizableBehavior, Polymer.IronOverlayBehaviorImpl ];
-})();
-
-Polymer.NeonAnimatableBehavior = {
-  properties: {
-    animationConfig: {
-      type: Object
-    },
-    entryAnimation: {
-      observer: '_entryAnimationChanged',
-      type: String
-    },
-    exitAnimation: {
-      observer: '_exitAnimationChanged',
-      type: String
-    }
-  },
-  _entryAnimationChanged: function() {
-    this.animationConfig = this.animationConfig || {};
-    this.animationConfig['entry'] = [ {
-      name: this.entryAnimation,
-      node: this
-    } ];
-  },
-  _exitAnimationChanged: function() {
-    this.animationConfig = this.animationConfig || {};
-    this.animationConfig['exit'] = [ {
-      name: this.exitAnimation,
-      node: this
-    } ];
-  },
-  _copyProperties: function(config1, config2) {
-    for (var property in config2) {
-      config1[property] = config2[property];
-    }
-  },
-  _cloneConfig: function(config) {
-    var clone = {
-      isClone: true
-    };
-    this._copyProperties(clone, config);
-    return clone;
-  },
-  _getAnimationConfigRecursive: function(type, map, allConfigs) {
-    if (!this.animationConfig) {
-      return;
-    }
-    if (this.animationConfig.value && typeof this.animationConfig.value === 'function') {
-      this._warn(this._logf('playAnimation', "Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));
-      return;
-    }
-    var thisConfig;
-    if (type) {
-      thisConfig = this.animationConfig[type];
-    } else {
-      thisConfig = this.animationConfig;
-    }
-    if (!Array.isArray(thisConfig)) {
-      thisConfig = [ thisConfig ];
-    }
-    if (thisConfig) {
-      for (var config, index = 0; config = thisConfig[index]; index++) {
-        if (config.animatable) {
-          config.animatable._getAnimationConfigRecursive(config.type || type, map, allConfigs);
-        } else {
-          if (config.id) {
-            var cachedConfig = map[config.id];
-            if (cachedConfig) {
-              if (!cachedConfig.isClone) {
-                map[config.id] = this._cloneConfig(cachedConfig);
-                cachedConfig = map[config.id];
-              }
-              this._copyProperties(cachedConfig, config);
-            } else {
-              map[config.id] = config;
-            }
-          } else {
-            allConfigs.push(config);
-          }
-        }
-      }
-    }
-  },
-  getAnimationConfig: function(type) {
-    var map = {};
-    var allConfigs = [];
-    this._getAnimationConfigRecursive(type, map, allConfigs);
-    for (var key in map) {
-      allConfigs.push(map[key]);
-    }
-    return allConfigs;
-  }
-};
-
-Polymer.NeonAnimationRunnerBehaviorImpl = {
-  _configureAnimations: function(configs) {
-    var results = [];
-    if (configs.length > 0) {
-      for (var config, index = 0; config = configs[index]; index++) {
-        var neonAnimation = document.createElement(config.name);
-        if (neonAnimation.isNeonAnimation) {
-          var result = null;
-          try {
-            result = neonAnimation.configure(config);
-            if (typeof result.cancel != 'function') {
-              result = document.timeline.play(result);
-            }
-          } catch (e) {
-            result = null;
-            console.warn('Couldnt play', '(', config.name, ').', e);
-          }
-          if (result) {
-            results.push({
-              neonAnimation: neonAnimation,
-              config: config,
-              animation: result
-            });
-          }
-        } else {
-          console.warn(this.is + ':', config.name, 'not found!');
-        }
-      }
-    }
-    return results;
-  },
-  _shouldComplete: function(activeEntries) {
-    var finished = true;
-    for (var i = 0; i < activeEntries.length; i++) {
-      if (activeEntries[i].animation.playState != 'finished') {
-        finished = false;
-        break;
-      }
-    }
-    return finished;
-  },
-  _complete: function(activeEntries) {
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].neonAnimation.complete(activeEntries[i].config);
-    }
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].animation.cancel();
-    }
-  },
-  playAnimation: function(type, cookie) {
-    var configs = this.getAnimationConfig(type);
-    if (!configs) {
-      return;
-    }
-    this._active = this._active || {};
-    if (this._active[type]) {
-      this._complete(this._active[type]);
-      delete this._active[type];
-    }
-    var activeEntries = this._configureAnimations(configs);
-    if (activeEntries.length == 0) {
-      this.fire('neon-animation-finish', cookie, {
-        bubbles: false
-      });
-      return;
-    }
-    this._active[type] = activeEntries;
-    for (var i = 0; i < activeEntries.length; i++) {
-      activeEntries[i].animation.onfinish = function() {
-        if (this._shouldComplete(activeEntries)) {
-          this._complete(activeEntries);
-          delete this._active[type];
-          this.fire('neon-animation-finish', cookie, {
-            bubbles: false
-          });
-        }
-      }.bind(this);
-    }
-  },
-  cancelAnimation: function() {
-    for (var k in this._animations) {
-      this._animations[k].cancel();
-    }
-    this._animations = {};
-  }
-};
-
-Polymer.NeonAnimationRunnerBehavior = [ Polymer.NeonAnimatableBehavior, Polymer.NeonAnimationRunnerBehaviorImpl ];
-
-Polymer.NeonAnimationBehavior = {
-  properties: {
-    animationTiming: {
-      type: Object,
-      value: function() {
-        return {
-          duration: 500,
-          easing: 'cubic-bezier(0.4, 0, 0.2, 1)',
-          fill: 'both'
-        };
-      }
-    }
-  },
-  isNeonAnimation: true,
-  timingFromConfig: function(config) {
-    if (config.timing) {
-      for (var property in config.timing) {
-        this.animationTiming[property] = config.timing[property];
-      }
-    }
-    return this.animationTiming;
-  },
-  setPrefixedProperty: function(node, property, value) {
-    var map = {
-      transform: [ 'webkitTransform' ],
-      transformOrigin: [ 'mozTransformOrigin', 'webkitTransformOrigin' ]
-    };
-    var prefixes = map[property];
-    for (var prefix, index = 0; prefix = prefixes[index]; index++) {
-      node.style[prefix] = value;
-    }
-    node.style[property] = value;
-  },
-  complete: function() {}
-};
-
-Polymer({
-  is: 'opaque-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '1'
-    }, {
-      opacity: '1'
-    } ], this.timingFromConfig(config));
-    node.style.opacity = '0';
-    return this._effect;
-  },
-  complete: function(config) {
-    config.node.style.opacity = '';
-  }
-});
-
-(function() {
-  'use strict';
-  var LAST_TOUCH_POSITION = {
-    pageX: 0,
-    pageY: 0
-  };
-  var ROOT_TARGET = null;
-  var SCROLLABLE_NODES = [];
-  Polymer.IronDropdownScrollManager = {
-    get currentLockingElement() {
-      return this._lockingElements[this._lockingElements.length - 1];
-    },
-    elementIsScrollLocked: function(element) {
-      var currentLockingElement = this.currentLockingElement;
-      if (currentLockingElement === undefined) return false;
-      var scrollLocked;
-      if (this._hasCachedLockedElement(element)) {
-        return true;
-      }
-      if (this._hasCachedUnlockedElement(element)) {
-        return false;
-      }
-      scrollLocked = !!currentLockingElement && currentLockingElement !== element && !this._composedTreeContains(currentLockingElement, element);
-      if (scrollLocked) {
-        this._lockedElementCache.push(element);
-      } else {
-        this._unlockedElementCache.push(element);
-      }
-      return scrollLocked;
-    },
-    pushScrollLock: function(element) {
-      if (this._lockingElements.indexOf(element) >= 0) {
-        return;
-      }
-      if (this._lockingElements.length === 0) {
-        this._lockScrollInteractions();
-      }
-      this._lockingElements.push(element);
-      this._lockedElementCache = [];
-      this._unlockedElementCache = [];
-    },
-    removeScrollLock: function(element) {
-      var index = this._lockingElements.indexOf(element);
-      if (index === -1) {
-        return;
-      }
-      this._lockingElements.splice(index, 1);
-      this._lockedElementCache = [];
-      this._unlockedElementCache = [];
-      if (this._lockingElements.length === 0) {
-        this._unlockScrollInteractions();
-      }
-    },
-    _lockingElements: [],
-    _lockedElementCache: null,
-    _unlockedElementCache: null,
-    _hasCachedLockedElement: function(element) {
-      return this._lockedElementCache.indexOf(element) > -1;
-    },
-    _hasCachedUnlockedElement: function(element) {
-      return this._unlockedElementCache.indexOf(element) > -1;
-    },
-    _composedTreeContains: function(element, child) {
-      var contentElements;
-      var distributedNodes;
-      var contentIndex;
-      var nodeIndex;
-      if (element.contains(child)) {
-        return true;
-      }
-      contentElements = Polymer.dom(element).querySelectorAll('content');
-      for (contentIndex = 0; contentIndex < contentElements.length; ++contentIndex) {
-        distributedNodes = Polymer.dom(contentElements[contentIndex]).getDistributedNodes();
-        for (nodeIndex = 0; nodeIndex < distributedNodes.length; ++nodeIndex) {
-          if (this._composedTreeContains(distributedNodes[nodeIndex], child)) {
-            return true;
-          }
-        }
-      }
-      return false;
-    },
-    _scrollInteractionHandler: function(event) {
-      if (event.cancelable && this._shouldPreventScrolling(event)) {
-        event.preventDefault();
-      }
-      if (event.targetTouches) {
-        var touch = event.targetTouches[0];
-        LAST_TOUCH_POSITION.pageX = touch.pageX;
-        LAST_TOUCH_POSITION.pageY = touch.pageY;
-      }
-    },
-    _lockScrollInteractions: function() {
-      this._boundScrollHandler = this._boundScrollHandler || this._scrollInteractionHandler.bind(this);
-      document.addEventListener('wheel', this._boundScrollHandler, true);
-      document.addEventListener('mousewheel', this._boundScrollHandler, true);
-      document.addEventListener('DOMMouseScroll', this._boundScrollHandler, true);
-      document.addEventListener('touchstart', this._boundScrollHandler, true);
-      document.addEventListener('touchmove', this._boundScrollHandler, true);
-    },
-    _unlockScrollInteractions: function() {
-      document.removeEventListener('wheel', this._boundScrollHandler, true);
-      document.removeEventListener('mousewheel', this._boundScrollHandler, true);
-      document.removeEventListener('DOMMouseScroll', this._boundScrollHandler, true);
-      document.removeEventListener('touchstart', this._boundScrollHandler, true);
-      document.removeEventListener('touchmove', this._boundScrollHandler, true);
-    },
-    _shouldPreventScrolling: function(event) {
-      var target = Polymer.dom(event).rootTarget;
-      if (event.type !== 'touchmove' && ROOT_TARGET !== target) {
-        ROOT_TARGET = target;
-        SCROLLABLE_NODES = this._getScrollableNodes(Polymer.dom(event).path);
-      }
-      if (!SCROLLABLE_NODES.length) {
-        return true;
-      }
-      if (event.type === 'touchstart') {
-        return false;
-      }
-      var info = this._getScrollInfo(event);
-      return !this._getScrollingNode(SCROLLABLE_NODES, info.deltaX, info.deltaY);
-    },
-    _getScrollableNodes: function(nodes) {
-      var scrollables = [];
-      var lockingIndex = nodes.indexOf(this.currentLockingElement);
-      for (var i = 0; i <= lockingIndex; i++) {
-        var node = nodes[i];
-        if (node.nodeType === 11) {
-          continue;
-        }
-        var style = node.style;
-        if (style.overflow !== 'scroll' && style.overflow !== 'auto') {
-          style = window.getComputedStyle(node);
-        }
-        if (style.overflow === 'scroll' || style.overflow === 'auto') {
-          scrollables.push(node);
-        }
-      }
-      return scrollables;
-    },
-    _getScrollingNode: function(nodes, deltaX, deltaY) {
-      if (!deltaX && !deltaY) {
-        return;
-      }
-      var verticalScroll = Math.abs(deltaY) >= Math.abs(deltaX);
-      for (var i = 0; i < nodes.length; i++) {
-        var node = nodes[i];
-        var canScroll = false;
-        if (verticalScroll) {
-          canScroll = deltaY < 0 ? node.scrollTop > 0 : node.scrollTop < node.scrollHeight - node.clientHeight;
-        } else {
-          canScroll = deltaX < 0 ? node.scrollLeft > 0 : node.scrollLeft < node.scrollWidth - node.clientWidth;
-        }
-        if (canScroll) {
-          return node;
-        }
-      }
-    },
-    _getScrollInfo: function(event) {
-      var info = {
-        deltaX: event.deltaX,
-        deltaY: event.deltaY
-      };
-      if ('deltaX' in event) {} else if ('wheelDeltaX' in event) {
-        info.deltaX = -event.wheelDeltaX;
-        info.deltaY = -event.wheelDeltaY;
-      } else if ('axis' in event) {
-        info.deltaX = event.axis === 1 ? event.detail : 0;
-        info.deltaY = event.axis === 2 ? event.detail : 0;
-      } else if (event.targetTouches) {
-        var touch = event.targetTouches[0];
-        info.deltaX = LAST_TOUCH_POSITION.pageX - touch.pageX;
-        info.deltaY = LAST_TOUCH_POSITION.pageY - touch.pageY;
-      }
-      return info;
-    }
-  };
-})();
-
-(function() {
-  'use strict';
-  Polymer({
-    is: 'iron-dropdown',
-    behaviors: [ Polymer.IronControlState, Polymer.IronA11yKeysBehavior, Polymer.IronOverlayBehavior, Polymer.NeonAnimationRunnerBehavior ],
-    properties: {
-      horizontalAlign: {
-        type: String,
-        value: 'left',
-        reflectToAttribute: true
-      },
-      verticalAlign: {
-        type: String,
-        value: 'top',
-        reflectToAttribute: true
-      },
-      openAnimationConfig: {
-        type: Object
-      },
-      closeAnimationConfig: {
-        type: Object
-      },
-      focusTarget: {
-        type: Object
-      },
-      noAnimations: {
-        type: Boolean,
-        value: false
-      },
-      allowOutsideScroll: {
-        type: Boolean,
-        value: false
-      },
-      _boundOnCaptureScroll: {
-        type: Function,
-        value: function() {
-          return this._onCaptureScroll.bind(this);
-        }
-      }
-    },
-    listeners: {
-      'neon-animation-finish': '_onNeonAnimationFinish'
-    },
-    observers: [ '_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)' ],
-    get containedElement() {
-      return Polymer.dom(this.$.content).getDistributedNodes()[0];
-    },
-    get _focusTarget() {
-      return this.focusTarget || this.containedElement;
-    },
-    ready: function() {
-      this._scrollTop = 0;
-      this._scrollLeft = 0;
-      this._refitOnScrollRAF = null;
-    },
-    attached: function() {
-      if (!this.sizingTarget || this.sizingTarget === this) {
-        this.sizingTarget = this.containedElement;
-      }
-    },
-    detached: function() {
-      this.cancelAnimation();
-      document.removeEventListener('scroll', this._boundOnCaptureScroll);
-      Polymer.IronDropdownScrollManager.removeScrollLock(this);
-    },
-    _openedChanged: function() {
-      if (this.opened && this.disabled) {
-        this.cancel();
-      } else {
-        this.cancelAnimation();
-        this._updateAnimationConfig();
-        this._saveScrollPosition();
-        if (this.opened) {
-          document.addEventListener('scroll', this._boundOnCaptureScroll);
-          !this.allowOutsideScroll && Polymer.IronDropdownScrollManager.pushScrollLock(this);
-        } else {
-          document.removeEventListener('scroll', this._boundOnCaptureScroll);
-          Polymer.IronDropdownScrollManager.removeScrollLock(this);
-        }
-        Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this, arguments);
-      }
-    },
-    _renderOpened: function() {
-      if (!this.noAnimations && this.animationConfig.open) {
-        this.$.contentWrapper.classList.add('animating');
-        this.playAnimation('open');
-      } else {
-        Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this, arguments);
-      }
-    },
-    _renderClosed: function() {
-      if (!this.noAnimations && this.animationConfig.close) {
-        this.$.contentWrapper.classList.add('animating');
-        this.playAnimation('close');
-      } else {
-        Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this, arguments);
-      }
-    },
-    _onNeonAnimationFinish: function() {
-      this.$.contentWrapper.classList.remove('animating');
-      if (this.opened) {
-        this._finishRenderOpened();
-      } else {
-        this._finishRenderClosed();
-      }
-    },
-    _onCaptureScroll: function() {
-      if (!this.allowOutsideScroll) {
-        this._restoreScrollPosition();
-      } else {
-        this._refitOnScrollRAF && window.cancelAnimationFrame(this._refitOnScrollRAF);
-        this._refitOnScrollRAF = window.requestAnimationFrame(this.refit.bind(this));
-      }
-    },
-    _saveScrollPosition: function() {
-      if (document.scrollingElement) {
-        this._scrollTop = document.scrollingElement.scrollTop;
-        this._scrollLeft = document.scrollingElement.scrollLeft;
-      } else {
-        this._scrollTop = Math.max(document.documentElement.scrollTop, document.body.scrollTop);
-        this._scrollLeft = Math.max(document.documentElement.scrollLeft, document.body.scrollLeft);
-      }
-    },
-    _restoreScrollPosition: function() {
-      if (document.scrollingElement) {
-        document.scrollingElement.scrollTop = this._scrollTop;
-        document.scrollingElement.scrollLeft = this._scrollLeft;
-      } else {
-        document.documentElement.scrollTop = this._scrollTop;
-        document.documentElement.scrollLeft = this._scrollLeft;
-        document.body.scrollTop = this._scrollTop;
-        document.body.scrollLeft = this._scrollLeft;
-      }
-    },
-    _updateAnimationConfig: function() {
-      var animations = (this.openAnimationConfig || []).concat(this.closeAnimationConfig || []);
-      for (var i = 0; i < animations.length; i++) {
-        animations[i].node = this.containedElement;
-      }
-      this.animationConfig = {
-        open: this.openAnimationConfig,
-        close: this.closeAnimationConfig
-      };
-    },
-    _updateOverlayPosition: function() {
-      if (this.isAttached) {
-        this.notifyResize();
-      }
-    },
-    _applyFocus: function() {
-      var focusTarget = this.focusTarget || this.containedElement;
-      if (focusTarget && this.opened && !this.noAutoFocus) {
-        focusTarget.focus();
-      } else {
-        Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this, arguments);
-      }
-    }
-  });
-})();
-
-Polymer({
-  is: 'fade-in-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '0'
-    }, {
-      opacity: '1'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'fade-out-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    this._effect = new KeyframeEffect(node, [ {
-      opacity: '1'
-    }, {
-      opacity: '0'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-grow-height-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var height = rect.height;
-    this._effect = new KeyframeEffect(node, [ {
-      height: height / 2 + 'px'
-    }, {
-      height: height + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-grow-width-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var width = rect.width;
-    this._effect = new KeyframeEffect(node, [ {
-      width: width / 2 + 'px'
-    }, {
-      width: width + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-shrink-width-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var width = rect.width;
-    this._effect = new KeyframeEffect(node, [ {
-      width: width + 'px'
-    }, {
-      width: width - width / 20 + 'px'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
-Polymer({
-  is: 'paper-menu-shrink-height-animation',
-  behaviors: [ Polymer.NeonAnimationBehavior ],
-  configure: function(config) {
-    var node = config.node;
-    var rect = node.getBoundingClientRect();
-    var height = rect.height;
-    var top = rect.top;
-    this.setPrefixedProperty(node, 'transformOrigin', '0 0');
-    this._effect = new KeyframeEffect(node, [ {
-      height: height + 'px',
-      transform: 'translateY(0)'
-    }, {
-      height: height / 2 + 'px',
-      transform: 'translateY(-20px)'
-    } ], this.timingFromConfig(config));
-    return this._effect;
-  }
-});
-
+document.addEventListener("touchmove",this._boundScrollHandler,true)},_unlockScrollInteractions:function(){document.removeEventListener("wheel",this._boundScrollHandler,true);document.removeEventListener("mousewheel",this._boundScrollHandler,true);document.removeEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.removeEventListener("touchstart",this._boundScrollHandler,true);document.removeEventListener("touchmove",this._boundScrollHandler,true)},_shouldPreventScrolling:function(event){var target=Polymer.dom(event).rootTarget;if(event.type!=="touchmove"&&ROOT_TARGET!==target){ROOT_TARGET=target;SCROLLABLE_NODES=this._getScrollableNodes(Polymer.dom(event).path)}if(!SCROLLABLE_NODES.length){return true}if(event.type==="touchstart"){return false}var info=this._getScrollInfo(event);return!this._getScrollingNode(SCROLLABLE_NODES,info.deltaX,info.deltaY)},_getScrollableNodes:function(nodes){var scrollables=[];var lockingIndex=nodes.indexOf(this.currentLockingElement);for(var i=0;i<=lockingIndex;i++){var node=nodes[i];if(node.nodeType===11){continue}var style=node.style;if(style.overflow!=="scroll"&&style.overflow!=="auto"){style=window.getComputedStyle(node)}if(style.overflow==="scroll"||style.overflow==="auto"){scrollables.push(node)}}return scrollables},_getScrollingNode:function(nodes,deltaX,deltaY){if(!deltaX&&!deltaY){return}var verticalScroll=Math.abs(deltaY)>=Math.abs(deltaX);for(var i=0;i<nodes.length;i++){var node=nodes[i];var canScroll=false;if(verticalScroll){canScroll=deltaY<0?node.scrollTop>0:node.scrollTop<node.scrollHeight-node.clientHeight}else{canScroll=deltaX<0?node.scrollLeft>0:node.scrollLeft<node.scrollWidth-node.clientWidth}if(canScroll){return node}}},_getScrollInfo:function(event){var info={deltaX:event.deltaX,deltaY:event.deltaY};if("deltaX"in event){}else if("wheelDeltaX"in event){info.deltaX=-event.wheelDeltaX;info.deltaY=-event.wheelDeltaY}else if("axis"in event){info.deltaX=event.axis===1?event.detail:0;info.deltaY=event.axis===2?event.detail:0}else if(event.targetTouches){var touch=event.targetTouches[0];info.deltaX=LAST_TOUCH_POSITION.pageX-touch.pageX;info.deltaY=LAST_TOUCH_POSITION.pageY-touch.pageY}return info}}})();(function(){"use strict";Polymer({is:"iron-dropdown",behaviors:[Polymer.IronControlState,Polymer.IronA11yKeysBehavior,Polymer.IronOverlayBehavior,Polymer.NeonAnimationRunnerBehavior],properties:{horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},openAnimationConfig:{type:Object},closeAnimationConfig:{type:Object},focusTarget:{type:Object},noAnimations:{type:Boolean,value:false},allowOutsideScroll:{type:Boolean,value:false},_boundOnCaptureScroll:{type:Function,value:function(){return this._onCaptureScroll.bind(this)}}},listeners:{"neon-animation-finish":"_onNeonAnimationFinish"},observers:["_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)"],get containedElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},get _focusTarget(){return this.focusTarget||this.containedElement},ready:function(){this._scrollTop=0;this._scrollLeft=0;this._refitOnScrollRAF=null},attached:function(){if(!this.sizingTarget||this.sizingTarget===this){this.sizingTarget=this.containedElement}},detached:function(){this.cancelAnimation();document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)},_openedChanged:function(){if(this.opened&&this.disabled){this.cancel()}else{this.cancelAnimation();this._updateAnimationConfig();this._saveScrollPosition();if(this.opened){document.addEventListener("scroll",this._boundOnCaptureScroll);!this.allowOutsideScroll&&Polymer.IronDropdownScrollManager.pushScrollLock(this)}else{document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)}Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this,arguments)}},_renderOpened:function(){if(!this.noAnimations&&this.animationConfig.open){this.$.contentWrapper.classList.add("animating");this.playAnimation("open")}else{Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this,arguments)}},_renderClosed:function(){if(!this.noAnimations&&this.animationConfig.close){this.$.contentWrapper.classList.add("animating");this.playAnimation("close")}else{Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this,arguments)}},_onNeonAnimationFinish:function(){this.$.contentWrapper.classList.remove("animating");if(this.opened){this._finishRenderOpened()}else{this._finishRenderClosed()}},_onCaptureScroll:function(){if(!this.allowOutsideScroll){this._restoreScrollPosition()}else{this._refitOnScrollRAF&&window.cancelAnimationFrame(this._refitOnScrollRAF);this._refitOnScrollRAF=window.requestAnimationFrame(this.refit.bind(this))}},_saveScrollPosition:function(){if(document.scrollingElement){this._scrollTop=document.scrollingElement.scrollTop;this._scrollLeft=document.scrollingElement.scrollLeft}else{this._scrollTop=Math.max(document.documentElement.scrollTop,document.body.scrollTop);this._scrollLeft=Math.max(document.documentElement.scrollLeft,document.body.scrollLeft)}},_restoreScrollPosition:function(){if(document.scrollingElement){document.scrollingElement.scrollTop=this._scrollTop;document.scrollingElement.scrollLeft=this._scrollLeft}else{document.documentElement.scrollTop=this._scrollTop;document.documentElement.scrollLeft=this._scrollLeft;document.body.scrollTop=this._scrollTop;document.body.scrollLeft=this._scrollLeft}},_updateAnimationConfig:function(){var animations=(this.openAnimationConfig||[]).concat(this.closeAnimationConfig||[]);for(var i=0;i<animations.length;i++){animations[i].node=this.containedElement}this.animationConfig={open:this.openAnimationConfig,close:this.closeAnimationConfig}},_updateOverlayPosition:function(){if(this.isAttached){this.notifyResize()}},_applyFocus:function(){var focusTarget=this.focusTarget||this.containedElement;if(focusTarget&&this.opened&&!this.noAutoFocus){focusTarget.focus()}else{Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this,arguments)}}})})();Polymer({is:"fade-in-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"0"},{opacity:"1"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"fade-out-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"0"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;this._effect=new KeyframeEffect(node,[{height:height/2+"px"},{height:height+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width/2+"px"},{width:width+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width+"px"},{width:width-width/20+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;var top=rect.top;this.setPrefixedProperty(node,"transformOrigin","0 0");this._effect=new KeyframeEffect(node,[{height:height+"px",transform:"translateY(0)"},{height:height/2+"px",transform:"translateY(-20px)"}],this.timingFromConfig(config));return this._effect}});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-var SLIDE_CUBIC_BEZIER = 'cubic-bezier(0.3, 0.95, 0.5, 1)';
-
-Polymer({
-  is: 'cr-shared-menu',
-  behaviors: [ Polymer.IronA11yKeysBehavior ],
-  properties: {
-    menuOpen: {
-      type: Boolean,
-      observer: 'menuOpenChanged_',
-      value: false,
-      notify: true
-    },
-    itemData: {
-      type: Object,
-      value: null
-    },
-    keyEventTarget: {
-      type: Object,
-      value: function() {
-        return this.$.menu;
-      }
-    },
-    openAnimationConfig: {
-      type: Object,
-      value: function() {
-        return [ {
-          name: 'fade-in-animation',
-          timing: {
-            delay: 50,
-            duration: 200
-          }
-        }, {
-          name: 'paper-menu-grow-width-animation',
-          timing: {
-            delay: 50,
-            duration: 150,
-            easing: SLIDE_CUBIC_BEZIER
-          }
-        }, {
-          name: 'paper-menu-grow-height-animation',
-          timing: {
-            delay: 100,
-            duration: 275,
-            easing: SLIDE_CUBIC_BEZIER
-          }
-        } ];
-      }
-    },
-    closeAnimationConfig: {
-      type: Object,
-      value: function() {
-        return [ {
-          name: 'fade-out-animation',
-          timing: {
-            duration: 150
-          }
-        } ];
-      }
-    }
-  },
-  keyBindings: {
-    tab: 'onTabPressed_'
-  },
-  listeners: {
-    'dropdown.iron-overlay-canceled': 'onOverlayCanceled_'
-  },
-  lastAnchor_: null,
-  firstFocus_: null,
-  lastFocus_: null,
-  attached: function() {
-    window.addEventListener('resize', this.closeMenu.bind(this));
-  },
-  closeMenu: function() {
-    if (this.root.activeElement == null) {
-      this.$.dropdown.restoreFocusOnClose = false;
-    }
-    this.menuOpen = false;
-  },
-  openMenu: function(anchor, opt_itemData) {
-    if (this.lastAnchor_ == anchor && this.menuOpen) return;
-    if (this.menuOpen) this.closeMenu();
-    this.itemData = opt_itemData || null;
-    this.lastAnchor_ = anchor;
-    this.$.dropdown.restoreFocusOnClose = true;
-    var focusableChildren = Polymer.dom(this).querySelectorAll('[tabindex]:not([disabled]):not([hidden]),' + 'button:not([disabled]):not([hidden])');
-    if (focusableChildren.length > 0) {
-      this.$.dropdown.focusTarget = focusableChildren[0];
-      this.firstFocus_ = focusableChildren[0];
-      this.lastFocus_ = focusableChildren[focusableChildren.length - 1];
-    }
-    this.$.dropdown.positionTarget = anchor;
-    this.menuOpen = true;
-  },
-  toggleMenu: function(anchor, opt_itemData) {
-    if (anchor == this.lastAnchor_ && this.menuOpen) this.closeMenu(); else this.openMenu(anchor, opt_itemData);
-  },
-  onTabPressed_: function(e) {
-    if (!this.firstFocus_ || !this.lastFocus_) return;
-    var toFocus;
-    var keyEvent = e.detail.keyboardEvent;
-    if (keyEvent.shiftKey && keyEvent.target == this.firstFocus_) toFocus = this.lastFocus_; else if (!keyEvent.shiftKey && keyEvent.target == this.lastFocus_) toFocus = this.firstFocus_;
-    if (!toFocus) return;
-    e.preventDefault();
-    toFocus.focus();
-  },
-  menuOpenChanged_: function() {
-    if (!this.menuOpen) {
-      this.itemData = null;
-      this.lastAnchor_ = null;
-    }
-  },
-  onOverlayCanceled_: function(e) {
-    if (e.detail.type == 'tap') this.$.dropdown.restoreFocusOnClose = false;
-  }
-});
-
-Polymer({
-  is: 'paper-icon-button-light',
-  "extends": 'button',
-  behaviors: [ Polymer.PaperRippleBehavior ],
-  listeners: {
-    down: '_rippleDown',
-    up: '_rippleUp',
-    focus: '_rippleDown',
-    blur: '_rippleUp'
-  },
-  _rippleDown: function() {
-    this.getRipple().downAction();
-  },
-  _rippleUp: function() {
-    this.getRipple().upAction();
-  },
-  ensureRipple: function(var_args) {
-    var lastRipple = this._ripple;
-    Polymer.PaperRippleBehavior.ensureRipple.apply(this, arguments);
-    if (this._ripple && this._ripple !== lastRipple) {
-      this._ripple.center = true;
-      this._ripple.classList.add('circle');
-    }
-  }
-});
-
+var SLIDE_CUBIC_BEZIER="cubic-bezier(0.3, 0.95, 0.5, 1)";Polymer({is:"cr-shared-menu",behaviors:[Polymer.IronA11yKeysBehavior],properties:{menuOpen:{type:Boolean,observer:"menuOpenChanged_",value:false,notify:true},itemData:{type:Object,value:null},keyEventTarget:{type:Object,value:function(){return this.$.menu}},openAnimationConfig:{type:Object,value:function(){return[{name:"fade-in-animation",timing:{delay:50,duration:200}},{name:"paper-menu-grow-width-animation",timing:{delay:50,duration:150,easing:SLIDE_CUBIC_BEZIER}},{name:"paper-menu-grow-height-animation",timing:{delay:100,duration:275,easing:SLIDE_CUBIC_BEZIER}}]}},closeAnimationConfig:{type:Object,value:function(){return[{name:"fade-out-animation",timing:{duration:150}}]}}},keyBindings:{tab:"onTabPressed_"},listeners:{"dropdown.iron-overlay-canceled":"onOverlayCanceled_"},lastAnchor_:null,firstFocus_:null,lastFocus_:null,attached:function(){window.addEventListener("resize",this.closeMenu.bind(this))},closeMenu:function(){if(this.root.activeElement==null){this.$.dropdown.restoreFocusOnClose=false}this.menuOpen=false},openMenu:function(anchor,opt_itemData){if(this.lastAnchor_==anchor&&this.menuOpen)return;if(this.menuOpen)this.closeMenu();this.itemData=opt_itemData||null;this.lastAnchor_=anchor;this.$.dropdown.restoreFocusOnClose=true;var focusableChildren=Polymer.dom(this).querySelectorAll("[tabindex]:not([disabled]):not([hidden]),"+"button:not([disabled]):not([hidden])");if(focusableChildren.length>0){this.$.dropdown.focusTarget=focusableChildren[0];this.firstFocus_=focusableChildren[0];this.lastFocus_=focusableChildren[focusableChildren.length-1]}this.$.dropdown.positionTarget=anchor;this.menuOpen=true},toggleMenu:function(anchor,opt_itemData){if(anchor==this.lastAnchor_&&this.menuOpen)this.closeMenu();else this.openMenu(anchor,opt_itemData)},onTabPressed_:function(e){if(!this.firstFocus_||!this.lastFocus_)return;var toFocus;var keyEvent=e.detail.keyboardEvent;if(keyEvent.shiftKey&&keyEvent.target==this.firstFocus_)toFocus=this.lastFocus_;else if(!keyEvent.shiftKey&&keyEvent.target==this.lastFocus_)toFocus=this.firstFocus_;if(!toFocus)return;e.preventDefault();toFocus.focus()},menuOpenChanged_:function(){if(!this.menuOpen){this.itemData=null;this.lastAnchor_=null}},onOverlayCanceled_:function(e){if(e.detail.type=="tap")this.$.dropdown.restoreFocusOnClose=false}});Polymer({is:"paper-icon-button-light","extends":"button",behaviors:[Polymer.PaperRippleBehavior],listeners:{down:"_rippleDown",up:"_rippleUp",focus:"_rippleDown",blur:"_rippleUp"},_rippleDown:function(){this.getRipple().downAction()},_rippleUp:function(){this.getRipple().upAction()},ensureRipple:function(var_args){var lastRipple=this._ripple;Polymer.PaperRippleBehavior.ensureRipple.apply(this,arguments);if(this._ripple&&this._ripple!==lastRipple){this._ripple.center=true;this._ripple.classList.add("circle")}}});
 // Copyright 2016 The Chromium 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({
-  is: 'history-synced-device-card',
-  properties: {
-    device: String,
-    lastUpdateTime: String,
-    tabs: {
-      type: Array,
-      value: function() {
-        return [];
-      },
-      observer: 'updateIcons_'
-    },
-    separatorIndexes: Array,
-    opened: Boolean,
-    searchTerm: String,
-    sessionTag: String
-  },
-  openTab_: function(e) {
-    var tab = e.model.tab;
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.LINK_CLICKED, SyncedTabsHistogram.LIMIT);
-    browserService.openForeignSessionTab(this.sessionTag, tab.windowId, tab.sessionId, e);
-    e.preventDefault();
-  },
-  toggleTabCard: function() {
-    var histogramValue = this.$.collapse.opened ? SyncedTabsHistogram.COLLAPSE_SESSION : SyncedTabsHistogram.EXPAND_SESSION;
-    md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, histogramValue, SyncedTabsHistogram.LIMIT);
-    this.$.collapse.toggle();
-    this.$['dropdown-indicator'].icon = this.$.collapse.opened ? 'cr:expand-less' : 'cr:expand-more';
-  },
-  updateIcons_: function() {
-    this.async(function() {
-      var icons = Polymer.dom(this.root).querySelectorAll('.website-icon');
-      for (var i = 0; i < this.tabs.length; i++) {
-        icons[i].style.backgroundImage = cr.icon.getFavicon(this.tabs[i].url);
-      }
-    });
-  },
-  isWindowSeparatorIndex_: function(index, separatorIndexes) {
-    return this.separatorIndexes.indexOf(index) != -1;
-  },
-  getCollapseIcon_: function(opened) {
-    return opened ? 'cr:expand-less' : 'cr:expand-more';
-  },
-  getCollapseTitle_: function(opened) {
-    return opened ? loadTimeData.getString('collapseSessionButton') : loadTimeData.getString('expandSessionButton');
-  },
-  onMenuButtonTap_: function(e) {
-    this.fire('toggle-menu', {
-      target: Polymer.dom(e).localTarget,
-      tag: this.sessionTag
-    });
-    e.stopPropagation();
-  },
-  onLinkRightClick_: function() {
-    md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.LINK_RIGHT_CLICKED, SyncedTabsHistogram.LIMIT);
-  }
-});
-
+Polymer({is:"history-synced-device-card",properties:{device:String,lastUpdateTime:String,tabs:{type:Array,value:function(){return[]},observer:"updateIcons_"},separatorIndexes:Array,opened:Boolean,searchTerm:String,sessionTag:String},openTab_:function(e){var tab=e.model.tab;var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.LINK_CLICKED,SyncedTabsHistogram.LIMIT);browserService.openForeignSessionTab(this.sessionTag,tab.windowId,tab.sessionId,e);e.preventDefault()},toggleTabCard:function(){var histogramValue=this.$.collapse.opened?SyncedTabsHistogram.COLLAPSE_SESSION:SyncedTabsHistogram.EXPAND_SESSION;md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,histogramValue,SyncedTabsHistogram.LIMIT);this.$.collapse.toggle();this.$["dropdown-indicator"].icon=this.$.collapse.opened?"cr:expand-less":"cr:expand-more"},updateIcons_:function(){this.async(function(){var icons=Polymer.dom(this.root).querySelectorAll(".website-icon");for(var i=0;i<this.tabs.length;i++){icons[i].style.backgroundImage=cr.icon.getFavicon(this.tabs[i].url)}})},isWindowSeparatorIndex_:function(index,separatorIndexes){return this.separatorIndexes.indexOf(index)!=-1},getCollapseIcon_:function(opened){return opened?"cr:expand-less":"cr:expand-more"},getCollapseTitle_:function(opened){return opened?loadTimeData.getString("collapseSessionButton"):loadTimeData.getString("expandSessionButton")},onMenuButtonTap_:function(e){this.fire("toggle-menu",{target:Polymer.dom(e).localTarget,tag:this.sessionTag});e.stopPropagation()},onLinkRightClick_:function(){md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.LINK_RIGHT_CLICKED,SyncedTabsHistogram.LIMIT)}});
 // Copyright 2016 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
-var ForeignDeviceInternal;
-
-Polymer({
-  is: 'history-synced-device-manager',
-  properties: {
-    sessionList: {
-      type: Array,
-      observer: 'updateSyncedDevices'
-    },
-    searchTerm: {
-      type: String,
-      observer: 'searchTermChanged'
-    },
-    syncedDevices_: {
-      type: Array,
-      value: function() {
-        return [];
-      }
-    },
-    signInState: {
-      type: Boolean,
-      observer: 'signInStateChanged_'
-    },
-    guestSession_: {
-      type: Boolean,
-      value: loadTimeData.getBoolean('isGuestSession')
-    },
-    fetchingSyncedTabs_: {
-      type: Boolean,
-      value: false
-    },
-    hasSeenForeignData_: Boolean
-  },
-  listeners: {
-    'toggle-menu': 'onToggleMenu_',
-    scroll: 'onListScroll_'
-  },
-  attached: function() {
-    chrome.send('otherDevicesInitialized');
-    md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.INITIALIZED, SyncedTabsHistogram.LIMIT);
-  },
-  getContentScrollTarget: function() {
-    return this;
-  },
-  createInternalDevice_: function(session) {
-    var tabs = [];
-    var separatorIndexes = [];
-    for (var i = 0; i < session.windows.length; i++) {
-      var windowId = session.windows[i].sessionId;
-      var newTabs = session.windows[i].tabs;
-      if (newTabs.length == 0) continue;
-      newTabs.forEach(function(tab) {
-        tab.windowId = windowId;
-      });
-      var windowAdded = false;
-      if (!this.searchTerm) {
-        tabs = tabs.concat(newTabs);
-        windowAdded = true;
-      } else {
-        var searchText = this.searchTerm.toLowerCase();
-        for (var j = 0; j < newTabs.length; j++) {
-          var tab = newTabs[j];
-          if (tab.title.toLowerCase().indexOf(searchText) != -1) {
-            tabs.push(tab);
-            windowAdded = true;
-          }
-        }
-      }
-      if (windowAdded && i != session.windows.length - 1) separatorIndexes.push(tabs.length - 1);
-    }
-    return {
-      device: session.name,
-      lastUpdateTime: '– ' + session.modifiedTime,
-      opened: true,
-      separatorIndexes: separatorIndexes,
-      timestamp: session.timestamp,
-      tabs: tabs,
-      tag: session.tag
-    };
-  },
-  onSignInTap_: function() {
-    chrome.send('startSignInFlow');
-  },
-  onListScroll_: function() {
-    var menu = this.$.menu.getIfExists();
-    if (menu) menu.closeMenu();
-  },
-  onToggleMenu_: function(e) {
-    var menu = this.$.menu.get();
-    menu.toggleMenu(e.detail.target, e.detail.tag);
-    if (menu.menuOpen) {
-      md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.SHOW_SESSION_MENU, SyncedTabsHistogram.LIMIT);
-    }
-  },
-  onOpenAllTap_: function() {
-    var menu = assert(this.$.menu.getIfExists());
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.OPEN_ALL, SyncedTabsHistogram.LIMIT);
-    browserService.openForeignSessionAllTabs(menu.itemData);
-    menu.closeMenu();
-  },
-  onDeleteSessionTap_: function() {
-    var menu = assert(this.$.menu.getIfExists());
-    var browserService = md_history.BrowserService.getInstance();
-    browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.HIDE_FOR_NOW, SyncedTabsHistogram.LIMIT);
-    browserService.deleteForeignSession(menu.itemData);
-    menu.closeMenu();
-  },
-  clearDisplayedSyncedDevices_: function() {
-    this.syncedDevices_ = [];
-  },
-  showNoSyncedMessage: function(signInState, syncedDevicesLength, guestSession) {
-    if (guestSession) return true;
-    return signInState && syncedDevicesLength == 0;
-  },
-  showSignInGuide: function(signInState, guestSession) {
-    var show = !signInState && !guestSession;
-    if (show) {
-      md_history.BrowserService.getInstance().recordAction('Signin_Impression_FromRecentTabs');
-    }
-    return show;
-  },
-  noSyncedTabsMessage: function() {
-    var stringName = this.fetchingSyncedTabs_ ? 'loading' : 'noSyncedResults';
-    if (this.searchTerm !== '') stringName = 'noSearchResults';
-    return loadTimeData.getString(stringName);
-  },
-  updateSyncedDevices: function(sessionList) {
-    this.fetchingSyncedTabs_ = false;
-    if (!sessionList) return;
-    if (sessionList.length > 0 && !this.hasSeenForeignData_) {
-      this.hasSeenForeignData_ = true;
-      md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME, SyncedTabsHistogram.HAS_FOREIGN_DATA, SyncedTabsHistogram.LIMIT);
-    }
-    var updateCount = Math.min(sessionList.length, this.syncedDevices_.length);
-    for (var i = 0; i < updateCount; i++) {
-      var oldDevice = this.syncedDevices_[i];
-      if (oldDevice.tag != sessionList[i].tag || oldDevice.timestamp != sessionList[i].timestamp) {
-        var device = this.createInternalDevice_(sessionList[i]);
-        if (device.tabs.length != 0) this.splice('syncedDevices_', i, 1, device);
-      }
-    }
-    if (sessionList.length >= this.syncedDevices_.length) {
-      for (var i = updateCount; i < sessionList.length; i++) {
-        var device = this.createInternalDevice_(sessionList[i]);
-        if (device.tabs.length != 0) this.push('syncedDevices_', device);
-      }
-    } else {
-      this.splice('syncedDevices_', updateCount, this.syncedDevices_.length - updateCount);
-    }
-  },
-  tabSyncDisabled: function() {
-    this.fetchingSyncedTabs_ = false;
-    this.clearDisplayedSyncedDevices_();
-  },
-  signInStateChanged_: function() {
-    this.fire('history-view-changed');
-    if (!this.signInState) {
-      this.clearDisplayedSyncedDevices_();
-      return;
-    }
-    this.fetchingSyncedTabs_ = true;
-  },
-  searchTermChanged: function(searchTerm) {
-    this.clearDisplayedSyncedDevices_();
-    this.updateSyncedDevices(this.sessionList);
-  }
-});
-
+var ForeignDeviceInternal;Polymer({is:"history-synced-device-manager",properties:{sessionList:{type:Array,observer:"updateSyncedDevices"},searchTerm:{type:String,observer:"searchTermChanged"},syncedDevices_:{type:Array,value:function(){return[]}},signInState:{type:Boolean,observer:"signInStateChanged_"},guestSession_:{type:Boolean,value:loadTimeData.getBoolean("isGuestSession")},fetchingSyncedTabs_:{type:Boolean,value:false},hasSeenForeignData_:Boolean},listeners:{"toggle-menu":"onToggleMenu_",scroll:"onListScroll_"},attached:function(){chrome.send("otherDevicesInitialized");md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.INITIALIZED,SyncedTabsHistogram.LIMIT)},getContentScrollTarget:function(){return this},createInternalDevice_:function(session){var tabs=[];var separatorIndexes=[];for(var i=0;i<session.windows.length;i++){var windowId=session.windows[i].sessionId;var newTabs=session.windows[i].tabs;if(newTabs.length==0)continue;newTabs.forEach(function(tab){tab.windowId=windowId});var windowAdded=false;if(!this.searchTerm){tabs=tabs.concat(newTabs);windowAdded=true}else{var searchText=this.searchTerm.toLowerCase();for(var j=0;j<newTabs.length;j++){var tab=newTabs[j];if(tab.title.toLowerCase().indexOf(searchText)!=-1){tabs.push(tab);windowAdded=true}}}if(windowAdded&&i!=session.windows.length-1)separatorIndexes.push(tabs.length-1)}return{device:session.name,lastUpdateTime:"– "+session.modifiedTime,opened:true,separatorIndexes:separatorIndexes,timestamp:session.timestamp,tabs:tabs,tag:session.tag}},onSignInTap_:function(){chrome.send("startSignInFlow")},onListScroll_:function(){var menu=this.$.menu.getIfExists();if(menu)menu.closeMenu()},onToggleMenu_:function(e){var menu=this.$.menu.get();menu.toggleMenu(e.detail.target,e.detail.tag);if(menu.menuOpen){md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.SHOW_SESSION_MENU,SyncedTabsHistogram.LIMIT)}},onOpenAllTap_:function(){var menu=assert(this.$.menu.getIfExists());var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.OPEN_ALL,SyncedTabsHistogram.LIMIT);browserService.openForeignSessionAllTabs(menu.itemData);menu.closeMenu()},onDeleteSessionTap_:function(){var menu=assert(this.$.menu.getIfExists());var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.HIDE_FOR_NOW,SyncedTabsHistogram.LIMIT);browserService.deleteForeignSession(menu.itemData);menu.closeMenu()},clearDisplayedSyncedDevices_:function(){this.syncedDevices_=[]},showNoSyncedMessage:function(signInState,syncedDevicesLength,guestSession){if(guestSession)return true;return signInState&&syncedDevicesLength==0},showSignInGuide:function(signInState,guestSession){var show=!signInState&&!guestSession;if(show){md_history.BrowserService.getInstance().recordAction("Signin_Impression_FromRecentTabs")}return show},noSyncedTabsMessage:function(){var stringName=this.fetchingSyncedTabs_?"loading":"noSyncedResults";if(this.searchTerm!=="")stringName="noSearchResults";return loadTimeData.getString(stringName)},updateSyncedDevices:function(sessionList){this.fetchingSyncedTabs_=false;if(!sessionList)return;if(sessionList.length>0&&!this.hasSeenForeignData_){this.hasSeenForeignData_=true;md_history.BrowserService.getInstance().recordHistogram(SYNCED_TABS_HISTOGRAM_NAME,SyncedTabsHistogram.HAS_FOREIGN_DATA,SyncedTabsHistogram.LIMIT)}var updateCount=Math.min(sessionList.length,this.syncedDevices_.length);for(var i=0;i<updateCount;i++){var oldDevice=this.syncedDevices_[i];if(oldDevice.tag!=sessionList[i].tag||oldDevice.timestamp!=sessionList[i].timestamp){var device=this.createInternalDevice_(sessionList[i]);if(device.tabs.length!=0)this.splice("syncedDevices_",i,1,device)}}if(sessionList.length>=this.syncedDevices_.length){for(var i=updateCount;i<sessionList.length;i++){var device=this.createInternalDevice_(sessionList[i]);if(device.tabs.length!=0)this.push("syncedDevices_",device)}}else{this.splice("syncedDevices_",updateCount,this.syncedDevices_.length-updateCount)}},tabSyncDisabled:function(){this.fetchingSyncedTabs_=false;this.clearDisplayedSyncedDevices_()},signInStateChanged_:function(){this.fire("history-view-changed");if(!this.signInState){this.clearDisplayedSyncedDevices_();return}this.fetchingSyncedTabs_=true},searchTermChanged:function(searchTerm){this.clearDisplayedSyncedDevices_();this.updateSyncedDevices(this.sessionList)}});
 // Copyright 2016 The Chromium 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({
-  is: 'cr-dialog',
-  "extends": 'dialog',
-  created: function() {
-    window.addEventListener('popstate', function() {
-      if (this.open) this.cancel();
-    }.bind(this));
-  },
-  cancel: function() {
-    this.fire('cancel');
-    HTMLDialogElement.prototype.close.call(this, '');
-  },
-  close: function(opt_returnValue) {
-    HTMLDialogElement.prototype.close.call(this, 'success');
-  },
-  getCloseButton: function() {
-    return this.$.close;
-  }
-});
-
-Polymer({
-  is: 'app-drawer',
-  properties: {
-    opened: {
-      type: Boolean,
-      value: false,
-      notify: true,
-      reflectToAttribute: true
-    },
-    persistent: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    align: {
-      type: String,
-      value: 'left'
-    },
-    position: {
-      type: String,
-      readOnly: true,
-      value: 'left',
-      reflectToAttribute: true
-    },
-    swipeOpen: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    },
-    noFocusTrap: {
-      type: Boolean,
-      value: false
-    }
-  },
-  observers: [ 'resetLayout(position)', '_resetPosition(align, isAttached)' ],
-  _translateOffset: 0,
-  _trackDetails: null,
-  _drawerState: 0,
-  _boundEscKeydownHandler: null,
-  _firstTabStop: null,
-  _lastTabStop: null,
-  ready: function() {
-    this.setScrollDirection('y');
-    this._setTransitionDuration('0s');
-  },
-  attached: function() {
-    Polymer.RenderStatus.afterNextRender(this, function() {
-      this._setTransitionDuration('');
-      this._boundEscKeydownHandler = this._escKeydownHandler.bind(this);
-      this._resetDrawerState();
-      this.listen(this, 'track', '_track');
-      this.addEventListener('transitionend', this._transitionend.bind(this));
-      this.addEventListener('keydown', this._tabKeydownHandler.bind(this));
-    });
-  },
-  detached: function() {
-    document.removeEventListener('keydown', this._boundEscKeydownHandler);
-  },
-  open: function() {
-    this.opened = true;
-  },
-  close: function() {
-    this.opened = false;
-  },
-  toggle: function() {
-    this.opened = !this.opened;
-  },
-  getWidth: function() {
-    return this.$.contentContainer.offsetWidth;
-  },
-  resetLayout: function() {
-    this.debounce('_resetLayout', function() {
-      this.fire('app-drawer-reset-layout');
-    }, 1);
-  },
-  _isRTL: function() {
-    return window.getComputedStyle(this).direction === 'rtl';
-  },
-  _resetPosition: function() {
-    switch (this.align) {
-     case 'start':
-      this._setPosition(this._isRTL() ? 'right' : 'left');
-      return;
-
-     case 'end':
-      this._setPosition(this._isRTL() ? 'left' : 'right');
-      return;
-    }
-    this._setPosition(this.align);
-  },
-  _escKeydownHandler: function(event) {
-    var ESC_KEYCODE = 27;
-    if (event.keyCode === ESC_KEYCODE) {
-      event.preventDefault();
-      this.close();
-    }
-  },
-  _track: function(event) {
-    if (this.persistent) {
-      return;
-    }
-    event.preventDefault();
-    switch (event.detail.state) {
-     case 'start':
-      this._trackStart(event);
-      break;
-
-     case 'track':
-      this._trackMove(event);
-      break;
-
-     case 'end':
-      this._trackEnd(event);
-      break;
-    }
-  },
-  _trackStart: function(event) {
-    this._drawerState = this._DRAWER_STATE.TRACKING;
-    this._setTransitionDuration('0s');
-    this.style.visibility = 'visible';
-    var rect = this.$.contentContainer.getBoundingClientRect();
-    if (this.position === 'left') {
-      this._translateOffset = rect.left;
-    } else {
-      this._translateOffset = rect.right - window.innerWidth;
-    }
-    this._trackDetails = [];
-  },
-  _trackMove: function(event) {
-    this._translateDrawer(event.detail.dx + this._translateOffset);
-    this._trackDetails.push({
-      dx: event.detail.dx,
-      timeStamp: Date.now()
-    });
-  },
-  _trackEnd: function(event) {
-    var x = event.detail.dx + this._translateOffset;
-    var drawerWidth = this.getWidth();
-    var isPositionLeft = this.position === 'left';
-    var isInEndState = isPositionLeft ? x >= 0 || x <= -drawerWidth : x <= 0 || x >= drawerWidth;
-    if (!isInEndState) {
-      var trackDetails = this._trackDetails;
-      this._trackDetails = null;
-      this._flingDrawer(event, trackDetails);
-      if (this._drawerState === this._DRAWER_STATE.FLINGING) {
-        return;
-      }
-    }
-    var halfWidth = drawerWidth / 2;
-    if (event.detail.dx < -halfWidth) {
-      this.opened = this.position === 'right';
-    } else if (event.detail.dx > halfWidth) {
-      this.opened = this.position === 'left';
-    }
-    if (isInEndState) {
-      this._resetDrawerState();
-    }
-    this._setTransitionDuration('');
-    this._resetDrawerTranslate();
-    this.style.visibility = '';
-  },
-  _calculateVelocity: function(event, trackDetails) {
-    var now = Date.now();
-    var timeLowerBound = now - 100;
-    var trackDetail;
-    var min = 0;
-    var max = trackDetails.length - 1;
-    while (min <= max) {
-      var mid = min + max >> 1;
-      var d = trackDetails[mid];
-      if (d.timeStamp >= timeLowerBound) {
-        trackDetail = d;
-        max = mid - 1;
-      } else {
-        min = mid + 1;
-      }
-    }
-    if (trackDetail) {
-      var dx = event.detail.dx - trackDetail.dx;
-      var dt = now - trackDetail.timeStamp || 1;
-      return dx / dt;
-    }
-    return 0;
-  },
-  _flingDrawer: function(event, trackDetails) {
-    var velocity = this._calculateVelocity(event, trackDetails);
-    if (Math.abs(velocity) < this._MIN_FLING_THRESHOLD) {
-      return;
-    }
-    this._drawerState = this._DRAWER_STATE.FLINGING;
-    var x = event.detail.dx + this._translateOffset;
-    var drawerWidth = this.getWidth();
-    var isPositionLeft = this.position === 'left';
-    var isVelocityPositive = velocity > 0;
-    var isClosingLeft = !isVelocityPositive && isPositionLeft;
-    var isClosingRight = isVelocityPositive && !isPositionLeft;
-    var dx;
-    if (isClosingLeft) {
-      dx = -(x + drawerWidth);
-    } else if (isClosingRight) {
-      dx = drawerWidth - x;
-    } else {
-      dx = -x;
-    }
-    if (isVelocityPositive) {
-      velocity = Math.max(velocity, this._MIN_TRANSITION_VELOCITY);
-      this.opened = this.position === 'left';
-    } else {
-      velocity = Math.min(velocity, -this._MIN_TRANSITION_VELOCITY);
-      this.opened = this.position === 'right';
-    }
-    this._setTransitionDuration(this._FLING_INITIAL_SLOPE * dx / velocity + 'ms');
-    this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);
-    this._resetDrawerTranslate();
-  },
-  _transitionend: function(event) {
-    var target = Polymer.dom(event).rootTarget;
-    if (target === this.$.contentContainer || target === this.$.scrim) {
-      if (this._drawerState === this._DRAWER_STATE.FLINGING) {
-        this._setTransitionDuration('');
-        this._setTransitionTimingFunction('');
-        this.style.visibility = '';
-      }
-      this._resetDrawerState();
-    }
-  },
-  _setTransitionDuration: function(duration) {
-    this.$.contentContainer.style.transitionDuration = duration;
-    this.$.scrim.style.transitionDuration = duration;
-  },
-  _setTransitionTimingFunction: function(timingFunction) {
-    this.$.contentContainer.style.transitionTimingFunction = timingFunction;
-    this.$.scrim.style.transitionTimingFunction = timingFunction;
-  },
-  _translateDrawer: function(x) {
-    var drawerWidth = this.getWidth();
-    if (this.position === 'left') {
-      x = Math.max(-drawerWidth, Math.min(x, 0));
-      this.$.scrim.style.opacity = 1 + x / drawerWidth;
-    } else {
-      x = Math.max(0, Math.min(x, drawerWidth));
-      this.$.scrim.style.opacity = 1 - x / drawerWidth;
-    }
-    this.translate3d(x + 'px', '0', '0', this.$.contentContainer);
-  },
-  _resetDrawerTranslate: function() {
-    this.$.scrim.style.opacity = '';
-    this.transform('', this.$.contentContainer);
-  },
-  _resetDrawerState: function() {
-    var oldState = this._drawerState;
-    if (this.opened) {
-      this._drawerState = this.persistent ? this._DRAWER_STATE.OPENED_PERSISTENT : this._DRAWER_STATE.OPENED;
-    } else {
-      this._drawerState = this._DRAWER_STATE.CLOSED;
-    }
-    if (oldState !== this._drawerState) {
-      if (this._drawerState === this._DRAWER_STATE.OPENED) {
-        this._setKeyboardFocusTrap();
-        document.addEventListener('keydown', this._boundEscKeydownHandler);
-        document.body.style.overflow = 'hidden';
-      } else {
-        document.removeEventListener('keydown', this._boundEscKeydownHandler);
-        document.body.style.overflow = '';
-      }
-      if (oldState !== this._DRAWER_STATE.INIT) {
-        this.fire('app-drawer-transitioned');
-      }
-    }
-  },
-  _setKeyboardFocusTrap: function() {
-    if (this.noFocusTrap) {
-      return;
-    }
-    var focusableElementsSelector = [ 'a[href]:not([tabindex="-1"])', 'area[href]:not([tabindex="-1"])', 'input:not([disabled]):not([tabindex="-1"])', 'select:not([disabled]):not([tabindex="-1"])', 'textarea:not([disabled]):not([tabindex="-1"])', 'button:not([disabled]):not([tabindex="-1"])', 'iframe:not([tabindex="-1"])', '[tabindex]:not([tabindex="-1"])', '[contentEditable=true]:not([tabindex="-1"])' ].join(',');
-    var focusableElements = Polymer.dom(this).querySelectorAll(focusableElementsSelector);
-    if (focusableElements.length > 0) {
-      this._firstTabStop = focusableElements[0];
-      this._lastTabStop = focusableElements[focusableElements.length - 1];
-    } else {
-      this._firstTabStop = null;
-      this._lastTabStop = null;
-    }
-    var tabindex = this.getAttribute('tabindex');
-    if (tabindex && parseInt(tabindex, 10) > -1) {
-      this.focus();
-    } else if (this._firstTabStop) {
-      this._firstTabStop.focus();
-    }
-  },
-  _tabKeydownHandler: function(event) {
-    if (this.noFocusTrap) {
-      return;
-    }
-    var TAB_KEYCODE = 9;
-    if (this._drawerState === this._DRAWER_STATE.OPENED && event.keyCode === TAB_KEYCODE) {
-      if (event.shiftKey) {
-        if (this._firstTabStop && Polymer.dom(event).localTarget === this._firstTabStop) {
-          event.preventDefault();
-          this._lastTabStop.focus();
-        }
-      } else {
-        if (this._lastTabStop && Polymer.dom(event).localTarget === this._lastTabStop) {
-          event.preventDefault();
-          this._firstTabStop.focus();
-        }
-      }
-    }
-  },
-  _MIN_FLING_THRESHOLD: .2,
-  _MIN_TRANSITION_VELOCITY: 1.2,
-  _FLING_TIMING_FUNCTION: 'cubic-bezier(0.667, 1, 0.667, 1)',
-  _FLING_INITIAL_SLOPE: 1.5,
-  _DRAWER_STATE: {
-    INIT: 0,
-    OPENED: 1,
-    OPENED_PERSISTENT: 2,
-    CLOSED: 3,
-    TRACKING: 4,
-    FLINGING: 5
-  }
-});
-
-Polymer.IronFormElementBehavior = {
-  properties: {
-    name: {
-      type: String
-    },
-    value: {
-      notify: true,
-      type: String
-    },
-    required: {
-      type: Boolean,
-      value: false
-    },
-    _parentForm: {
-      type: Object
-    }
-  },
-  attached: function() {
-    this.fire('iron-form-element-register');
-  },
-  detached: function() {
-    if (this._parentForm) {
-      this._parentForm.fire('iron-form-element-unregister', {
-        target: this
-      });
-    }
-  }
-};
-
-Polymer.IronCheckedElementBehaviorImpl = {
-  properties: {
-    checked: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true,
-      notify: true,
-      observer: '_checkedChanged'
-    },
-    toggles: {
-      type: Boolean,
-      value: true,
-      reflectToAttribute: true
-    },
-    value: {
-      type: String,
-      value: 'on',
-      observer: '_valueChanged'
-    }
-  },
-  observers: [ '_requiredChanged(required)' ],
-  created: function() {
-    this._hasIronCheckedElementBehavior = true;
-  },
-  _getValidity: function(_value) {
-    return this.disabled || !this.required || this.checked;
-  },
-  _requiredChanged: function() {
-    if (this.required) {
-      this.setAttribute('aria-required', 'true');
-    } else {
-      this.removeAttribute('aria-required');
-    }
-  },
-  _checkedChanged: function() {
-    this.active = this.checked;
-    this.fire('iron-change');
-  },
-  _valueChanged: function() {
-    if (this.value === undefined || this.value === null) {
-      this.value = 'on';
-    }
-  }
-};
-
-Polymer.IronCheckedElementBehavior = [ Polymer.IronFormElementBehavior, Polymer.IronValidatableBehavior, Polymer.IronCheckedElementBehaviorImpl ];
-
-Polymer.PaperCheckedElementBehaviorImpl = {
-  _checkedChanged: function() {
-    Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this);
-    if (this.hasRipple()) {
-      if (this.checked) {
-        this._ripple.setAttribute('checked', '');
-      } else {
-        this._ripple.removeAttribute('checked');
-      }
-    }
-  },
-  _buttonStateChanged: function() {
-    Polymer.PaperRippleBehavior._buttonStateChanged.call(this);
-    if (this.disabled) {
-      return;
-    }
-    if (this.isAttached) {
-      this.checked = this.active;
-    }
-  }
-};
-
-Polymer.PaperCheckedElementBehavior = [ Polymer.PaperInkyFocusBehavior, Polymer.IronCheckedElementBehavior, Polymer.PaperCheckedElementBehaviorImpl ];
-
-Polymer({
-  is: 'paper-checkbox',
-  behaviors: [ Polymer.PaperCheckedElementBehavior ],
-  hostAttributes: {
-    role: 'checkbox',
-    'aria-checked': false,
-    tabindex: 0
-  },
-  properties: {
-    ariaActiveAttribute: {
-      type: String,
-      value: 'aria-checked'
-    }
-  },
-  attached: function() {
-    var inkSize = this.getComputedStyleValue('--calculated-paper-checkbox-ink-size');
-    if (inkSize === '-1px') {
-      var checkboxSize = parseFloat(this.getComputedStyleValue('--calculated-paper-checkbox-size'));
-      var defaultInkSize = Math.floor(8 / 3 * checkboxSize);
-      if (defaultInkSize % 2 !== checkboxSize % 2) {
-        defaultInkSize++;
-      }
-      this.customStyle['--paper-checkbox-ink-size'] = defaultInkSize + 'px';
-      this.updateStyles();
-    }
-  },
-  _computeCheckboxClass: function(checked, invalid) {
-    var className = '';
-    if (checked) {
-      className += 'checked ';
-    }
-    if (invalid) {
-      className += 'invalid';
-    }
-    return className;
-  },
-  _computeCheckmarkClass: function(checked) {
-    return checked ? '' : 'hidden';
-  },
-  _createRipple: function() {
-    this._rippleContainer = this.$.checkboxContainer;
-    return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this);
-  }
-});
-
-Polymer({
-  is: 'paper-tab',
-  behaviors: [ Polymer.IronControlState, Polymer.IronButtonState, Polymer.PaperRippleBehavior ],
-  properties: {
-    link: {
-      type: Boolean,
-      value: false,
-      reflectToAttribute: true
-    }
-  },
-  hostAttributes: {
-    role: 'tab'
-  },
-  listeners: {
-    down: '_updateNoink',
-    tap: '_onTap'
-  },
-  attached: function() {
-    this._updateNoink();
-  },
-  get _parentNoink() {
-    var parent = Polymer.dom(this).parentNode;
-    return !!parent && !!parent.noink;
-  },
-  _updateNoink: function() {
-    this.noink = !!this.noink || !!this._parentNoink;
-  },
-  _onTap: function(event) {
-    if (this.link) {
-      var anchor = this.queryEffectiveChildren('a');
-      if (!anchor) {
-        return;
-      }
-      if (event.target === anchor) {
-        return;
-      }
-      anchor.click();
-    }
-  }
-});
-
-Polymer.IronMenuBehaviorImpl = {
-  properties: {
-    focusedItem: {
-      observer: '_focusedItemChanged',
-      readOnly: true,
-      type: Object
-    },
-    attrForItemTitle: {
-      type: String
-    }
-  },
-  hostAttributes: {
-    role: 'menu',
-    tabindex: '0'
-  },
-  observers: [ '_updateMultiselectable(multi)' ],
-  listeners: {
-    focus: '_onFocus',
-    keydown: '_onKeydown',
-    'iron-items-changed': '_onIronItemsChanged'
-  },
-  keyBindings: {
-    up: '_onUpKey',
-    down: '_onDownKey',
-    esc: '_onEscKey',
-    'shift+tab:keydown': '_onShiftTabDown'
-  },
-  attached: function() {
-    this._resetTabindices();
-  },
-  select: function(value) {
-    if (this._defaultFocusAsync) {
-      this.cancelAsync(this._defaultFocusAsync);
-      this._defaultFocusAsync = null;
-    }
-    var item = this._valueToItem(value);
-    if (item && item.hasAttribute('disabled')) return;
-    this._setFocusedItem(item);
-    Polymer.IronMultiSelectableBehaviorImpl.select.apply(this, arguments);
-  },
-  _resetTabindices: function() {
-    var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
-    this.items.forEach(function(item) {
-      item.setAttribute('tabindex', item === selectedItem ? '0' : '-1');
-    }, this);
-  },
-  _updateMultiselectable: function(multi) {
-    if (multi) {
-      this.setAttribute('aria-multiselectable', 'true');
-    } else {
-      this.removeAttribute('aria-multiselectable');
-    }
-  },
-  _focusWithKeyboardEvent: function(event) {
-    for (var i = 0, item; item = this.items[i]; i++) {
-      var attr = this.attrForItemTitle || 'textContent';
-      var title = item[attr] || item.getAttribute(attr);
-      if (!item.hasAttribute('disabled') && title && title.trim().charAt(0).toLowerCase() === String.fromCharCode(event.keyCode).toLowerCase()) {
-        this._setFocusedItem(item);
-        break;
-      }
-    }
-  },
-  _focusPrevious: function() {
-    var length = this.items.length;
-    var curFocusIndex = Number(this.indexOf(this.focusedItem));
-    for (var i = 1; i < length + 1; i++) {
-      var item = this.items[(curFocusIndex - i + length) % length];
-      if (!item.hasAttribute('disabled')) {
-        var owner = Polymer.dom(item).getOwnerRoot() || document;
-        this._setFocusedItem(item);
-        if (Polymer.dom(owner).activeElement == item) {
-          return;
-        }
-      }
-    }
-  },
-  _focusNext: function() {
-    var length = this.items.length;
-    var curFocusIndex = Number(this.indexOf(this.focusedItem));
-    for (var i = 1; i < length + 1; i++) {
-      var item = this.items[(curFocusIndex + i) % length];
-      if (!item.hasAttribute('disabled')) {
-        var owner = Polymer.dom(item).getOwnerRoot() || document;
-        this._setFocusedItem(item);
-        if (Polymer.dom(owner).activeElement == item) {
-          return;
-        }
-      }
-    }
-  },
-  _applySelection: function(item, isSelected) {
-    if (isSelected) {
-      item.setAttribute('aria-selected', 'true');
-    } else {
-      item.removeAttribute('aria-selected');
-    }
-    Polymer.IronSelectableBehavior._applySelection.apply(this, arguments);
-  },
-  _focusedItemChanged: function(focusedItem, old) {
-    old && old.setAttribute('tabindex', '-1');
-    if (focusedItem) {
-      focusedItem.setAttribute('tabindex', '0');
-      focusedItem.focus();
-    }
-  },
-  _onIronItemsChanged: function(event) {
-    if (event.detail.addedNodes.length) {
-      this._resetTabindices();
-    }
-  },
-  _onShiftTabDown: function(event) {
-    var oldTabIndex = this.getAttribute('tabindex');
-    Polymer.IronMenuBehaviorImpl._shiftTabPressed = true;
-    this._setFocusedItem(null);
-    this.setAttribute('tabindex', '-1');
-    this.async(function() {
-      this.setAttribute('tabindex', oldTabIndex);
-      Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
-    }, 1);
-  },
-  _onFocus: function(event) {
-    if (Polymer.IronMenuBehaviorImpl._shiftTabPressed) {
-      return;
-    }
-    var rootTarget = Polymer.dom(event).rootTarget;
-    if (rootTarget !== this && typeof rootTarget.tabIndex !== "undefined" && !this.isLightDescendant(rootTarget)) {
-      return;
-    }
-    this._defaultFocusAsync = this.async(function() {
-      var selectedItem = this.multi ? this.selectedItems && this.selectedItems[0] : this.selectedItem;
-      this._setFocusedItem(null);
-      if (selectedItem) {
-        this._setFocusedItem(selectedItem);
-      } else if (this.items[0]) {
-        this._focusNext();
-      }
-    });
-  },
-  _onUpKey: function(event) {
-    this._focusPrevious();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onDownKey: function(event) {
-    this._focusNext();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onEscKey: function(event) {
-    this.focusedItem.blur();
-  },
-  _onKeydown: function(event) {
-    if (!this.keyboardEventMatchesKeys(event, 'up down esc')) {
-      this._focusWithKeyboardEvent(event);
-    }
-    event.stopPropagation();
-  },
-  _activateHandler: function(event) {
-    Polymer.IronSelectableBehavior._activateHandler.call(this, event);
-    event.stopPropagation();
-  }
-};
-
-Polymer.IronMenuBehaviorImpl._shiftTabPressed = false;
-
-Polymer.IronMenuBehavior = [ Polymer.IronMultiSelectableBehavior, Polymer.IronA11yKeysBehavior, Polymer.IronMenuBehaviorImpl ];
-
-Polymer.IronMenubarBehaviorImpl = {
-  hostAttributes: {
-    role: 'menubar'
-  },
-  keyBindings: {
-    left: '_onLeftKey',
-    right: '_onRightKey'
-  },
-  _onUpKey: function(event) {
-    this.focusedItem.click();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onDownKey: function(event) {
-    this.focusedItem.click();
-    event.detail.keyboardEvent.preventDefault();
-  },
-  get _isRTL() {
-    return window.getComputedStyle(this)['direction'] === 'rtl';
-  },
-  _onLeftKey: function(event) {
-    if (this._isRTL) {
-      this._focusNext();
-    } else {
-      this._focusPrevious();
-    }
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onRightKey: function(event) {
-    if (this._isRTL) {
-      this._focusPrevious();
-    } else {
-      this._focusNext();
-    }
-    event.detail.keyboardEvent.preventDefault();
-  },
-  _onKeydown: function(event) {
-    if (this.keyboardEventMatchesKeys(event, 'up down left right esc')) {
-      return;
-    }
-    this._focusWithKeyboardEvent(event);
-  }
-};
-
-Polymer.IronMenubarBehavior = [ Polymer.IronMenuBehavior, Polymer.IronMenubarBehaviorImpl ];
-
-Polymer({
-  is: 'paper-tabs',
-  behaviors: [ Polymer.IronResizableBehavior, Polymer.IronMenubarBehavior ],
-  properties: {
-    noink: {
-      type: Boolean,
-      value: false,
-      observer: '_noinkChanged'
-    },
-    noBar: {
-      type: Boolean,
-      value: false
-    },
-    noSlide: {
-      type: Boolean,
-      value: false
-    },
-    scrollable: {
-      type: Boolean,
-      value: false
-    },
-    fitContainer: {
-      type: Boolean,
-      value: false
-    },
-    disableDrag: {
-      type: Boolean,
-      value: false
-    },
-    hideScrollButtons: {
-      type: Boolean,
-      value: false
-    },
-    alignBottom: {
-      type: Boolean,
-      value: false
-    },
-    selectable: {
-      type: String,
-      value: 'paper-tab'
-    },
-    autoselect: {
-      type: Boolean,
-      value: false
-    },
-    autoselectDelay: {
-      type: Number,
-      value: 0
-    },
-    _step: {
-      type: Number,
-      value: 10
-    },
-    _holdDelay: {
-      type: Number,
-      value: 1
-    },
-    _leftHidden: {
-      type: Boolean,
-      value: false
-    },
-    _rightHidden: {
-      type: Boolean,
-      value: false
-    },
-    _previousTab: {
-      type: Object
-    }
-  },
-  hostAttributes: {
-    role: 'tablist'
-  },
-  listeners: {
-    'iron-resize': '_onTabSizingChanged',
-    'iron-items-changed': '_onTabSizingChanged',
-    'iron-select': '_onIronSelect',
-    'iron-deselect': '_onIronDeselect'
-  },
-  keyBindings: {
-    'left:keyup right:keyup': '_onArrowKeyup'
-  },
-  created: function() {
-    this._holdJob = null;
-    this._pendingActivationItem = undefined;
-    this._pendingActivationTimeout = undefined;
-    this._bindDelayedActivationHandler = this._delayedActivationHandler.bind(this);
-    this.addEventListener('blur', this._onBlurCapture.bind(this), true);
-  },
-  ready: function() {
-    this.setScrollDirection('y', this.$.tabsContainer);
-  },
-  detached: function() {
-    this._cancelPendingActivation();
-  },
-  _noinkChanged: function(noink) {
-    var childTabs = Polymer.dom(this).querySelectorAll('paper-tab');
-    childTabs.forEach(noink ? this._setNoinkAttribute : this._removeNoinkAttribute);
-  },
-  _setNoinkAttribute: function(element) {
-    element.setAttribute('noink', '');
-  },
-  _removeNoinkAttribute: function(element) {
-    element.removeAttribute('noink');
-  },
-  _computeScrollButtonClass: function(hideThisButton, scrollable, hideScrollButtons) {
-    if (!scrollable || hideScrollButtons) {
-      return 'hidden';
-    }
-    if (hideThisButton) {
-      return 'not-visible';
-    }
-    return '';
-  },
-  _computeTabsContentClass: function(scrollable, fitContainer) {
-    return scrollable ? 'scrollable' + (fitContainer ? ' fit-container' : '') : ' fit-container';
-  },
-  _computeSelectionBarClass: function(noBar, alignBottom) {
-    if (noBar) {
-      return 'hidden';
-    } else if (alignBottom) {
-      return 'align-bottom';
-    }
-    return '';
-  },
-  _onTabSizingChanged: function() {
-    this.debounce('_onTabSizingChanged', function() {
-      this._scroll();
-      this._tabChanged(this.selectedItem);
-    }, 10);
-  },
-  _onIronSelect: function(event) {
-    this._tabChanged(event.detail.item, this._previousTab);
-    this._previousTab = event.detail.item;
-    this.cancelDebouncer('tab-changed');
-  },
-  _onIronDeselect: function(event) {
-    this.debounce('tab-changed', function() {
-      this._tabChanged(null, this._previousTab);
-      this._previousTab = null;
-    }, 1);
-  },
-  _activateHandler: function() {
-    this._cancelPendingActivation();
-    Polymer.IronMenuBehaviorImpl._activateHandler.apply(this, arguments);
-  },
-  _scheduleActivation: function(item, delay) {
-    this._pendingActivationItem = item;
-    this._pendingActivationTimeout = this.async(this._bindDelayedActivationHandler, delay);
-  },
-  _delayedActivationHandler: function() {
-    var item = this._pendingActivationItem;
-    this._pendingActivationItem = undefined;
-    this._pendingActivationTimeout = undefined;
-    item.fire(this.activateEvent, null, {
-      bubbles: true,
-      cancelable: true
-    });
-  },
-  _cancelPendingActivation: function() {
-    if (this._pendingActivationTimeout !== undefined) {
-      this.cancelAsync(this._pendingActivationTimeout);
-      this._pendingActivationItem = undefined;
-      this._pendingActivationTimeout = undefined;
-    }
-  },
-  _onArrowKeyup: function(event) {
-    if (this.autoselect) {
-      this._scheduleActivation(this.focusedItem, this.autoselectDelay);
-    }
-  },
-  _onBlurCapture: function(event) {
-    if (event.target === this._pendingActivationItem) {
-      this._cancelPendingActivation();
-    }
-  },
-  get _tabContainerScrollSize() {
-    return Math.max(0, this.$.tabsContainer.scrollWidth - this.$.tabsContainer.offsetWidth);
-  },
-  _scroll: function(e, detail) {
-    if (!this.scrollable) {
-      return;
-    }
-    var ddx = detail && -detail.ddx || 0;
-    this._affectScroll(ddx);
-  },
-  _down: function(e) {
-    this.async(function() {
-      if (this._defaultFocusAsync) {
-        this.cancelAsync(this._defaultFocusAsync);
-        this._defaultFocusAsync = null;
-      }
-    }, 1);
-  },
-  _affectScroll: function(dx) {
-    this.$.tabsContainer.scrollLeft += dx;
-    var scrollLeft = this.$.tabsContainer.scrollLeft;
-    this._leftHidden = scrollLeft === 0;
-    this._rightHidden = scrollLeft === this._tabContainerScrollSize;
-  },
-  _onLeftScrollButtonDown: function() {
-    this._scrollToLeft();
-    this._holdJob = setInterval(this._scrollToLeft.bind(this), this._holdDelay);
-  },
-  _onRightScrollButtonDown: function() {
-    this._scrollToRight();
-    this._holdJob = setInterval(this._scrollToRight.bind(this), this._holdDelay);
-  },
-  _onScrollButtonUp: function() {
-    clearInterval(this._holdJob);
-    this._holdJob = null;
-  },
-  _scrollToLeft: function() {
-    this._affectScroll(-this._step);
-  },
-  _scrollToRight: function() {
-    this._affectScroll(this._step);
-  },
-  _tabChanged: function(tab, old) {
-    if (!tab) {
-      this.$.selectionBar.classList.remove('expand');
-      this.$.selectionBar.classList.remove('contract');
-      this._positionBar(0, 0);
-      return;
-    }
-    var r = this.$.tabsContent.getBoundingClientRect();
-    var w = r.width;
-    var tabRect = tab.getBoundingClientRect();
-    var tabOffsetLeft = tabRect.left - r.left;
-    this._pos = {
-      width: this._calcPercent(tabRect.width, w),
-      left: this._calcPercent(tabOffsetLeft, w)
-    };
-    if (this.noSlide || old == null) {
-      this.$.selectionBar.classList.remove('expand');
-      this.$.selectionBar.classList.remove('contract');
-      this._positionBar(this._pos.width, this._pos.left);
-      return;
-    }
-    var oldRect = old.getBoundingClientRect();
-    var oldIndex = this.items.indexOf(old);
-    var index = this.items.indexOf(tab);
-    var m = 5;
-    this.$.selectionBar.classList.add('expand');
-    var moveRight = oldIndex < index;
-    var isRTL = this._isRTL;
-    if (isRTL) {
-      moveRight = !moveRight;
-    }
-    if (moveRight) {
-      this._positionBar(this._calcPercent(tabRect.left + tabRect.width - oldRect.left, w) - m, this._left);
-    } else {
-      this._positionBar(this._calcPercent(oldRect.left + oldRect.width - tabRect.left, w) - m, this._calcPercent(tabOffsetLeft, w) + m);
-    }
-    if (this.scrollable) {
-      this._scrollToSelectedIfNeeded(tabRect.width, tabOffsetLeft);
-    }
-  },
-  _scrollToSelectedIfNeeded: function(tabWidth, tabOffsetLeft) {
-    var l = tabOffsetLeft - this.$.tabsContainer.scrollLeft;
-    if (l < 0) {
-      this.$.tabsContainer.scrollLeft += l;
-    } else {
-      l += tabWidth - this.$.tabsContainer.offsetWidth;
-      if (l > 0) {
-        this.$.tabsContainer.scrollLeft += l;
-      }
-    }
-  },
-  _calcPercent: function(w, w0) {
-    return 100 * w / w0;
-  },
-  _positionBar: function(width, left) {
-    width = width || 0;
-    left = left || 0;
-    this._width = width;
-    this._left = left;
-    this.transform('translateX(' + left + '%) scaleX(' + width / 100 + ')', this.$.selectionBar);
-  },
-  _onBarTransitionEnd: function(e) {
-    var cl = this.$.selectionBar.classList;
-    if (cl.contains('expand')) {
-      cl.remove('expand');
-      cl.add('contract');
-      this._positionBar(this._pos.width, this._pos.left);
-    } else if (cl.contains('contract')) {
-      cl.remove('contract');
-    }
-  }
-});
\ No newline at end of file
+Polymer({is:"cr-dialog","extends":"dialog",created:function(){window.addEventListener("popstate",function(){if(this.open)this.cancel()}.bind(this))},cancel:function(){this.fire("cancel");HTMLDialogElement.prototype.close.call(this,"")},close:function(opt_returnValue){HTMLDialogElement.prototype.close.call(this,"success")},getCloseButton:function(){return this.$.close}});Polymer({is:"app-drawer",properties:{opened:{type:Boolean,value:false,notify:true,reflectToAttribute:true},persistent:{type:Boolean,value:false,reflectToAttribute:true},align:{type:String,value:"left"},position:{type:String,readOnly:true,value:"left",reflectToAttribute:true},swipeOpen:{type:Boolean,value:false,reflectToAttribute:true},noFocusTrap:{type:Boolean,value:false}},observers:["resetLayout(position)","_resetPosition(align, isAttached)"],_translateOffset:0,_trackDetails:null,_drawerState:0,_boundEscKeydownHandler:null,_firstTabStop:null,_lastTabStop:null,ready:function(){this.setScrollDirection("y");this._setTransitionDuration("0s")},attached:function(){Polymer.RenderStatus.afterNextRender(this,function(){this._setTransitionDuration("");this._boundEscKeydownHandler=this._escKeydownHandler.bind(this);this._resetDrawerState();this.listen(this,"track","_track");this.addEventListener("transitionend",this._transitionend.bind(this));this.addEventListener("keydown",this._tabKeydownHandler.bind(this))})},detached:function(){document.removeEventListener("keydown",this._boundEscKeydownHandler)},open:function(){this.opened=true},close:function(){this.opened=false},toggle:function(){this.opened=!this.opened},getWidth:function(){return this.$.contentContainer.offsetWidth},resetLayout:function(){this.debounce("_resetLayout",function(){this.fire("app-drawer-reset-layout")},1)},_isRTL:function(){return window.getComputedStyle(this).direction==="rtl"},_resetPosition:function(){switch(this.align){case"start":this._setPosition(this._isRTL()?"right":"left");return;case"end":this._setPosition(this._isRTL()?"left":"right");return}this._setPosition(this.align)},_escKeydownHandler:function(event){var ESC_KEYCODE=27;if(event.keyCode===ESC_KEYCODE){event.preventDefault();this.close()}},_track:function(event){if(this.persistent){return}event.preventDefault();switch(event.detail.state){case"start":this._trackStart(event);break;case"track":this._trackMove(event);break;case"end":this._trackEnd(event);break}},_trackStart:function(event){this._drawerState=this._DRAWER_STATE.TRACKING;this._setTransitionDuration("0s");this.style.visibility="visible";var rect=this.$.contentContainer.getBoundingClientRect();if(this.position==="left"){this._translateOffset=rect.left}else{this._translateOffset=rect.right-window.innerWidth}this._trackDetails=[]},_trackMove:function(event){this._translateDrawer(event.detail.dx+this._translateOffset);this._trackDetails.push({dx:event.detail.dx,timeStamp:Date.now()})},_trackEnd:function(event){var x=event.detail.dx+this._translateOffset;var drawerWidth=this.getWidth();var isPositionLeft=this.position==="left";var isInEndState=isPositionLeft?x>=0||x<=-drawerWidth:x<=0||x>=drawerWidth;if(!isInEndState){var trackDetails=this._trackDetails;this._trackDetails=null;this._flingDrawer(event,trackDetails);if(this._drawerState===this._DRAWER_STATE.FLINGING){return}}var halfWidth=drawerWidth/2;if(event.detail.dx<-halfWidth){this.opened=this.position==="right"}else if(event.detail.dx>halfWidth){this.opened=this.position==="left"}if(isInEndState){this._resetDrawerState()}this._setTransitionDuration("");this._resetDrawerTranslate();this.style.visibility=""},_calculateVelocity:function(event,trackDetails){var now=Date.now();var timeLowerBound=now-100;var trackDetail;var min=0;var max=trackDetails.length-1;while(min<=max){var mid=min+max>>1;var d=trackDetails[mid];if(d.timeStamp>=timeLowerBound){trackDetail=d;max=mid-1}else{min=mid+1}}if(trackDetail){var dx=event.detail.dx-trackDetail.dx;var dt=now-trackDetail.timeStamp||1;return dx/dt}return 0},_flingDrawer:function(event,trackDetails){var velocity=this._calculateVelocity(event,trackDetails);if(Math.abs(velocity)<this._MIN_FLING_THRESHOLD){return}this._drawerState=this._DRAWER_STATE.FLINGING;var x=event.detail.dx+this._translateOffset;var drawerWidth=this.getWidth();var isPositionLeft=this.position==="left";var isVelocityPositive=velocity>0;var isClosingLeft=!isVelocityPositive&&isPositionLeft;var isClosingRight=isVelocityPositive&&!isPositionLeft;var dx;if(isClosingLeft){dx=-(x+drawerWidth)}else if(isClosingRight){dx=drawerWidth-x}else{dx=-x}if(isVelocityPositive){velocity=Math.max(velocity,this._MIN_TRANSITION_VELOCITY);this.opened=this.position==="left"}else{velocity=Math.min(velocity,-this._MIN_TRANSITION_VELOCITY);this.opened=this.position==="right"}this._setTransitionDuration(this._FLING_INITIAL_SLOPE*dx/velocity+"ms");this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);this._resetDrawerTranslate()},_transitionend:function(event){var target=Polymer.dom(event).rootTarget;if(target===this.$.contentContainer||target===this.$.scrim){if(this._drawerState===this._DRAWER_STATE.FLINGING){this._setTransitionDuration("");this._setTransitionTimingFunction("");this.style.visibility=""}this._resetDrawerState()}},_setTransitionDuration:function(duration){this.$.contentContainer.style.transitionDuration=duration;this.$.scrim.style.transitionDuration=duration},_setTransitionTimingFunction:function(timingFunction){this.$.contentContainer.style.transitionTimingFunction=timingFunction;this.$.scrim.style.transitionTimingFunction=timingFunction},_translateDrawer:function(x){var drawerWidth=this.getWidth();if(this.position==="left"){x=Math.max(-drawerWidth,Math.min(x,0));this.$.scrim.style.opacity=1+x/drawerWidth}else{x=Math.max(0,Math.min(x,drawerWidth));this.$.scrim.style.opacity=1-x/drawerWidth}this.translate3d(x+"px","0","0",this.$.contentContainer)},_resetDrawerTranslate:function(){this.$.scrim.style.opacity="";this.transform("",this.$.contentContainer)},_resetDrawerState:function(){var oldState=this._drawerState;if(this.opened){this._drawerState=this.persistent?this._DRAWER_STATE.OPENED_PERSISTENT:this._DRAWER_STATE.OPENED}else{this._drawerState=this._DRAWER_STATE.CLOSED}if(oldState!==this._drawerState){if(this._drawerState===this._DRAWER_STATE.OPENED){this._setKeyboardFocusTrap();document.addEventListener("keydown",this._boundEscKeydownHandler);document.body.style.overflow="hidden"}else{document.removeEventListener("keydown",this._boundEscKeydownHandler);document.body.style.overflow=""}if(oldState!==this._DRAWER_STATE.INIT){this.fire("app-drawer-transitioned")}}},_setKeyboardFocusTrap:function(){if(this.noFocusTrap){return}var focusableElementsSelector=['a[href]:not([tabindex="-1"])','area[href]:not([tabindex="-1"])','input:not([disabled]):not([tabindex="-1"])','select:not([disabled]):not([tabindex="-1"])','textarea:not([disabled]):not([tabindex="-1"])','button:not([disabled]):not([tabindex="-1"])','iframe:not([tabindex="-1"])','[tabindex]:not([tabindex="-1"])','[contentEditable=true]:not([tabindex="-1"])'].join(",");var focusableElements=Polymer.dom(this).querySelectorAll(focusableElementsSelector);if(focusableElements.length>0){this._firstTabStop=focusableElements[0];this._lastTabStop=focusableElements[focusableElements.length-1]}else{this._firstTabStop=null;this._lastTabStop=null}var tabindex=this.getAttribute("tabindex");if(tabindex&&parseInt(tabindex,10)>-1){this.focus()}else if(this._firstTabStop){this._firstTabStop.focus()}},_tabKeydownHandler:function(event){if(this.noFocusTrap){return}var TAB_KEYCODE=9;if(this._drawerState===this._DRAWER_STATE.OPENED&&event.keyCode===TAB_KEYCODE){if(event.shiftKey){if(this._firstTabStop&&Polymer.dom(event).localTarget===this._firstTabStop){event.preventDefault();this._lastTabStop.focus()}}else{if(this._lastTabStop&&Polymer.dom(event).localTarget===this._lastTabStop){event.preventDefault();this._firstTabStop.focus()}}}},_MIN_FLING_THRESHOLD:.2,_MIN_TRANSITION_VELOCITY:1.2,_FLING_TIMING_FUNCTION:"cubic-bezier(0.667, 1, 0.667, 1)",_FLING_INITIAL_SLOPE:1.5,_DRAWER_STATE:{INIT:0,OPENED:1,OPENED_PERSISTENT:2,CLOSED:3,TRACKING:4,FLINGING:5}});Polymer.IronFormElementBehavior={properties:{name:{type:String},value:{notify:true,type:String},required:{type:Boolean,value:false},_parentForm:{type:Object}},attached:function(){this.fire("iron-form-element-register")},detached:function(){if(this._parentForm){this._parentForm.fire("iron-form-element-unregister",{target:this})}}};Polymer.IronCheckedElementBehaviorImpl={properties:{checked:{type:Boolean,value:false,reflectToAttribute:true,notify:true,observer:"_checkedChanged"},toggles:{type:Boolean,value:true,reflectToAttribute:true},value:{type:String,value:"on",observer:"_valueChanged"}},observers:["_requiredChanged(required)"],created:function(){this._hasIronCheckedElementBehavior=true},_getValidity:function(_value){return this.disabled||!this.required||this.checked},_requiredChanged:function(){if(this.required){this.setAttribute("aria-required","true")}else{this.removeAttribute("aria-required")}},_checkedChanged:function(){this.active=this.checked;this.fire("iron-change")},_valueChanged:function(){if(this.value===undefined||this.value===null){this.value="on"}}};Polymer.IronCheckedElementBehavior=[Polymer.IronFormElementBehavior,Polymer.IronValidatableBehavior,Polymer.IronCheckedElementBehaviorImpl];Polymer.PaperCheckedElementBehaviorImpl={_checkedChanged:function(){Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this);if(this.hasRipple()){if(this.checked){this._ripple.setAttribute("checked","")}else{this._ripple.removeAttribute("checked")}}},_buttonStateChanged:function(){Polymer.PaperRippleBehavior._buttonStateChanged.call(this);if(this.disabled){return}if(this.isAttached){this.checked=this.active}}};Polymer.PaperCheckedElementBehavior=[Polymer.PaperInkyFocusBehavior,Polymer.IronCheckedElementBehavior,Polymer.PaperCheckedElementBehaviorImpl];Polymer({is:"paper-checkbox",behaviors:[Polymer.PaperCheckedElementBehavior],hostAttributes:{role:"checkbox","aria-checked":false,tabindex:0},properties:{ariaActiveAttribute:{type:String,value:"aria-checked"}},attached:function(){var inkSize=this.getComputedStyleValue("--calculated-paper-checkbox-ink-size");if(inkSize==="-1px"){var checkboxSize=parseFloat(this.getComputedStyleValue("--calculated-paper-checkbox-size"));var defaultInkSize=Math.floor(8/3*checkboxSize);if(defaultInkSize%2!==checkboxSize%2){defaultInkSize++}this.customStyle["--paper-checkbox-ink-size"]=defaultInkSize+"px";this.updateStyles()}},_computeCheckboxClass:function(checked,invalid){var className="";if(checked){className+="checked "}if(invalid){className+="invalid"}return className},_computeCheckmarkClass:function(checked){return checked?"":"hidden"},_createRipple:function(){this._rippleContainer=this.$.checkboxContainer;return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this)}});Polymer({is:"paper-tab",behaviors:[Polymer.IronControlState,Polymer.IronButtonState,Polymer.PaperRippleBehavior],properties:{link:{type:Boolean,value:false,reflectToAttribute:true}},hostAttributes:{role:"tab"},listeners:{down:"_updateNoink",tap:"_onTap"},attached:function(){this._updateNoink()},get _parentNoink(){var parent=Polymer.dom(this).parentNode;return!!parent&&!!parent.noink},_updateNoink:function(){this.noink=!!this.noink||!!this._parentNoink},_onTap:function(event){if(this.link){var anchor=this.queryEffectiveChildren("a");if(!anchor){return}if(event.target===anchor){return}anchor.click()}}});Polymer.IronMenuBehaviorImpl={properties:{focusedItem:{observer:"_focusedItemChanged",readOnly:true,type:Object},attrForItemTitle:{type:String}},hostAttributes:{role:"menu",tabindex:"0"},observers:["_updateMultiselectable(multi)"],listeners:{focus:"_onFocus",keydown:"_onKeydown","iron-items-changed":"_onIronItemsChanged"},keyBindings:{up:"_onUpKey",down:"_onDownKey",esc:"_onEscKey","shift+tab:keydown":"_onShiftTabDown"},attached:function(){this._resetTabindices()},select:function(value){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}var item=this._valueToItem(value);if(item&&item.hasAttribute("disabled"))return;this._setFocusedItem(item);Polymer.IronMultiSelectableBehaviorImpl.select.apply(this,arguments)},_resetTabindices:function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this.items.forEach(function(item){item.setAttribute("tabindex",item===selectedItem?"0":"-1")},this)},_updateMultiselectable:function(multi){if(multi){this.setAttribute("aria-multiselectable","true")}else{this.removeAttribute("aria-multiselectable")}},_focusWithKeyboardEvent:function(event){for(var i=0,item;item=this.items[i];i++){var attr=this.attrForItemTitle||"textContent";var title=item[attr]||item.getAttribute(attr);if(!item.hasAttribute("disabled")&&title&&title.trim().charAt(0).toLowerCase()===String.fromCharCode(event.keyCode).toLowerCase()){this._setFocusedItem(item);break}}},_focusPrevious:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex-i+length)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_focusNext:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex+i)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_applySelection:function(item,isSelected){if(isSelected){item.setAttribute("aria-selected","true")}else{item.removeAttribute("aria-selected")}Polymer.IronSelectableBehavior._applySelection.apply(this,arguments)},_focusedItemChanged:function(focusedItem,old){old&&old.setAttribute("tabindex","-1");if(focusedItem){focusedItem.setAttribute("tabindex","0");focusedItem.focus()}},_onIronItemsChanged:function(event){if(event.detail.addedNodes.length){this._resetTabindices()}},_onShiftTabDown:function(event){var oldTabIndex=this.getAttribute("tabindex");Polymer.IronMenuBehaviorImpl._shiftTabPressed=true;this._setFocusedItem(null);this.setAttribute("tabindex","-1");this.async(function(){this.setAttribute("tabindex",oldTabIndex);Polymer.IronMenuBehaviorImpl._shiftTabPressed=false},1)},_onFocus:function(event){if(Polymer.IronMenuBehaviorImpl._shiftTabPressed){return}var rootTarget=Polymer.dom(event).rootTarget;if(rootTarget!==this&&typeof rootTarget.tabIndex!=="undefined"&&!this.isLightDescendant(rootTarget)){return}this._defaultFocusAsync=this.async(function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this._setFocusedItem(null);if(selectedItem){this._setFocusedItem(selectedItem)}else if(this.items[0]){this._focusNext()}})},_onUpKey:function(event){this._focusPrevious();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this._focusNext();event.detail.keyboardEvent.preventDefault()},_onEscKey:function(event){this.focusedItem.blur()},_onKeydown:function(event){if(!this.keyboardEventMatchesKeys(event,"up down esc")){this._focusWithKeyboardEvent(event)}event.stopPropagation()},_activateHandler:function(event){Polymer.IronSelectableBehavior._activateHandler.call(this,event);event.stopPropagation()}};Polymer.IronMenuBehaviorImpl._shiftTabPressed=false;Polymer.IronMenuBehavior=[Polymer.IronMultiSelectableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronMenuBehaviorImpl];Polymer.IronMenubarBehaviorImpl={hostAttributes:{role:"menubar"},keyBindings:{left:"_onLeftKey",right:"_onRightKey"},_onUpKey:function(event){this.focusedItem.click();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this.focusedItem.click();event.detail.keyboardEvent.preventDefault()},get _isRTL(){return window.getComputedStyle(this)["direction"]==="rtl"},_onLeftKey:function(event){if(this._isRTL){this._focusNext()}else{this._focusPrevious()}event.detail.keyboardEvent.preventDefault()},_onRightKey:function(event){if(this._isRTL){this._focusPrevious()}else{this._focusNext()}event.detail.keyboardEvent.preventDefault()},_onKeydown:function(event){if(this.keyboardEventMatchesKeys(event,"up down left right esc")){return}this._focusWithKeyboardEvent(event)}};Polymer.IronMenubarBehavior=[Polymer.IronMenuBehavior,Polymer.IronMenubarBehaviorImpl];Polymer({is:"paper-tabs",behaviors:[Polymer.IronResizableBehavior,Polymer.IronMenubarBehavior],properties:{noink:{type:Boolean,value:false,observer:"_noinkChanged"},noBar:{type:Boolean,value:false},noSlide:{type:Boolean,value:false},scrollable:{type:Boolean,value:false},fitContainer:{type:Boolean,value:false},disableDrag:{type:Boolean,value:false},hideScrollButtons:{type:Boolean,value:false},alignBottom:{type:Boolean,value:false},selectable:{type:String,value:"paper-tab"},autoselect:{type:Boolean,value:false},autoselectDelay:{type:Number,value:0},_step:{type:Number,value:10},_holdDelay:{type:Number,value:1},_leftHidden:{type:Boolean,value:false},_rightHidden:{type:Boolean,value:false},_previousTab:{type:Object}},hostAttributes:{role:"tablist"},listeners:{"iron-resize":"_onTabSizingChanged","iron-items-changed":"_onTabSizingChanged","iron-select":"_onIronSelect","iron-deselect":"_onIronDeselect"},keyBindings:{"left:keyup right:keyup":"_onArrowKeyup"},created:function(){this._holdJob=null;this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined;this._bindDelayedActivationHandler=this._delayedActivationHandler.bind(this);this.addEventListener("blur",this._onBlurCapture.bind(this),true)},ready:function(){this.setScrollDirection("y",this.$.tabsContainer)},detached:function(){this._cancelPendingActivation()},_noinkChanged:function(noink){var childTabs=Polymer.dom(this).querySelectorAll("paper-tab");childTabs.forEach(noink?this._setNoinkAttribute:this._removeNoinkAttribute)},_setNoinkAttribute:function(element){element.setAttribute("noink","")},_removeNoinkAttribute:function(element){element.removeAttribute("noink")},_computeScrollButtonClass:function(hideThisButton,scrollable,hideScrollButtons){if(!scrollable||hideScrollButtons){return"hidden"}if(hideThisButton){return"not-visible"}return""},_computeTabsContentClass:function(scrollable,fitContainer){return scrollable?"scrollable"+(fitContainer?" fit-container":""):" fit-container"},_computeSelectionBarClass:function(noBar,alignBottom){if(noBar){return"hidden"}else if(alignBottom){return"align-bottom"}return""},_onTabSizingChanged:function(){this.debounce("_onTabSizingChanged",function(){this._scroll();this._tabChanged(this.selectedItem)},10)},_onIronSelect:function(event){this._tabChanged(event.detail.item,this._previousTab);this._previousTab=event.detail.item;this.cancelDebouncer("tab-changed")},_onIronDeselect:function(event){this.debounce("tab-changed",function(){this._tabChanged(null,this._previousTab);this._previousTab=null},1)},_activateHandler:function(){this._cancelPendingActivation();Polymer.IronMenuBehaviorImpl._activateHandler.apply(this,arguments)},_scheduleActivation:function(item,delay){this._pendingActivationItem=item;this._pendingActivationTimeout=this.async(this._bindDelayedActivationHandler,delay)},_delayedActivationHandler:function(){var item=this._pendingActivationItem;this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined;item.fire(this.activateEvent,null,{bubbles:true,cancelable:true})},_cancelPendingActivation:function(){if(this._pendingActivationTimeout!==undefined){this.cancelAsync(this._pendingActivationTimeout);this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined}},_onArrowKeyup:function(event){if(this.autoselect){this._scheduleActivation(this.focusedItem,this.autoselectDelay)}},_onBlurCapture:function(event){if(event.target===this._pendingActivationItem){this._cancelPendingActivation()}},get _tabContainerScrollSize(){return Math.max(0,this.$.tabsContainer.scrollWidth-this.$.tabsContainer.offsetWidth)},_scroll:function(e,detail){if(!this.scrollable){return}var ddx=detail&&-detail.ddx||0;this._affectScroll(ddx)},_down:function(e){this.async(function(){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}},1)},_affectScroll:function(dx){this.$.tabsContainer.scrollLeft+=dx;var scrollLeft=this.$.tabsContainer.scrollLeft;this._leftHidden=scrollLeft===0;this._rightHidden=scrollLeft===this._tabContainerScrollSize},_onLeftScrollButtonDown:function(){this._scrollToLeft();this._holdJob=setInterval(this._scrollToLeft.bind(this),this._holdDelay)},_onRightScrollButtonDown:function(){this._scrollToRight();this._holdJob=setInterval(this._scrollToRight.bind(this),this._holdDelay)},_onScrollButtonUp:function(){clearInterval(this._holdJob);this._holdJob=null},_scrollToLeft:function(){this._affectScroll(-this._step)},_scrollToRight:function(){this._affectScroll(this._step)},_tabChanged:function(tab,old){if(!tab){this.$.selectionBar.classList.remove("expand");this.$.selectionBar.classList.remove("contract");this._positionBar(0,0);return}var r=this.$.tabsContent.getBoundingClientRect();var w=r.width;var tabRect=tab.getBoundingClientRect();var tabOffsetLeft=tabRect.left-r.left;this._pos={width:this._calcPercent(tabRect.width,w),left:this._calcPercent(tabOffsetLeft,w)};if(this.noSlide||old==null){this.$.selectionBar.classList.remove("expand");this.$.selectionBar.classList.remove("contract");this._positionBar(this._pos.width,this._pos.left);return}var oldRect=old.getBoundingClientRect();var oldIndex=this.items.indexOf(old);var index=this.items.indexOf(tab);var m=5;this.$.selectionBar.classList.add("expand");var moveRight=oldIndex<index;var isRTL=this._isRTL;if(isRTL){moveRight=!moveRight}if(moveRight){this._positionBar(this._calcPercent(tabRect.left+tabRect.width-oldRect.left,w)-m,this._left)}else{this._positionBar(this._calcPercent(oldRect.left+oldRect.width-tabRect.left,w)-m,this._calcPercent(tabOffsetLeft,w)+m)}if(this.scrollable){this._scrollToSelectedIfNeeded(tabRect.width,tabOffsetLeft)}},_scrollToSelectedIfNeeded:function(tabWidth,tabOffsetLeft){var l=tabOffsetLeft-this.$.tabsContainer.scrollLeft;if(l<0){this.$.tabsContainer.scrollLeft+=l}else{l+=tabWidth-this.$.tabsContainer.offsetWidth;if(l>0){this.$.tabsContainer.scrollLeft+=l}}},_calcPercent:function(w,w0){return 100*w/w0},_positionBar:function(width,left){width=width||0;left=left||0;this._width=width;this._left=left;this.transform("translateX("+left+"%) scaleX("+width/100+")",this.$.selectionBar)},_onBarTransitionEnd:function(e){var cl=this.$.selectionBar.classList;if(cl.contains("expand")){cl.remove("expand");cl.add("contract");this._positionBar(this._pos.width,this._pos.left)}else if(cl.contains("contract")){cl.remove("contract")}}});
\ No newline at end of file
diff --git a/chrome/browser/resources/md_history/lazy_load.vulcanized.html b/chrome/browser/resources/md_history/lazy_load.vulcanized.html
index b36ec21..838b605 100644
--- a/chrome/browser/resources/md_history/lazy_load.vulcanized.html
+++ b/chrome/browser/resources/md_history/lazy_load.vulcanized.html
@@ -898,6 +898,12 @@
   cursor: var(--cr-actionable_-_cursor);
 }
 
+.scroll-container {
+  display: flex;
+        flex-direction: column;
+        min-height: 1px;
+}
+
 [selectable]:focus, [selectable] > :focus {
   background-color: var(--cr-selectable-focus_-_background-color); outline: var(--cr-selectable-focus_-_outline);
 }
diff --git a/chrome/browser/resources/settings/compiled_resources2.gyp b/chrome/browser/resources/settings/compiled_resources2.gyp
index 3626edf..09caa83 100644
--- a/chrome/browser/resources/settings/compiled_resources2.gyp
+++ b/chrome/browser/resources/settings/compiled_resources2.gyp
@@ -72,15 +72,5 @@
       ],
       'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
     },
-    {
-      'target_name': 'settings',
-      'dependencies': [
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert',
-        '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr',
-        'direction_delegate',
-        'route',
-      ],
-      'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'],
-    },
   ],
 }
diff --git a/chrome/browser/resources/settings/settings.html b/chrome/browser/resources/settings/settings.html
index 86370a0..6efcfe3 100644
--- a/chrome/browser/resources/settings/settings.html
+++ b/chrome/browser/resources/settings/settings.html
@@ -4,30 +4,11 @@
   <meta charset="utf-8">
   <title>$i18n{settings}</title>
   <link rel="import" href="chrome://resources/html/polymer.html">
-  <link rel="import" href="/i18n_setup.html">
-  <link rel="import" href="/direction_delegate.html">
   <link rel="import" href="/settings_ui/settings_ui.html">
-  <link rel="import" href="/prefs/prefs.html">
-  <link rel="import" href="/route.html">
-  <link rel="import" href="/settings_vars_css.html">
   <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
 </head>
 <body>
-
-  <dom-module id="cr-settings">
-    <template>
-      <style>
-        :host {
-          color: var(--paper-grey-800);
-        }
-      </style>
-      <settings-prefs id="prefs" prefs="{{prefs_}}"></settings-prefs>
-      <settings-ui id="ui" prefs="{{prefs_}}"></settings-ui>
-    </template>
-    <script src="/settings.js"></script>
-  </dom-module>
-
-  <cr-settings></cr-settings>
+  <settings-ui></settings-ui>
   <link rel="import" href="chrome://resources/html/i18n_template.html">
 </body>
 </html>
diff --git a/chrome/browser/resources/settings/settings.js b/chrome/browser/resources/settings/settings.js
deleted file mode 100644
index bb59abb..0000000
--- a/chrome/browser/resources/settings/settings.js
+++ /dev/null
@@ -1,31 +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.
-
-cr.exportPath('settings');
-assert(!settings.defaultResourceLoaded,
-       'settings.js run twice. You probably have an invalid import.');
-/** Global defined when the main Settings script runs. */
-settings.defaultResourceLoaded = true;
-
-/**
- * @fileoverview
- * 'cr-settings' is the main MD-Settings element, combining the UI and models.
- *
- * Example:
- *
- *    <cr-settings></cr-settings>
- */
-Polymer({
-  is: 'cr-settings',
-
-  /** @override */
-  created: function() {
-    settings.initializeRouteFromUrl();
-  },
-
-  /** @override */
-  ready: function() {
-    this.$.ui.directionDelegate = new settings.DirectionDelegateImpl;
-  },
-});
diff --git a/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chrome/browser/resources/settings/settings_page/settings_subpage.html
index d55220b..0a4c36f 100644
--- a/chrome/browser/resources/settings/settings_page/settings_subpage.html
+++ b/chrome/browser/resources/settings/settings_page/settings_subpage.html
@@ -22,10 +22,11 @@
       }
 
       paper-icon-button {
+        /* Centers the ripple on the icon with appropriate margin on right. */
+        -webkit-margin-end: 8px;
+        -webkit-margin-start: -8px;
         /* The inner icon is 20px in size. paper-icon-button has 8px padding. */
         height: 36px;
-        /* Centers the ripple on the icon with appropriate margin on right. */
-        margin: 0 8px 0 -8px;
         width: 36px;
       }
 
diff --git a/chrome/browser/resources/settings/settings_resources.grd b/chrome/browser/resources/settings/settings_resources.grd
index 0371670..cfd1d04 100644
--- a/chrome/browser/resources/settings/settings_resources.grd
+++ b/chrome/browser/resources/settings/settings_resources.grd
@@ -882,9 +882,6 @@
       <structure name="IDR_SETTINGS_SETTINGS_HTML"
                  file="settings.html"
                  type="chrome_html" />
-      <structure name="IDR_SETTINGS_SETTINGS_JS"
-                 file="settings.js"
-                 type="chrome_html" />
       <structure name="IDR_SETTINGS_USB_DEVICES_HTML"
                  file="site_settings/usb_devices.html"
                  type="chrome_html" />
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chrome/browser/resources/settings/settings_ui/settings_ui.html
index 4153d77..baafd39c 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.html
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.html
@@ -10,6 +10,9 @@
 <link rel="import" href="/settings_main/settings_main.html">
 <link rel="import" href="/settings_menu/settings_menu.html">
 <link rel="import" href="/settings_shared_css.html">
+<link rel="import" href="/prefs/prefs.html">
+<link rel="import" href="/route.html">
+<link rel="import" href="/settings_vars_css.html">
 
 <dom-module id="settings-ui">
   <template>
@@ -21,6 +24,7 @@
         };
         -webkit-user-select: none;
         background-color: var(--settings-background-color);
+        color: var(--paper-grey-800);
         display: flex;
         flex-direction: column;
         overflow: hidden;  /* Prevent double scroll bar bugs. */
@@ -78,6 +82,7 @@
         overflow: auto;
       }
     </style>
+    <settings-prefs id="prefs" prefs="{{prefs}}"></settings-prefs>
     <cr-toolbar page-name="$i18n{settings}" clear-label="$i18n{clearSearch}"
         search-prompt="$i18n{searchPrompt}" on-cr-menu-tap="onMenuButtonTap_"
         spinner-active="[[toolbarSpinnerActive_]]" show-menu
diff --git a/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chrome/browser/resources/settings/settings_ui/settings_ui.js
index 910bddc..52307933 100644
--- a/chrome/browser/resources/settings/settings_ui/settings_ui.js
+++ b/chrome/browser/resources/settings/settings_ui/settings_ui.js
@@ -10,6 +10,12 @@
  *
  *    <settings-ui prefs="{{prefs}}"></settings-ui>
  */
+cr.exportPath('settings');
+assert(!settings.defaultResourceLoaded,
+       'settings_ui.js run twice. You probably have an invalid import.');
+/** Global defined when the main Settings script runs. */
+settings.defaultResourceLoaded = true;
+
 Polymer({
   is: 'settings-ui',
 
@@ -23,6 +29,7 @@
     directionDelegate: {
       observer: 'directionDelegateChanged_',
       type: Object,
+      value: new settings.DirectionDelegateImpl(),
     },
 
     /** @private {boolean} */
@@ -38,6 +45,11 @@
     pageVisibility_: Object,
   },
 
+  /** @override */
+  created: function() {
+    settings.initializeRouteFromUrl();
+  },
+
   /**
    * @override
    * @suppress {es5Strict} Object literals cannot contain duplicate keys in ES5
diff --git a/chrome/browser/resources/snippets_internals.html b/chrome/browser/resources/snippets_internals.html
index f8251e9..eab56bb3 100644
--- a/chrome/browser/resources/snippets_internals.html
+++ b/chrome/browser/resources/snippets_internals.html
@@ -137,7 +137,7 @@
               <table>
                 <tr>
                   <td>ID
-                  <td jscontent="suggestionId">
+                  <td jscontent="idWithinCategory">
                 <tr>
                   <td>URL
                   <td><a class="url" jsvalues="href:url" jscontent="url"></a>
diff --git a/chrome/browser/resources/vulcanize.py b/chrome/browser/resources/vulcanize.py
index 66f7fa4..3752c965 100755
--- a/chrome/browser/resources/vulcanize.py
+++ b/chrome/browser/resources/vulcanize.py
@@ -88,7 +88,6 @@
     # TODO(tsergeant): Remove when JS resources are minified by default:
     # crbug.com/619091.
     _run_cmd(['uglifyjs', js_out_path,
-                         '--beautify', 'indent-level=2,quote_style=3',
                          '--comments', '/Copyright|license|LICENSE|\<\/?if/',
                          '--output', js_out_path])
   finally:
diff --git a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
index b8c0766e..734e4d5 100644
--- a/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
+++ b/chrome/browser/sync/sessions/sessions_sync_manager_unittest.cc
@@ -180,6 +180,10 @@
     return sync_data_to_return_;
   }
 
+  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override {}
+  void RemoveLocalChangeObserver(
+      syncer::LocalChangeObserver* observer) override {}
+
   void FailProcessSyncChangesWith(const syncer::SyncError& error) {
     error_ = error;
   }
diff --git a/chrome/browser/ui/login/login_handler_browsertest.cc b/chrome/browser/ui/login/login_handler_browsertest.cc
index 532374d..d3e1ca5 100644
--- a/chrome/browser/ui/login/login_handler_browsertest.cc
+++ b/chrome/browser/ui/login/login_handler_browsertest.cc
@@ -361,8 +361,9 @@
   observer.Register(content::Source<NavigationController>(controller));
 
   // One LOAD_STOP event for LoginInterstitial, second for kAuthURL and third
-  // for kNoAuthURL.
-  const int kLoadStopEvents = 3;
+  // for kNoAuthURL, unless PlzNavigate is active, in which case the
+  // interrupted ongoing navigation does not receive LOAD_STOP.
+  const int kLoadStopEvents = content::IsBrowserSideNavigationEnabled() ? 2 : 3;
   WindowedLoadStopObserver load_stop_waiter(controller, kLoadStopEvents);
   WindowedAuthNeededObserver auth_needed_waiter(controller);
   browser()->OpenURL(OpenURLParams(kAuthURL, Referrer(),
diff --git a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
index 6d2bf4c..817448ce 100644
--- a/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
+++ b/chrome/browser/ui/webui/chromeos/keyboard_overlay_ui.cc
@@ -259,6 +259,8 @@
   { "keyboardOverlayDisableCapsLock", IDS_KEYBOARD_OVERLAY_DISABLE_CAPS_LOCK },
   { "keyboardOverlayToggleChromevoxSpokenFeedback",
     IDS_KEYBOARD_OVERLAY_TOGGLE_CHROMEVOX_SPOKEN_FEEDBACK },
+  { "keyboardOverlayToggleHighContrastMode",
+    IDS_KEYBOARD_OVERLAY_TOGGLE_HIGH_CONTRAST_MODE},
   { "keyboardOverlayToggleProjectionTouchHud",
     IDS_KEYBOARD_OVERLAY_TOGGLE_PROJECTION_TOUCH_HUD },
   { "keyboardOverlayUndo", IDS_KEYBOARD_OVERLAY_UNDO },
diff --git a/chrome/browser/ui/webui/md_history_ui.cc b/chrome/browser/ui/webui/md_history_ui.cc
index bd1e358b0..56bbf9b 100644
--- a/chrome/browser/ui/webui/md_history_ui.cc
+++ b/chrome/browser/ui/webui/md_history_ui.cc
@@ -35,6 +35,8 @@
 
 namespace {
 
+constexpr char kShowMenuPromoKey[] = "showMenuPromo";
+
 content::WebUIDataSource* CreateMdHistoryUIHTMLSource(Profile* profile,
                                                       bool use_test_title) {
   content::WebUIDataSource* source =
@@ -117,7 +119,7 @@
       prefs->GetBoolean(prefs::kAllowDeletingBrowserHistory);
   source->AddBoolean("allowDeletingHistory", allow_deleting_history);
 
-  source->AddBoolean("showMenuPromo",
+  source->AddBoolean(kShowMenuPromoKey,
       !prefs->GetBoolean(prefs::kMdHistoryMenuPromoShown));
 
   bool group_by_domain = base::CommandLine::ForCurrentProcess()->HasSwitch(
@@ -267,5 +269,5 @@
 void MdHistoryUI::HandleMenuPromoShown(const base::ListValue* args) {
   Profile::FromWebUI(web_ui())->GetPrefs()->SetBoolean(
       prefs::kMdHistoryMenuPromoShown, true);
-  data_source_->AddBoolean("showMenuPromo", false);
+  data_source_->AddBoolean(kShowMenuPromoKey, false);
 }
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.cc b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
index 761bad9..55030f8 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.cc
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.cc
@@ -41,7 +41,7 @@
     const ContentSuggestion& suggestion,
     int index) {
   auto entry = base::MakeUnique<base::DictionaryValue>();
-  entry->SetString("suggestionId", suggestion.id());
+  entry->SetString("idWithinCategory", suggestion.id().id_within_category());
   entry->SetString("url", suggestion.url().spec());
   entry->SetString("ampUrl", suggestion.amp_url().spec());
   entry->SetString("title", suggestion.title());
@@ -144,8 +144,7 @@
 }
 
 void SnippetsInternalsMessageHandler::OnSuggestionInvalidated(
-    ntp_snippets::Category category,
-    const std::string& suggestion_id) {
+    const ntp_snippets::ContentSuggestion::ID& suggestion_id) {
   if (!dom_loaded_)
     return;
   SendContentSuggestions();
diff --git a/chrome/browser/ui/webui/snippets_internals_message_handler.h b/chrome/browser/ui/webui/snippets_internals_message_handler.h
index 6b423bc..4ca4ead 100644
--- a/chrome/browser/ui/webui/snippets_internals_message_handler.h
+++ b/chrome/browser/ui/webui/snippets_internals_message_handler.h
@@ -41,8 +41,8 @@
   void OnCategoryStatusChanged(
       ntp_snippets::Category category,
       ntp_snippets::CategoryStatus new_status) override;
-  void OnSuggestionInvalidated(ntp_snippets::Category category,
-                               const std::string& suggestion_id) override;
+  void OnSuggestionInvalidated(
+      const ntp_snippets::ContentSuggestion::ID& suggestion_id) override;
   void ContentSuggestionsServiceShutdown() override;
 
   void HandleRefreshContent(const base::ListValue* args);
diff --git a/chrome/gpu/arc_gpu_video_decode_accelerator.cc b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
index 27e0a9e..dc194db3 100644
--- a/chrome/gpu/arc_gpu_video_decode_accelerator.cc
+++ b/chrome/gpu/arc_gpu_video_decode_accelerator.cc
@@ -299,8 +299,8 @@
         handle.native_pixmap_handle.fds.emplace_back(
             base::FileDescriptor(info.handle.release(), true));
         for (const auto& plane : info.planes) {
-          handle.native_pixmap_handle.planes.emplace_back(
-              plane.stride, plane.offset, 0);
+          handle.native_pixmap_handle.planes.emplace_back(plane.stride,
+                                                          plane.offset, 0, 0);
         }
 #endif
         vda_->ImportBufferForPicture(index, handle);
diff --git a/chrome/test/data/downloads/tiny_binary.bin b/chrome/test/data/downloads/tiny_binary.bin
new file mode 100644
index 0000000..593f470
--- /dev/null
+++ b/chrome/test/data/downloads/tiny_binary.bin
Binary files differ
diff --git a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
index d6214712..b3c1f4bb 100644
--- a/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
+++ b/chrome/test/data/webui/settings/easy_unlock_browsertest_chromeos.js
@@ -134,7 +134,7 @@
 
       // Before clearing the body, save a copy of the real prefs so we can
       // cleanly re-create the People page element.
-      prefs = document.querySelector('cr-settings').$$('settings-prefs').prefs;
+      prefs = document.querySelector('settings-ui').$$('settings-prefs').prefs;
     });
 
     setup(function() {
diff --git a/chrome/test/data/webui/settings/on_startup_browsertest.js b/chrome/test/data/webui/settings/on_startup_browsertest.js
index f6c0db2..5c9e7aa3 100644
--- a/chrome/test/data/webui/settings/on_startup_browsertest.js
+++ b/chrome/test/data/webui/settings/on_startup_browsertest.js
@@ -62,7 +62,7 @@
       self.getPage('basic').set('pageVisibility.onStartup', true);
       Polymer.dom.flush();
 
-      settingsPrefs = document.querySelector('cr-settings').$$(
+      settingsPrefs = document.querySelector('settings-ui').$$(
           'settings-prefs');
       assertTrue(!!settingsPrefs);
       return CrSettingsPrefs.initialized;
diff --git a/chrome/test/data/webui/settings/settings_page_browsertest.js b/chrome/test/data/webui/settings/settings_page_browsertest.js
index a3a2fb1..afd3351 100644
--- a/chrome/test/data/webui/settings/settings_page_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_page_browsertest.js
@@ -55,9 +55,7 @@
    * @return {!PolymerElement} The PolymerElement for the page.
    */
   getPage: function(type) {
-    var settings = document.querySelector('cr-settings');
-    assertTrue(!!settings);
-    var settingsUi = settings.$$('settings-ui');
+    var settingsUi = document.querySelector('settings-ui');
     assertTrue(!!settingsUi);
     var settingsMain = settingsUi.$$('settings-main');
     assertTrue(!!settingsMain);
diff --git a/chrome/test/data/webui/settings/settings_ui_browsertest.js b/chrome/test/data/webui/settings/settings_ui_browsertest.js
index 5e08ca8..bc44014 100644
--- a/chrome/test/data/webui/settings/settings_ui_browsertest.js
+++ b/chrome/test/data/webui/settings/settings_ui_browsertest.js
@@ -31,8 +31,7 @@
     var ui;
 
     suiteSetup(function() {
-      var settings = assert(document.querySelector('cr-settings'));
-      ui = assert(settings.$$('settings-ui'));
+      ui = assert(document.querySelector('settings-ui'));
     });
 
     test('basic', function() {
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc
index 7ced1be..ffe6089 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.cc
+++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -775,7 +775,7 @@
   return network_thread_->task_runner();
 }
 
-void CronetURLRequestContextAdapter::StartNetLogToFile(
+bool CronetURLRequestContextAdapter::StartNetLogToFile(
     JNIEnv* env,
     const JavaParamRef<jobject>& jcaller,
     const JavaParamRef<jstring>& jfile_name,
@@ -783,14 +783,14 @@
   base::AutoLock lock(write_to_file_observer_lock_);
   // Do nothing if already logging to a file.
   if (write_to_file_observer_)
-    return;
+    return true;
   std::string file_name =
       base::android::ConvertJavaStringToUTF8(env, jfile_name);
   base::FilePath file_path(file_name);
   base::ScopedFILE file(base::OpenFile(file_path, "w"));
   if (!file) {
     LOG(ERROR) << "Failed to open NetLog file for writing.";
-    return;
+    return false;
   }
 
   write_to_file_observer_.reset(new net::WriteToFileNetLogObserver());
@@ -801,6 +801,8 @@
   write_to_file_observer_->StartObserving(
       g_net_log.Get().net_log(), std::move(file),
       /*constants=*/nullptr, /*url_request_context=*/nullptr);
+
+  return true;
 }
 
 void CronetURLRequestContextAdapter::StartNetLogToDisk(
diff --git a/components/cronet/android/cronet_url_request_context_adapter.h b/components/cronet/android/cronet_url_request_context_adapter.h
index 901f26c6..647cc06 100644
--- a/components/cronet/android/cronet_url_request_context_adapter.h
+++ b/components/cronet/android/cronet_url_request_context_adapter.h
@@ -79,8 +79,9 @@
 
   net::URLRequestContext* GetURLRequestContext();
 
-  // Starts NetLog logging to file. This can be called on any thread.
-  void StartNetLogToFile(JNIEnv* env,
+  // Starts NetLog logging to file. This can be called on any thread.  Returns
+  // false if it fails to open log file.
+  bool StartNetLogToFile(JNIEnv* env,
                          const base::android::JavaParamRef<jobject>& jcaller,
                          const base::android::JavaParamRef<jstring>& jfile_name,
                          jboolean jlog_all);
diff --git a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
index 2c2df1a7..f9656fa 100644
--- a/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
+++ b/components/cronet/android/java/src/org/chromium/net/impl/CronetUrlRequestContext.java
@@ -260,7 +260,9 @@
     public void startNetLogToFile(String fileName, boolean logAll) {
         synchronized (mLock) {
             checkHaveAdapter();
-            nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName, logAll);
+            if (!nativeStartNetLogToFile(mUrlRequestContextAdapter, fileName, logAll)) {
+                throw new RuntimeException("Unable to start NetLog");
+            }
             mIsLogging = true;
         }
     }
@@ -612,7 +614,7 @@
     private native void nativeDestroy(long nativePtr);
 
     @NativeClassQualifiedName("CronetURLRequestContextAdapter")
-    private native void nativeStartNetLogToFile(long nativePtr, String fileName, boolean logAll);
+    private native boolean nativeStartNetLogToFile(long nativePtr, String fileName, boolean logAll);
 
     @NativeClassQualifiedName("CronetURLRequestContextAdapter")
     private native void nativeStartNetLogToDisk(
diff --git a/components/domain_reliability/quic_error_mapping.cc b/components/domain_reliability/quic_error_mapping.cc
index 853f49f..3b247e8 100644
--- a/components/domain_reliability/quic_error_mapping.cc
+++ b/components/domain_reliability/quic_error_mapping.cc
@@ -242,6 +242,10 @@
   // has too many gaps.
   { net::QUIC_TOO_MANY_FRAME_GAPS,
     "quic.too_many_frame_gaps" },
+  // Sequencer buffer get into weird state where continuing read/write
+  // will lead to crash.
+  { net::QUIC_STREAM_SEQUENCER_INVALID_STATE,
+    "quic.stream_sequencer_invalid_state" },
 
   // No error. Used as bound while iterating.
   { net::QUIC_LAST_ERROR, "quic.last_error"}
diff --git a/components/exo/wayland/server.cc b/components/exo/wayland/server.cc
index de1df93..53b20f9 100644
--- a/components/exo/wayland/server.cc
+++ b/components/exo/wayland/server.cc
@@ -536,9 +536,9 @@
   }
 
   std::vector<gfx::NativePixmapPlane> planes;
-  planes.emplace_back(stride0, offset0, 0);
-  planes.emplace_back(stride1, offset1, 0);
-  planes.emplace_back(stride2, offset2, 0);
+  planes.emplace_back(stride0, offset0, 0, 0);
+  planes.emplace_back(stride1, offset1, 0, 0);
+  planes.emplace_back(stride2, offset2, 0, 0);
   std::vector<base::ScopedFD> fds;
 
   size_t num_planes =
@@ -694,7 +694,7 @@
       return;
     }
     LinuxBufferParams::Plane& plane = plane_it->second;
-    planes.emplace_back(plane.stride, plane.offset, 0);
+    planes.emplace_back(plane.stride, plane.offset, 0, 0);
     if (plane.fd.is_valid())
       fds.push_back(std::move(plane.fd));
   }
diff --git a/components/gcm_driver/gcm_stats_recorder_impl.cc b/components/gcm_driver/gcm_stats_recorder_impl.cc
index d632bd3..719f2538 100644
--- a/components/gcm_driver/gcm_stats_recorder_impl.cc
+++ b/components/gcm_driver/gcm_stats_recorder_impl.cc
@@ -400,6 +400,8 @@
     int message_byte_size,
     bool to_registered_app,
     ReceivedMessageType message_type) {
+  UMA_HISTOGRAM_BOOLEAN("GCM.DataMessageReceivedHasRegisteredApp",
+                        to_registered_app);
   if (to_registered_app)
     UMA_HISTOGRAM_COUNTS("GCM.DataMessageReceived", 1);
 
diff --git a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
index 27db5336..ca953b5 100644
--- a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
+++ b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.cc
@@ -154,14 +154,14 @@
 }
 
 void BookmarkSuggestionsProvider::DismissSuggestion(
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   DCHECK(bookmark_model_->loaded());
-  GURL url(GetWithinCategoryIDFromUniqueID(suggestion_id));
+  GURL url(suggestion_id.id_within_category());
   MarkBookmarksDismissed(bookmark_model_, url);
 }
 
 void BookmarkSuggestionsProvider::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, gfx::Image()));
@@ -260,9 +260,8 @@
 
 ContentSuggestion BookmarkSuggestionsProvider::ConvertBookmark(
     const BookmarkNode* bookmark) {
-  ContentSuggestion suggestion(
-      MakeUniqueID(provided_category_, bookmark->url().spec()),
-      bookmark->url());
+  ContentSuggestion suggestion(provided_category_, bookmark->url().spec(),
+                               bookmark->url());
 
   suggestion.set_title(bookmark->GetTitle());
   suggestion.set_snippet_text(base::string16());
diff --git a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
index 79b8718..68ede9d 100644
--- a/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
+++ b/components/ntp_snippets/bookmarks/bookmark_suggestions_provider.h
@@ -39,8 +39,8 @@
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
diff --git a/components/ntp_snippets/category_factory.cc b/components/ntp_snippets/category_factory.cc
index 9962f077..4da984e 100644
--- a/components/ntp_snippets/category_factory.cc
+++ b/components/ntp_snippets/category_factory.cc
@@ -12,13 +12,6 @@
 
 namespace ntp_snippets {
 
-namespace {
-
-const char kCombinedIDFormat[] = "%d|%s";
-const char kSeparator = '|';
-
-}  // namespace
-
 CategoryFactory::CategoryFactory() {
   // Add all local categories in a fixed order.
   AddKnownCategory(KnownCategories::DOWNLOADS);
@@ -66,32 +59,6 @@
                                      ordered_categories_.end(), right);
 }
 
-std::string CategoryFactory::MakeUniqueID(
-    Category category,
-    const std::string& within_category_id) const {
-  return base::StringPrintf(kCombinedIDFormat, category.id(),
-                            within_category_id.c_str());
-}
-
-Category CategoryFactory::GetCategoryFromUniqueID(
-    const std::string& unique_id) {
-  size_t colon_index = unique_id.find(kSeparator);
-  DCHECK_NE(std::string::npos, colon_index) << "Not a valid unique_id: "
-                                            << unique_id;
-  int category = -1;
-  bool ret = base::StringToInt(unique_id.substr(0, colon_index), &category);
-  DCHECK(ret) << "Non-numeric category part in unique_id: " << unique_id;
-  return FromIDValue(category);
-}
-
-std::string CategoryFactory::GetWithinCategoryIDFromUniqueID(
-    const std::string& unique_id) const {
-  size_t colon_index = unique_id.find(kSeparator);
-  DCHECK_NE(std::string::npos, colon_index) << "Not a valid unique_id: "
-                                            << unique_id;
-  return unique_id.substr(colon_index + 1);
-}
-
 ////////////////////////////////////////////////////////////////////////////////
 // Private methods
 
diff --git a/components/ntp_snippets/category_factory.h b/components/ntp_snippets/category_factory.h
index db134d2..c3941ea 100644
--- a/components/ntp_snippets/category_factory.h
+++ b/components/ntp_snippets/category_factory.h
@@ -44,23 +44,6 @@
   // |FromRemoteCategory|.
   bool CompareCategories(const Category& left, const Category& right) const;
 
-  // TODO(treib): Remove the following 3 functions from here once we move to a
-  // more structured identification than the unique_id string and thus once we
-  // eliminate these functions. See crbug.com/649048.
-
-  // Creates a unique ID. The given |within_category_id| must be unique among
-  // all suggestion IDs from this provider for the given |category|. This method
-  // combines it with the |category| to form an ID that is unique
-  // application-wide, because this provider is the only one that provides
-  // suggestions for that category.
-  std::string MakeUniqueID(Category category,
-                           const std::string& within_category_id) const;
-
-  // Reverse functions for MakeUniqueID()
-  Category GetCategoryFromUniqueID(const std::string& unique_id);
-  std::string GetWithinCategoryIDFromUniqueID(
-      const std::string& unique_id) const;
-
  private:
   bool CategoryExists(int id);
   void AddKnownCategory(KnownCategories known_category);
diff --git a/components/ntp_snippets/content_suggestion.cc b/components/ntp_snippets/content_suggestion.cc
index 0617f6e..44524cb 100644
--- a/components/ntp_snippets/content_suggestion.cc
+++ b/components/ntp_snippets/content_suggestion.cc
@@ -6,13 +6,32 @@
 
 namespace ntp_snippets {
 
-ContentSuggestion::ContentSuggestion(const std::string& id, const GURL& url)
+bool ContentSuggestion::ID::operator==(const ID& rhs) const {
+  return category_ == rhs.category_ &&
+         id_within_category_ == rhs.id_within_category_;
+}
+
+bool ContentSuggestion::ID::operator!=(const ID& rhs) const {
+  return !(*this == rhs);
+}
+
+ContentSuggestion::ContentSuggestion(ID id, const GURL& url)
     : id_(id), url_(url), score_(0) {}
 
+ContentSuggestion::ContentSuggestion(Category category,
+                                     const std::string& id_within_category,
+                                     const GURL& url)
+    : id_(category, id_within_category), url_(url), score_(0) {}
+
 ContentSuggestion::ContentSuggestion(ContentSuggestion&&) = default;
 
 ContentSuggestion& ContentSuggestion::operator=(ContentSuggestion&&) = default;
 
 ContentSuggestion::~ContentSuggestion() = default;
 
+std::ostream& operator<<(std::ostream& os, ContentSuggestion::ID id) {
+  os << id.category() << "|" << id.id_within_category();
+  return os;
+}
+
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/content_suggestion.h b/components/ntp_snippets/content_suggestion.h
index f289706..bf8442c 100644
--- a/components/ntp_snippets/content_suggestion.h
+++ b/components/ntp_snippets/content_suggestion.h
@@ -5,13 +5,12 @@
 #ifndef COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
 #define COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
 
-#include <memory>
 #include <string>
-#include <vector>
 
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/time/time.h"
+#include "components/ntp_snippets/category.h"
 #include "url/gurl.h"
 
 namespace ntp_snippets {
@@ -20,9 +19,32 @@
 // offline page, for example.
 class ContentSuggestion {
  public:
+  class ID {
+   public:
+    ID(Category category, const std::string& id_within_category)
+        : category_(category), id_within_category_(id_within_category) {}
+
+    Category category() const { return category_; }
+
+    const std::string& id_within_category() const {
+      return id_within_category_;
+    }
+
+    bool operator==(const ID& rhs) const;
+    bool operator!=(const ID& rhs) const;
+
+   private:
+    Category category_;
+    std::string id_within_category_;
+
+    // Allow copy and assignment.
+  };
+
   // Creates a new ContentSuggestion. The caller must ensure that the |id|
   // passed in here is unique application-wide.
-  ContentSuggestion(const std::string& id,
+  ContentSuggestion(ID id, const GURL& url);
+  ContentSuggestion(Category category,
+                    const std::string& id_within_category,
                     const GURL& url);
   ContentSuggestion(ContentSuggestion&&);
   ContentSuggestion& operator=(ContentSuggestion&&);
@@ -30,7 +52,7 @@
   ~ContentSuggestion();
 
   // An ID for identifying the suggestion. The ID is unique application-wide.
-  const std::string& id() const { return id_; }
+  const ID& id() const { return id_; }
 
   // The normal content URL where the content referenced by the suggestion can
   // be accessed.
@@ -72,7 +94,7 @@
   void set_score(float score) { score_ = score; }
 
  private:
-  std::string id_;
+  ID id_;
   GURL url_;
   GURL amp_url_;
   base::string16 title_;
@@ -84,6 +106,8 @@
   DISALLOW_COPY_AND_ASSIGN(ContentSuggestion);
 };
 
+std::ostream& operator<<(std::ostream& os, ContentSuggestion::ID id);
+
 }  // namespace ntp_snippets
 
 #endif  // COMPONENTS_NTP_SNIPPETS_CONTENT_SUGGESTION_H_
diff --git a/components/ntp_snippets/content_suggestions_provider.cc b/components/ntp_snippets/content_suggestions_provider.cc
index de3c759..3489657 100644
--- a/components/ntp_snippets/content_suggestions_provider.cc
+++ b/components/ntp_snippets/content_suggestions_provider.cc
@@ -15,20 +15,4 @@
 
 ContentSuggestionsProvider::~ContentSuggestionsProvider() = default;
 
-std::string ContentSuggestionsProvider::MakeUniqueID(
-    Category category,
-    const std::string& within_category_id) const {
-  return category_factory()->MakeUniqueID(category, within_category_id);
-}
-
-Category ContentSuggestionsProvider::GetCategoryFromUniqueID(
-    const std::string& unique_id) const {
-  return category_factory()->GetCategoryFromUniqueID(unique_id);
-}
-
-std::string ContentSuggestionsProvider::GetWithinCategoryIDFromUniqueID(
-    const std::string& unique_id) const {
-  return category_factory()->GetWithinCategoryIDFromUniqueID(unique_id);
-}
-
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/content_suggestions_provider.h b/components/ntp_snippets/content_suggestions_provider.h
index bc568f5..b3119669 100644
--- a/components/ntp_snippets/content_suggestions_provider.h
+++ b/components/ntp_snippets/content_suggestions_provider.h
@@ -70,13 +70,13 @@
     // |FetchSuggestionImage| or |DismissSuggestion| anymore, and should
     // immediately be cleared from the UI and caches. This happens, for example,
     // when the content that the suggestion refers to is gone.
-    // Note that this event may be fired even if the corresponding |category| is
+    // Note that this event may be fired even if the corresponding category is
     // not currently AVAILABLE, because open UIs may still be showing the
     // suggestion that is to be removed. This event may also be fired for
     // |suggestion_id|s that never existed and should be ignored in that case.
-    virtual void OnSuggestionInvalidated(ContentSuggestionsProvider* provider,
-                                         Category category,
-                                         const std::string& suggestion_id) = 0;
+    virtual void OnSuggestionInvalidated(
+        ContentSuggestionsProvider* provider,
+        const ContentSuggestion::ID& suggestion_id) = 0;
   };
 
   virtual ~ContentSuggestionsProvider();
@@ -91,14 +91,15 @@
   // a once-dismissed suggestion is never delivered again (through the
   // Observer). The provider must not call Observer::OnSuggestionsChanged if the
   // removal of the dismissed suggestion is the only change.
-  virtual void DismissSuggestion(const std::string& suggestion_id) = 0;
+  virtual void DismissSuggestion(
+      const ContentSuggestion::ID& suggestion_id) = 0;
 
   // Fetches the image for the suggestion with the given ID and returns it
   // through the callback. This fetch may occur locally or from the internet.
   // If that suggestion doesn't exist, doesn't have an image or if the fetch
   // fails, the callback gets a null image. The callback will not be called
   // synchronously.
-  virtual void FetchSuggestionImage(const std::string& suggestion_id,
+  virtual void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                                     const ImageFetchedCallback& callback) = 0;
 
   // Removes history from the specified time range where the URL matches the
@@ -136,19 +137,6 @@
   ContentSuggestionsProvider(Observer* observer,
                              CategoryFactory* category_factory);
 
-  // Creates a unique ID. The given |within_category_id| must be unique among
-  // all suggestion IDs from this provider for the given |category|. This method
-  // combines it with the |category| to form an ID that is unique
-  // application-wide, because this provider is the only one that provides
-  // suggestions for that category.
-  std::string MakeUniqueID(Category category,
-                           const std::string& within_category_id) const;
-
-  // Reverse functions for MakeUniqueID()
-  Category GetCategoryFromUniqueID(const std::string& unique_id) const;
-  std::string GetWithinCategoryIDFromUniqueID(
-      const std::string& unique_id) const;
-
   Observer* observer() const { return observer_; }
   CategoryFactory* category_factory() const { return category_factory_; }
 
diff --git a/components/ntp_snippets/content_suggestions_service.cc b/components/ntp_snippets/content_suggestions_service.cc
index f141eab..f52a980 100644
--- a/components/ntp_snippets/content_suggestions_service.cc
+++ b/components/ntp_snippets/content_suggestions_service.cc
@@ -72,18 +72,17 @@
 }
 
 void ContentSuggestionsService::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
-  Category category = category_factory_.GetCategoryFromUniqueID(suggestion_id);
-  if (!providers_by_category_.count(category)) {
+  if (!providers_by_category_.count(suggestion_id.category())) {
     LOG(WARNING) << "Requested image for suggestion " << suggestion_id
-                 << " for unavailable category " << category;
+                 << " for unavailable category " << suggestion_id.category();
     base::ThreadTaskRunnerHandle::Get()->PostTask(
         FROM_HERE, base::Bind(callback, gfx::Image()));
     return;
   }
-  providers_by_category_[category]->FetchSuggestionImage(suggestion_id,
-                                                         callback);
+  providers_by_category_[suggestion_id.category()]->FetchSuggestionImage(
+      suggestion_id, callback);
 }
 
 void ContentSuggestionsService::ClearHistory(
@@ -130,17 +129,17 @@
 }
 
 void ContentSuggestionsService::DismissSuggestion(
-    const std::string& suggestion_id) {
-  Category category = category_factory_.GetCategoryFromUniqueID(suggestion_id);
-  if (!providers_by_category_.count(category)) {
+    const ContentSuggestion::ID& suggestion_id) {
+  if (!providers_by_category_.count(suggestion_id.category())) {
     LOG(WARNING) << "Dismissed suggestion " << suggestion_id
-                 << " for unavailable category " << category;
+                 << " for unavailable category " << suggestion_id.category();
     return;
   }
-  providers_by_category_[category]->DismissSuggestion(suggestion_id);
+  providers_by_category_[suggestion_id.category()]->DismissSuggestion(
+      suggestion_id);
 
   // Remove the suggestion locally.
-  bool removed = RemoveSuggestionByID(category, suggestion_id);
+  bool removed = RemoveSuggestionByID(suggestion_id);
   DCHECK(removed) << "The dismissed suggestion " << suggestion_id
                   << " has already been removed. Providers must not call"
                   << " OnNewSuggestions in response to DismissSuggestion.";
@@ -214,11 +213,10 @@
 
 void ContentSuggestionsService::OnSuggestionInvalidated(
     ContentSuggestionsProvider* provider,
-    Category category,
-    const std::string& suggestion_id) {
-  RemoveSuggestionByID(category, suggestion_id);
+    const ContentSuggestion::ID& suggestion_id) {
+  RemoveSuggestionByID(suggestion_id);
   FOR_EACH_OBSERVER(Observer, observers_,
-                    OnSuggestionInvalidated(category, suggestion_id));
+                    OnSuggestionInvalidated(suggestion_id));
 }
 
 // history::HistoryServiceObserver implementation.
@@ -287,10 +285,9 @@
 }
 
 bool ContentSuggestionsService::RemoveSuggestionByID(
-    Category category,
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   std::vector<ContentSuggestion>* suggestions =
-      &suggestions_by_category_[category];
+      &suggestions_by_category_[suggestion_id.category()];
   auto position =
       std::find_if(suggestions->begin(), suggestions->end(),
                    [&suggestion_id](const ContentSuggestion& suggestion) {
@@ -302,7 +299,7 @@
 
   // The positioning of the bookmarks category depends on whether it's empty.
   // TODO(treib): Remove this temporary hack, crbug.com/640568.
-  if (category.IsKnownCategory(KnownCategories::BOOKMARKS))
+  if (suggestion_id.category().IsKnownCategory(KnownCategories::BOOKMARKS))
     SortCategories();
 
   return true;
diff --git a/components/ntp_snippets/content_suggestions_service.h b/components/ntp_snippets/content_suggestions_service.h
index 8c4a4f7..045785f0 100644
--- a/components/ntp_snippets/content_suggestions_service.h
+++ b/components/ntp_snippets/content_suggestions_service.h
@@ -63,12 +63,12 @@
     // Fired when a suggestion has been invalidated. The UI must immediately
     // clear the suggestion even from open NTPs. Invalidation happens, for
     // example, when the content that the suggestion refers to is gone.
-    // Note that this event may be fired even if the corresponding |category| is
+    // Note that this event may be fired even if the corresponding category is
     // not currently AVAILABLE, because open UIs may still be showing the
     // suggestion that is to be removed. This event may also be fired for
     // |suggestion_id|s that never existed and should be ignored in that case.
-    virtual void OnSuggestionInvalidated(Category category,
-                                         const std::string& suggestion_id) = 0;
+    virtual void OnSuggestionInvalidated(
+        const ContentSuggestion::ID& suggestion_id) = 0;
 
     // Sent when the service is shutting down. After the service has shut down,
     // it will not provide any data anymore, though calling the getters is still
@@ -114,12 +114,12 @@
   // runs the |callback|. If that suggestion doesn't exist or the fetch fails,
   // the callback gets an empty image. The callback will not be called
   // synchronously.
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback);
 
   // Dismisses the suggestion with the given |suggestion_id|, if it exists.
   // This will not trigger an update through the observers.
-  void DismissSuggestion(const std::string& suggestion_id);
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id);
 
   // Dismisses the given |category|, if it exists.
   // This will not trigger an update through the observers.
@@ -193,9 +193,9 @@
   void OnCategoryStatusChanged(ContentSuggestionsProvider* provider,
                                Category category,
                                CategoryStatus new_status) override;
-  void OnSuggestionInvalidated(ContentSuggestionsProvider* provider,
-                               Category category,
-                               const std::string& suggestion_id) override;
+  void OnSuggestionInvalidated(
+      ContentSuggestionsProvider* provider,
+      const ContentSuggestion::ID& suggestion_id) override;
 
   // history::HistoryServiceObserver implementation.
   void OnURLsDeleted(history::HistoryService* history_service,
@@ -214,8 +214,7 @@
 
   // Removes a suggestion from the local store |suggestions_by_category_|, if it
   // exists. Returns true if a suggestion was removed.
-  bool RemoveSuggestionByID(Category category,
-                            const std::string& suggestion_id);
+  bool RemoveSuggestionByID(const ContentSuggestion::ID& suggestion_id);
 
   // Fires the OnCategoryStatusChanged event for the given |category|.
   void NotifyCategoryStatusChanged(Category category);
diff --git a/components/ntp_snippets/content_suggestions_service_unittest.cc b/components/ntp_snippets/content_suggestions_service_unittest.cc
index d0629cb..a2245bf 100644
--- a/components/ntp_snippets/content_suggestions_service_unittest.cc
+++ b/components/ntp_snippets/content_suggestions_service_unittest.cc
@@ -77,9 +77,8 @@
                                         statuses_[category.id()]);
   }
 
-  void FireSuggestionInvalidated(Category category,
-                                 const std::string& suggestion_id) {
-    observer()->OnSuggestionInvalidated(this, category, suggestion_id);
+  void FireSuggestionInvalidated(const ContentSuggestion::ID& suggestion_id) {
+    observer()->OnSuggestionInvalidated(this, suggestion_id);
   }
 
   MOCK_METHOD3(ClearHistory,
@@ -91,9 +90,10 @@
                void(Category category,
                     const DismissedSuggestionsCallback& callback));
   MOCK_METHOD1(ClearDismissedSuggestionsForDebugging, void(Category category));
-  MOCK_METHOD1(DismissSuggestion, void(const std::string& suggestion_id));
+  MOCK_METHOD1(DismissSuggestion,
+               void(const ContentSuggestion::ID& suggestion_id));
   MOCK_METHOD2(FetchSuggestionImage,
-               void(const std::string& suggestion_id,
+               void(const ContentSuggestion::ID& suggestion_id,
                     const ImageFetchedCallback& callback));
 
  private:
@@ -109,8 +109,8 @@
   MOCK_METHOD1(OnNewSuggestions, void(Category category));
   MOCK_METHOD2(OnCategoryStatusChanged,
                void(Category changed_category, CategoryStatus new_status));
-  MOCK_METHOD2(OnSuggestionInvalidated,
-               void(Category category, const std::string& suggestion_id));
+  MOCK_METHOD1(OnSuggestionInvalidated,
+               void(const ContentSuggestion::ID& suggestion_id));
   MOCK_METHOD0(ContentSuggestionsServiceShutdown, void());
 
  private:
@@ -143,11 +143,9 @@
 
     for (const auto& suggestion :
          service()->GetSuggestionsForCategory(category)) {
-      std::string within_category_id =
-          service()->category_factory()->GetWithinCategoryIDFromUniqueID(
-              suggestion.id());
+      std::string id_within_category = suggestion.id().id_within_category();
       int id;
-      ASSERT_TRUE(base::StringToInt(within_category_id, &id));
+      ASSERT_TRUE(base::StringToInt(id_within_category, &id));
       auto position = std::find(numbers.begin(), numbers.end(), id);
       if (position == numbers.end()) {
         ADD_FAILURE() << "Unexpected suggestion with ID " << id;
@@ -205,8 +203,7 @@
   // Returns a suggestion instance for testing.
   ContentSuggestion CreateSuggestion(Category category, int number) {
     return ContentSuggestion(
-        service()->category_factory()->MakeUniqueID(category,
-                                                    base::IntToString(number)),
+        category, base::IntToString(number),
         GURL("http://testsuggestion/" + base::IntToString(number)));
   }
 
@@ -299,7 +296,7 @@
 
   provider1->FireSuggestionsChanged(articles_category,
                                     CreateSuggestions(articles_category, {1}));
-  std::string suggestion_id = CreateSuggestion(articles_category, 1).id();
+  ContentSuggestion::ID suggestion_id(articles_category, "1");
 
   EXPECT_CALL(*provider1, FetchSuggestionImage(suggestion_id, _));
   EXPECT_CALL(*provider2, FetchSuggestionImage(_, _)).Times(0);
@@ -315,7 +312,8 @@
 
   base::RunLoop run_loop;
   // Assuming there will never be a category with the id below.
-  std::string suggestion_id = "21563|TestID";
+  ContentSuggestion::ID suggestion_id(category_factory()->FromIDValue(21563),
+                                      "TestID");
   EXPECT_CALL(*this, OnImageFetched(Property(&gfx::Image::IsEmpty, Eq(true))))
       .WillOnce(InvokeWithoutArgs(&run_loop, &base::RunLoop::Quit));
   service()->FetchSuggestionImage(
@@ -333,7 +331,7 @@
 
   provider2->FireSuggestionsChanged(
       offline_pages_category, CreateSuggestions(offline_pages_category, {11}));
-  std::string suggestion_id = CreateSuggestion(offline_pages_category, 11).id();
+  ContentSuggestion::ID suggestion_id(offline_pages_category, "11");
 
   EXPECT_CALL(*provider1, DismissSuggestion(_)).Times(0);
   EXPECT_CALL(*provider2, DismissSuggestion(suggestion_id));
@@ -351,19 +349,18 @@
       articles_category, CreateSuggestions(articles_category, {11, 12, 13}));
   ExpectThatSuggestionsAre(articles_category, {11, 12, 13});
 
-  std::string suggestion_id = CreateSuggestion(articles_category, 12).id();
-  EXPECT_CALL(observer,
-              OnSuggestionInvalidated(articles_category, suggestion_id));
-  provider->FireSuggestionInvalidated(articles_category, suggestion_id);
+  ContentSuggestion::ID suggestion_id(articles_category, "12");
+  EXPECT_CALL(observer, OnSuggestionInvalidated(suggestion_id));
+  provider->FireSuggestionInvalidated(suggestion_id);
   ExpectThatSuggestionsAre(articles_category, {11, 13});
   Mock::VerifyAndClearExpectations(&observer);
 
   // Unknown IDs must be forwarded (though no change happens to the service's
   // internal data structures) because previously opened UIs, which can still
   // show the invalidated suggestion, must be notified.
-  std::string unknown_id = CreateSuggestion(articles_category, 1234).id();
-  EXPECT_CALL(observer, OnSuggestionInvalidated(articles_category, unknown_id));
-  provider->FireSuggestionInvalidated(articles_category, unknown_id);
+  ContentSuggestion::ID unknown_id(articles_category, "1234");
+  EXPECT_CALL(observer, OnSuggestionInvalidated(unknown_id));
+  provider->FireSuggestionInvalidated(unknown_id);
   ExpectThatSuggestionsAre(articles_category, {11, 13});
   Mock::VerifyAndClearExpectations(&observer);
 
@@ -576,10 +573,10 @@
       bookmarks, CreateSuggestions(bookmarks, {1, 2}));
   EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
   bookmarks_provider->FireSuggestionInvalidated(
-      bookmarks, CreateSuggestion(bookmarks, 1).id());
+      ContentSuggestion::ID(bookmarks, "1"));
   EXPECT_THAT(service()->GetCategories(), ElementsAre(bookmarks, remote));
   bookmarks_provider->FireSuggestionInvalidated(
-      bookmarks, CreateSuggestion(bookmarks, 2).id());
+      ContentSuggestion::ID(bookmarks, "2"));
   EXPECT_THAT(service()->GetCategories(), ElementsAre(remote, bookmarks));
 
   // Same thing, but now the bookmarks category updates "naturally".
diff --git a/components/ntp_snippets/mock_content_suggestions_provider_observer.h b/components/ntp_snippets/mock_content_suggestions_provider_observer.h
index 01e273d..12bb1fd 100644
--- a/components/ntp_snippets/mock_content_suggestions_provider_observer.h
+++ b/components/ntp_snippets/mock_content_suggestions_provider_observer.h
@@ -37,10 +37,9 @@
                void(ContentSuggestionsProvider* provider,
                     Category category,
                     CategoryStatus new_status));
-  MOCK_METHOD3(OnSuggestionInvalidated,
+  MOCK_METHOD2(OnSuggestionInvalidated,
                void(ContentSuggestionsProvider* provider,
-                    Category category,
-                    const std::string& suggestion_id));
+                    const ContentSuggestion::ID& suggestion_id));
 };
 
 }  // namespace ntp_snippets
diff --git a/components/ntp_snippets/ntp_snippets_service.cc b/components/ntp_snippets/ntp_snippets_service.cc
index c59770b..e24233b 100644
--- a/components/ntp_snippets/ntp_snippets_service.cc
+++ b/components/ntp_snippets/ntp_snippets_service.cc
@@ -15,6 +15,7 @@
 #include "base/metrics/histogram_macros.h"
 #include "base/metrics/sparse_histogram.h"
 #include "base/path_service.h"
+#include "base/stl_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/task_runner_util.h"
@@ -321,39 +322,36 @@
                       /* show_if_empty */ true);
 }
 
-void NTPSnippetsService::DismissSuggestion(const std::string& suggestion_id) {
+void NTPSnippetsService::DismissSuggestion(
+    const ContentSuggestion::ID& suggestion_id) {
   if (!ready())
     return;
 
-  Category category = GetCategoryFromUniqueID(suggestion_id);
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
+  DCHECK(base::ContainsKey(categories_, suggestion_id.category()));
 
-  DCHECK(categories_.find(category) != categories_.end());
-
-  CategoryContent* content = &categories_[category];
-  auto it =
-      std::find_if(content->snippets.begin(), content->snippets.end(),
-                   [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
-                     return snippet->id() == snippet_id;
-                   });
+  CategoryContent* content = &categories_[suggestion_id.category()];
+  auto it = std::find_if(
+      content->snippets.begin(), content->snippets.end(),
+      [&suggestion_id](const std::unique_ptr<NTPSnippet>& snippet) {
+        return snippet->id() == suggestion_id.id_within_category();
+      });
   if (it == content->snippets.end())
     return;
 
   (*it)->set_dismissed(true);
 
   database_->SaveSnippet(**it);
-  database_->DeleteImage(snippet_id);
+  database_->DeleteImage(suggestion_id.id_within_category());
 
   content->dismissed.push_back(std::move(*it));
   content->snippets.erase(it);
 }
 
 void NTPSnippetsService::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
   database_->LoadImage(
-      snippet_id,
+      suggestion_id.id_within_category(),
       base::Bind(&NTPSnippetsService::OnSnippetImageFetchedFromDatabase,
                  base::Unretained(this), callback, suggestion_id));
 }
@@ -400,7 +398,7 @@
   for (const std::unique_ptr<NTPSnippet>& snippet : content.dismissed) {
     if (!snippet->is_complete())
       continue;
-    ContentSuggestion suggestion(MakeUniqueID(category, snippet->id()),
+    ContentSuggestion suggestion(category, snippet->id(),
                                  snippet->best_source().url);
     suggestion.set_amp_url(snippet->best_source().amp_url);
     suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
@@ -451,49 +449,38 @@
 // Private methods
 
 GURL NTPSnippetsService::FindSnippetImageUrl(
-    Category category,
-    const std::string& snippet_id) const {
-  DCHECK(categories_.find(category) != categories_.end());
+    const ContentSuggestion::ID& suggestion_id) const {
+  DCHECK(categories_.find(suggestion_id.category()) != categories_.end());
 
-  const CategoryContent& content = categories_.at(category);
-  // Search for the snippet in current and archived snippets.
-  auto it =
-      std::find_if(content.snippets.begin(), content.snippets.end(),
-                   [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
-                     return snippet->id() == snippet_id;
-                   });
-  if (it != content.snippets.end())
-    return (*it)->salient_image_url();
-
-  it = std::find_if(content.archived.begin(), content.archived.end(),
-                    [&snippet_id](const std::unique_ptr<NTPSnippet>& snippet) {
-                      return snippet->id() == snippet_id;
-                    });
-  if (it != content.archived.end())
-    return (*it)->salient_image_url();
-
-  return GURL();
+  const CategoryContent& content = categories_.at(suggestion_id.category());
+  const NTPSnippet* snippet =
+      content.FindSnippet(suggestion_id.id_within_category());
+  if (!snippet)
+    return GURL();
+  return snippet->salient_image_url();
 }
 
 // image_fetcher::ImageFetcherDelegate implementation.
-void NTPSnippetsService::OnImageDataFetched(const std::string& suggestion_id,
-                                            const std::string& image_data) {
+void NTPSnippetsService::OnImageDataFetched(
+    const std::string& id_within_category,
+    const std::string& image_data) {
   if (image_data.empty())
     return;
 
-  Category category = GetCategoryFromUniqueID(suggestion_id);
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
-
-  if (categories_.find(category) == categories_.end())
-    return;
-
   // Only save the image if the corresponding snippet still exists.
-  if (FindSnippetImageUrl(category, snippet_id).is_empty())
+  bool found = false;
+  for (const std::pair<const Category, CategoryContent>& entry : categories_) {
+    if (entry.second.FindSnippet(id_within_category)) {
+      found = true;
+      break;
+    }
+  }
+  if (!found)
     return;
 
   // Only cache the data in the DB, the actual serving is done in the callback
   // provided to |image_fetcher_| (OnSnippetImageDecodedFromNetwork()).
-  database_->SaveImage(snippet_id, image_data);
+  database_->SaveImage(id_within_category, image_data);
 }
 
 void NTPSnippetsService::OnDatabaseLoaded(NTPSnippet::PtrVector snippets) {
@@ -819,7 +806,7 @@
 
 void NTPSnippetsService::OnSnippetImageFetchedFromDatabase(
     const ImageFetchedCallback& callback,
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     std::string data) {
   // |image_decoder_| is null in tests.
   if (image_decoder_ && !data.empty()) {
@@ -835,7 +822,7 @@
 
 void NTPSnippetsService::OnSnippetImageDecodedFromDatabase(
     const ImageFetchedCallback& callback,
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const gfx::Image& image) {
   if (!image.IsEmpty()) {
     callback.Run(image);
@@ -843,24 +830,21 @@
   }
 
   // If decoding the image failed, delete the DB entry.
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
-  database_->DeleteImage(snippet_id);
+  database_->DeleteImage(suggestion_id.id_within_category());
 
   FetchSnippetImageFromNetwork(suggestion_id, callback);
 }
 
 void NTPSnippetsService::FetchSnippetImageFromNetwork(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
-  Category category = GetCategoryFromUniqueID(suggestion_id);
-  std::string snippet_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
-
-  if (categories_.find(category) == categories_.end()) {
-    OnSnippetImageDecodedFromNetwork(callback, suggestion_id, gfx::Image());
+  if (categories_.find(suggestion_id.category()) == categories_.end()) {
+    OnSnippetImageDecodedFromNetwork(
+        callback, suggestion_id.id_within_category(), gfx::Image());
     return;
   }
 
-  GURL image_url = FindSnippetImageUrl(category, snippet_id);
+  GURL image_url = FindSnippetImageUrl(suggestion_id);
 
   if (image_url.is_empty() ||
       !thumbnail_requests_throttler_.DemandQuotaForRequest(
@@ -868,19 +852,20 @@
     // Return an empty image. Directly, this is never synchronous with the
     // original FetchSuggestionImage() call - an asynchronous database query has
     // happened in the meantime.
-    OnSnippetImageDecodedFromNetwork(callback, suggestion_id, gfx::Image());
+    OnSnippetImageDecodedFromNetwork(
+        callback, suggestion_id.id_within_category(), gfx::Image());
     return;
   }
 
   image_fetcher_->StartOrQueueNetworkRequest(
-      suggestion_id, image_url,
+      suggestion_id.id_within_category(), image_url,
       base::Bind(&NTPSnippetsService::OnSnippetImageDecodedFromNetwork,
                  base::Unretained(this), callback));
 }
 
 void NTPSnippetsService::OnSnippetImageDecodedFromNetwork(
     const ImageFetchedCallback& callback,
-    const std::string& suggestion_id,
+    const std::string& id_within_category,
     const gfx::Image& image) {
   callback.Run(image);
 }
@@ -1026,7 +1011,7 @@
       // incomplete ones we kept.
       if (!snippet->is_complete())
         continue;
-      ContentSuggestion suggestion(MakeUniqueID(category, snippet->id()),
+      ContentSuggestion suggestion(category, snippet->id(),
                                    snippet->best_source().url);
       suggestion.set_amp_url(snippet->best_source().amp_url);
       suggestion.set_title(base::UTF8ToUTF16(snippet->title()));
@@ -1064,6 +1049,28 @@
   }
 }
 
+const NTPSnippet* NTPSnippetsService::CategoryContent::FindSnippet(
+    const std::string& id_within_category) const {
+  // Search for the snippet in current and archived snippets.
+  auto it = std::find_if(
+      snippets.begin(), snippets.end(),
+      [&id_within_category](const std::unique_ptr<NTPSnippet>& snippet) {
+        return snippet->id() == id_within_category;
+      });
+  if (it != snippets.end())
+    return it->get();
+
+  it = std::find_if(
+      archived.begin(), archived.end(),
+      [&id_within_category](const std::unique_ptr<NTPSnippet>& snippet) {
+        return snippet->id() == id_within_category;
+      });
+  if (it != archived.end())
+    return it->get();
+
+  return nullptr;
+}
+
 NTPSnippetsService::CategoryContent::CategoryContent() = default;
 NTPSnippetsService::CategoryContent::CategoryContent(CategoryContent&&) =
     default;
diff --git a/components/ntp_snippets/ntp_snippets_service.h b/components/ntp_snippets/ntp_snippets_service.h
index 1aac5ec6..d3f41e5 100644
--- a/components/ntp_snippets/ntp_snippets_service.h
+++ b/components/ntp_snippets/ntp_snippets_service.h
@@ -118,8 +118,8 @@
   // ContentSuggestionsProvider implementation
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
@@ -199,12 +199,12 @@
   };
 
   // Returns the URL of the image of a snippet if it is among the current or
-  // among the archived snippets in |category|. Returns an empty URL, otherwise.
-  GURL FindSnippetImageUrl(Category category,
-                           const std::string& snippet_id) const;
+  // among the archived snippets in the matching category. Returns an empty URL
+  // otherwise.
+  GURL FindSnippetImageUrl(const ContentSuggestion::ID& suggestion_id) const;
 
   // image_fetcher::ImageFetcherDelegate implementation.
-  void OnImageDataFetched(const std::string& suggestion_id,
+  void OnImageDataFetched(const std::string& id_within_category,
                           const std::string& image_data) override;
 
   // Callbacks for the NTPSnippetsDatabase.
@@ -242,19 +242,21 @@
   // observers. This is done after construction, once the database is loaded.
   void FinishInitialization();
 
-  void OnSnippetImageFetchedFromDatabase(const ImageFetchedCallback& callback,
-                                         const std::string& suggestion_id,
-                                         std::string data);
+  void OnSnippetImageFetchedFromDatabase(
+      const ImageFetchedCallback& callback,
+      const ContentSuggestion::ID& suggestion_id,
+      std::string data);
 
-  void OnSnippetImageDecodedFromDatabase(const ImageFetchedCallback& callback,
-                                         const std::string& suggestion_id,
-                                         const gfx::Image& image);
+  void OnSnippetImageDecodedFromDatabase(
+      const ImageFetchedCallback& callback,
+      const ContentSuggestion::ID& suggestion_id,
+      const gfx::Image& image);
 
-  void FetchSnippetImageFromNetwork(const std::string& suggestion_id,
+  void FetchSnippetImageFromNetwork(const ContentSuggestion::ID& suggestion_id,
                                     const ImageFetchedCallback& callback);
 
   void OnSnippetImageDecodedFromNetwork(const ImageFetchedCallback& callback,
-                                        const std::string& suggestion_id,
+                                        const std::string& id_within_category,
                                         const gfx::Image& image);
 
   // Triggers a state transition depending on the provided reason to be
@@ -320,6 +322,10 @@
     // expire so we won't re-add them to |snippets| on the next fetch.
     NTPSnippet::PtrVector dismissed;
 
+    // Returns a non-dismissed snippet with the given |id_within_category|, or
+    // null if none exist.
+    const NTPSnippet* FindSnippet(const std::string& id_within_category) const;
+
     CategoryContent();
     CategoryContent(CategoryContent&&);
     ~CategoryContent();
diff --git a/components/ntp_snippets/ntp_snippets_service_unittest.cc b/components/ntp_snippets/ntp_snippets_service_unittest.cc
index d9708da..a1dec51 100644
--- a/components/ntp_snippets/ntp_snippets_service_unittest.cc
+++ b/components/ntp_snippets/ntp_snippets_service_unittest.cc
@@ -299,9 +299,9 @@
     statuses_[category] = new_status;
   }
 
-  void OnSuggestionInvalidated(ContentSuggestionsProvider* provider,
-                               Category category,
-                               const std::string& suggestion_id) override {}
+  void OnSuggestionInvalidated(
+      ContentSuggestionsProvider* provider,
+      const ContentSuggestion::ID& suggestion_id) override {}
 
   const std::map<Category, CategoryStatus, Category::CompareByID>& statuses()
       const {
@@ -423,18 +423,16 @@
     *service = MakeSnippetsService();
   }
 
-  std::string MakeArticleID(const NTPSnippetsService& service,
-                            const std::string& within_category_id) {
-    return service.MakeUniqueID(articles_category(), within_category_id);
+  ContentSuggestion::ID MakeArticleID(const std::string& id_within_category) {
+    return ContentSuggestion::ID(articles_category(), id_within_category);
   }
 
   Category articles_category() {
     return category_factory_.FromKnownCategory(KnownCategories::ARTICLES);
   }
 
-  std::string MakeOtherID(const NTPSnippetsService& service,
-                          const std::string& within_category_id) {
-    return service.MakeUniqueID(other_category(), within_category_id);
+  ContentSuggestion::ID MakeOtherID(const std::string& id_within_category) {
+    return ContentSuggestion::ID(other_category(), id_within_category);
   }
 
   Category other_category() { return category_factory_.FromRemoteCategory(2); }
@@ -610,7 +608,7 @@
   const ContentSuggestion& suggestion =
       observer().SuggestionsForCategory(articles_category()).front();
 
-  EXPECT_EQ(MakeArticleID(*service, kSnippetUrl), suggestion.id());
+  EXPECT_EQ(MakeArticleID(kSnippetUrl), suggestion.id());
   EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
   EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
   EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
@@ -644,8 +642,7 @@
   {
     const ContentSuggestion& suggestion =
         observer().SuggestionsForCategory(articles_category()).front();
-    EXPECT_EQ(MakeArticleID(*service, std::string(kSnippetUrl) + "/0"),
-              suggestion.id());
+    EXPECT_EQ(MakeArticleID(std::string(kSnippetUrl) + "/0"), suggestion.id());
     EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
     EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
     EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
@@ -657,8 +654,7 @@
   {
     const ContentSuggestion& suggestion =
         observer().SuggestionsForCategory(other_category()).front();
-    EXPECT_EQ(MakeOtherID(*service, std::string(kSnippetUrl) + "/1"),
-              suggestion.id());
+    EXPECT_EQ(MakeOtherID(std::string(kSnippetUrl) + "/1"), suggestion.id());
     EXPECT_EQ(kSnippetTitle, base::UTF16ToUTF8(suggestion.title()));
     EXPECT_EQ(kSnippetText, base::UTF16ToUTF8(suggestion.snippet_text()));
     EXPECT_EQ(GetDefaultCreationTime(), suggestion.publish_date());
@@ -751,11 +747,11 @@
   ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
 
   // Dismissing a non-existent snippet shouldn't do anything.
-  service->DismissSuggestion(MakeArticleID(*service, "http://othersite.com"));
+  service->DismissSuggestion(MakeArticleID("http://othersite.com"));
   EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
 
   // Dismiss the snippet.
-  service->DismissSuggestion(MakeArticleID(*service, kSnippetUrl));
+  service->DismissSuggestion(MakeArticleID(kSnippetUrl));
   EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
 
   // Make sure that fetching the same snippet again does not re-add it.
@@ -779,7 +775,7 @@
 
   LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
 
-  service->DismissSuggestion(MakeArticleID(*service, kSnippetUrl));
+  service->DismissSuggestion(MakeArticleID(kSnippetUrl));
 
   service->GetDismissedSuggestionsForDebugging(
       articles_category(),
@@ -788,8 +784,7 @@
              std::vector<ContentSuggestion> dismissed_suggestions) {
             EXPECT_EQ(1u, dismissed_suggestions.size());
             for (auto& suggestion : dismissed_suggestions) {
-              EXPECT_EQ(test->MakeArticleID(*service, kSnippetUrl),
-                        suggestion.id());
+              EXPECT_EQ(test->MakeArticleID(kSnippetUrl), suggestion.id());
             }
           },
           service.get(), this));
@@ -829,7 +824,7 @@
   LoadFromJSONString(service.get(), json_str1);
   // Dismiss the suggestion
   service->DismissSuggestion(
-      service->MakeUniqueID(service->articles_category_, kSnippetUrl));
+      ContentSuggestion::ID(articles_category(), kSnippetUrl));
 
   // Load a different snippet - this will clear the expired dismissed ones.
   std::string json_str2(GetTestJson({GetSnippetWithUrl(kSnippetUrl2)}));
@@ -928,7 +923,7 @@
 
   // Dismissing a snippet should decrease the list size. This will only be
   // logged after the next fetch.
-  service->DismissSuggestion(MakeArticleID(*service, kSnippetUrl));
+  service->DismissSuggestion(MakeArticleID(kSnippetUrl));
   LoadFromJSONString(service.get(), GetTestJson({GetSnippet()}));
   EXPECT_THAT(tester.GetAllSamples("NewTabPage.Snippets.NumArticles"),
               ElementsAre(base::Bucket(/*min=*/0, /*count=*/3),
@@ -982,7 +977,7 @@
                          publishers[0], amp_urls[0])}));
   ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
   // Dismiss the snippet via the mashable source corpus ID.
-  service->DismissSuggestion(MakeArticleID(*service, source_urls[0]));
+  service->DismissSuggestion(MakeArticleID(source_urls[0]));
   EXPECT_THAT(service->GetSnippetsForTesting(articles_category()), IsEmpty());
 
   // The same article from the AOL domain should now be detected as dismissed.
@@ -1035,7 +1030,7 @@
   }
 
   service->FetchSuggestionImage(
-      MakeArticleID(*service, kSnippetUrl),
+      MakeArticleID(kSnippetUrl),
       base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
                  base::Unretained(&image_fetched)));
   base::RunLoop().RunUntilIdle();
@@ -1052,7 +1047,7 @@
   EXPECT_CALL(image_fetched, Call(_)).WillOnce(SaveArg<0>(&image));
 
   service->FetchSuggestionImage(
-      MakeArticleID(*service, kSnippetUrl2),
+      MakeArticleID(kSnippetUrl2),
       base::Bind(&MockFunction<void(const gfx::Image&)>::Call,
                  base::Unretained(&image_fetched)));
 
@@ -1069,7 +1064,7 @@
   LoadFromJSONString(service.get(), json_str);
   ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(2));
 
-  service->DismissSuggestion(MakeArticleID(*service, "http://url1.com"));
+  service->DismissSuggestion(MakeArticleID("http://url1.com"));
   ASSERT_THAT(service->GetSnippetsForTesting(articles_category()), SizeIs(1));
   ASSERT_THAT(service->GetDismissedSnippetsForTesting(articles_category()),
               SizeIs(1));
diff --git a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc
index 8d489a65..d1525ba4f 100644
--- a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc
+++ b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.cc
@@ -135,16 +135,15 @@
 }
 
 void OfflinePageSuggestionsProvider::DismissSuggestion(
-    const std::string& suggestion_id) {
-  Category category = GetCategoryFromUniqueID(suggestion_id);
-  std::string offline_page_id = GetWithinCategoryIDFromUniqueID(suggestion_id);
-  std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(category);
-  dismissed_ids.insert(offline_page_id);
-  StoreDismissedIDsToPrefs(category, dismissed_ids);
+    const ContentSuggestion::ID& suggestion_id) {
+  std::set<std::string> dismissed_ids =
+      ReadDismissedIDsFromPrefs(suggestion_id.category());
+  dismissed_ids.insert(suggestion_id.id_within_category());
+  StoreDismissedIDsToPrefs(suggestion_id.category(), dismissed_ids);
 }
 
 void OfflinePageSuggestionsProvider::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
   // TODO(pke): Fetch proper thumbnail from OfflinePageModel once it's available
   // there.
@@ -314,9 +313,9 @@
   // TODO(pke): Make sure the URL is actually opened as an offline URL.
   // Currently, the browser opens the offline URL and then immediately
   // redirects to the online URL if the device is online.
-  ContentSuggestion suggestion(
-      MakeUniqueID(category, base::IntToString(offline_page.offline_id)),
-      offline_page.GetOfflineURL());
+  ContentSuggestion suggestion(category,
+                               base::IntToString(offline_page.offline_id),
+                               offline_page.GetOfflineURL());
 
   if (offline_page.title.empty()) {
     // TODO(pke): Remove this fallback once the OfflinePageModel provides titles
@@ -348,8 +347,8 @@
 void OfflinePageSuggestionsProvider::InvalidateSuggestion(Category category,
                                                           int64_t offline_id) {
   std::string offline_page_id = base::IntToString(offline_id);
-  observer()->OnSuggestionInvalidated(this, category,
-                                      MakeUniqueID(category, offline_page_id));
+  observer()->OnSuggestionInvalidated(
+      this, ContentSuggestion::ID(category, offline_page_id));
 
   std::set<std::string> dismissed_ids = ReadDismissedIDsFromPrefs(category);
   auto it = dismissed_ids.find(offline_page_id);
diff --git a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h
index 19a058a5..41d421e 100644
--- a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h
+++ b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider.h
@@ -52,8 +52,8 @@
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
diff --git a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc
index 039ac5b..4ad0254f 100644
--- a/components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc
+++ b/components/ntp_snippets/offline_pages/offline_page_suggestions_provider_unittest.cc
@@ -134,8 +134,8 @@
     return category_factory_.FromKnownCategory(KnownCategories::DOWNLOADS);
   }
 
-  std::string GetDummySuggestionId(Category category, int id) {
-    return provider_->MakeUniqueID(category, base::IntToString(id));
+  ContentSuggestion::ID GetDummySuggestionId(Category category, int id) {
+    return ContentSuggestion::ID(category, base::IntToString(id));
   }
 
   ContentSuggestion CreateDummySuggestion(Category category, int id) {
@@ -348,10 +348,9 @@
   FireOfflinePageModelChanged();
 
   // Invalidation of suggestion 2 should be forwarded.
-  EXPECT_CALL(
-      *observer(),
-      OnSuggestionInvalidated(_, recent_tabs_category(),
-                              GetDummySuggestionId(recent_tabs_category(), 2)));
+  EXPECT_CALL(*observer(),
+              OnSuggestionInvalidated(
+                  _, GetDummySuggestionId(recent_tabs_category(), 2)));
   FireOfflinePageDeleted(model()->items().at(1));
 }
 
diff --git a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
index 22dd7ed..b87f20e 100644
--- a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
+++ b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.cc
@@ -45,9 +45,8 @@
   for (const UrlInfo& url_info : urls) {
     if (suggestions.size() >= kMaxSuggestionsCount) break;
 
-    ContentSuggestion suggestion(
-        MakeUniqueID(provided_category_, url_info.site_url.spec()),
-        url_info.site_url);
+    ContentSuggestion suggestion(provided_category_, url_info.site_url.spec(),
+                                 url_info.site_url);
 
     suggestion.set_title(base::UTF8ToUTF16(url_info.title));
     suggestion.set_snippet_text(base::UTF8ToUTF16(url_info.description));
@@ -75,13 +74,14 @@
 }
 
 void PhysicalWebPageSuggestionsProvider::DismissSuggestion(
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   // TODO(vitaliii): Implement this and then
   // ClearDismissedSuggestionsForDebugging.
 }
 
 void PhysicalWebPageSuggestionsProvider::FetchSuggestionImage(
-    const std::string& suggestion_id, const ImageFetchedCallback& callback) {
+    const ContentSuggestion::ID& suggestion_id,
+    const ImageFetchedCallback& callback) {
   // TODO(vitaliii): Implement.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, gfx::Image()));
diff --git a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
index b2c7431a..934dd74 100644
--- a/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
+++ b/components/ntp_snippets/physical_web_pages/physical_web_page_suggestions_provider.h
@@ -45,8 +45,8 @@
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
diff --git a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
index 0a6aaa7..f913d66 100644
--- a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
+++ b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.cc
@@ -125,21 +125,21 @@
 }
 
 void ForeignSessionsSuggestionsProvider::DismissSuggestion(
-    const std::string& suggestion_id) {
+    const ContentSuggestion::ID& suggestion_id) {
   // TODO(skym): Right now this continuously grows, without clearing out old and
   // irrelevant entries. Could either use a timestamp and expire after a
   // threshold, or compare with current foreign tabs and remove anything that
   // isn't actively blockign a foreign_sessions tab.
   std::set<std::string> dismissed_ids = prefs::ReadDismissedIDsFromPrefs(
       *pref_service_, prefs::kDismissedForeignSessionsSuggestions);
-  dismissed_ids.insert(suggestion_id);
+  dismissed_ids.insert(suggestion_id.id_within_category());
   prefs::StoreDismissedIDsToPrefs(pref_service_,
                                   prefs::kDismissedForeignSessionsSuggestions,
                                   dismissed_ids);
 }
 
 void ForeignSessionsSuggestionsProvider::FetchSuggestionImage(
-    const std::string& suggestion_id,
+    const ContentSuggestion::ID& suggestion_id,
     const ImageFetchedCallback& callback) {
   base::ThreadTaskRunnerHandle::Get()->PostTask(
       FROM_HERE, base::Bind(callback, gfx::Image()));
@@ -152,7 +152,7 @@
   std::set<std::string> dismissed_ids = prefs::ReadDismissedIDsFromPrefs(
       *pref_service_, prefs::kDismissedForeignSessionsSuggestions);
   for (auto iter = dismissed_ids.begin(); iter != dismissed_ids.end();) {
-    if (filter.Run(GURL(base::StringPiece(*iter)))) {
+    if (filter.Run(GURL(*iter))) {
       iter = dismissed_ids.erase(iter);
     } else {
       ++iter;
@@ -277,13 +277,12 @@
           continue;
 
         const SerializedNavigationEntry& navigation = tab->navigations.back();
-        const std::string unique_id =
-            MakeUniqueID(provided_category_, navigation.virtual_url().spec());
+        const std::string id = navigation.virtual_url().spec();
         // TODO(skym): Filter out internal pages. Tabs that contain only
         // non-syncable content should never reach the local client, but
         // sometimes the most recent navigation may be internal while one
         // of the previous ones was more valid.
-        if (dismissed_ids.find(unique_id) == dismissed_ids.end() &&
+        if (dismissed_ids.find(id) == dismissed_ids.end() &&
             (base::Time::Now() - tab->timestamp) < max_foreign_tab_age) {
           suggestion_candidates.push_back(
               SessionData{session, tab.get(), &navigation});
@@ -296,9 +295,9 @@
 
 ContentSuggestion ForeignSessionsSuggestionsProvider::BuildSuggestion(
     const SessionData& data) {
-  ContentSuggestion suggestion(
-      MakeUniqueID(provided_category_, data.navigation->virtual_url().spec()),
-      data.navigation->virtual_url());
+  ContentSuggestion suggestion(provided_category_,
+                               data.navigation->virtual_url().spec(),
+                               data.navigation->virtual_url());
   suggestion.set_title(data.navigation->title());
   suggestion.set_publish_date(data.tab->timestamp);
   // TODO(skym): It's unclear if this simple approach is sufficient for
diff --git a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
index bb9540b9..4d21a3f 100644
--- a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
+++ b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider.h
@@ -54,8 +54,8 @@
   // ContentSuggestionsProvider implementation.
   CategoryStatus GetCategoryStatus(Category category) override;
   CategoryInfo GetCategoryInfo(Category category) override;
-  void DismissSuggestion(const std::string& suggestion_id) override;
-  void FetchSuggestionImage(const std::string& suggestion_id,
+  void DismissSuggestion(const ContentSuggestion::ID& suggestion_id) override;
+  void FetchSuggestionImage(const ContentSuggestion::ID& suggestion_id,
                             const ImageFetchedCallback& callback) override;
   void ClearHistory(
       base::Time begin,
diff --git a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
index 202c0398..e36cf23 100644
--- a/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
+++ b/components/ntp_snippets/sessions/foreign_sessions_suggestions_provider_unittest.cc
@@ -149,8 +149,8 @@
   }
 
   void Dismiss(const std::string& url) {
-    // The url of a given suggestion is used as the |within_category_id|.
-    provider_->DismissSuggestion(provider_->MakeUniqueID(category(), url));
+    // The url of a given suggestion is used as the |id_within_category|.
+    provider_->DismissSuggestion(ContentSuggestion::ID(category(), url));
   }
 
   Category category() {
diff --git a/components/safe_browsing_db/database_manager.cc b/components/safe_browsing_db/database_manager.cc
index a882409a..91e4d7b6 100644
--- a/components/safe_browsing_db/database_manager.cc
+++ b/components/safe_browsing_db/database_manager.cc
@@ -67,9 +67,8 @@
   return api_checks_.end();
 }
 
-std::unordered_set<ListIdentifier>
-SafeBrowsingDatabaseManager::GetStoresForFullHashRequests() {
-  return std::unordered_set<ListIdentifier>({GetChromeUrlApiId()});
+StoresToCheck SafeBrowsingDatabaseManager::GetStoresForFullHashRequests() {
+  return StoresToCheck({GetChromeUrlApiId()});
 }
 
 void SafeBrowsingDatabaseManager::OnThreatMetadataResponse(
diff --git a/components/safe_browsing_db/database_manager.h b/components/safe_browsing_db/database_manager.h
index 687c7be..0d24b8bf 100644
--- a/components/safe_browsing_db/database_manager.h
+++ b/components/safe_browsing_db/database_manager.h
@@ -172,7 +172,7 @@
   //
 
   // Returns the lists that this DatabaseManager should get full hashes for.
-  virtual std::unordered_set<ListIdentifier> GetStoresForFullHashRequests();
+  virtual StoresToCheck GetStoresForFullHashRequests();
 
   // Returns the ThreatSource for this implementation.
   virtual ThreatSource GetThreatSource() const = 0;
diff --git a/components/safe_browsing_db/v4_database.cc b/components/safe_browsing_db/v4_database.cc
index 532475b1..efcbe7b 100644
--- a/components/safe_browsing_db/v4_database.cc
+++ b/components/safe_browsing_db/v4_database.cc
@@ -174,11 +174,11 @@
 
 void V4Database::GetStoresMatchingFullHash(
     const FullHash& full_hash,
-    const std::unordered_set<ListIdentifier>& stores_to_look,
+    const StoresToCheck& stores_to_check,
     StoreAndHashPrefixes* matched_store_and_hash_prefixes) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   matched_store_and_hash_prefixes->clear();
-  for (const ListIdentifier& identifier : stores_to_look) {
+  for (const ListIdentifier& identifier : stores_to_check) {
     const auto& store_pair = store_map_->find(identifier);
     DCHECK(store_pair != store_map_->end());
     const std::unique_ptr<V4Store>& store = store_pair->second;
diff --git a/components/safe_browsing_db/v4_database.h b/components/safe_browsing_db/v4_database.h
index 6b41731..bddba598 100644
--- a/components/safe_browsing_db/v4_database.h
+++ b/components/safe_browsing_db/v4_database.h
@@ -109,11 +109,11 @@
   std::unique_ptr<StoreStateMap> GetStoreStateMap();
 
   // Searches for a hash prefix matching the |full_hash| in stores in the
-  // database, filtered by |stores_to_look|, and returns the identifier of the
+  // database, filtered by |stores_to_check|, and returns the identifier of the
   // store along with the matching hash prefix in |matched_hash_prefix_map|.
   virtual void GetStoresMatchingFullHash(
       const FullHash& full_hash,
-      const std::unordered_set<ListIdentifier>& stores_to_look,
+      const StoresToCheck& stores_to_check,
       StoreAndHashPrefixes* matched_store_and_full_hashes);
 
   // Deletes the current database and creates a new one.
diff --git a/components/safe_browsing_db/v4_database_unittest.cc b/components/safe_browsing_db/v4_database_unittest.cc
index e16f182..2ce05ee 100644
--- a/components/safe_browsing_db/v4_database_unittest.cc
+++ b/components/safe_browsing_db/v4_database_unittest.cc
@@ -380,17 +380,16 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(true, created_and_called_back_);
 
-  std::unordered_set<ListIdentifier> stores_to_look(
-      {linux_malware_id_, win_malware_id_});
+  StoresToCheck stores_to_check({linux_malware_id_, win_malware_id_});
   StoreAndHashPrefixes store_and_hash_prefixes;
-  v4_database_->GetStoresMatchingFullHash("anything", stores_to_look,
+  v4_database_->GetStoresMatchingFullHash("anything", stores_to_check,
                                           &store_and_hash_prefixes);
   EXPECT_EQ(2u, store_and_hash_prefixes.size());
-  std::unordered_set<ListIdentifier> stores_found;
+  StoresToCheck stores_found;
   for (const auto& it : store_and_hash_prefixes) {
     stores_found.insert(it.list_id);
   }
-  EXPECT_EQ(stores_to_look, stores_found);
+  EXPECT_EQ(stores_to_check, stores_found);
 }
 
 // Test to ensure the case that no stores match a given full hash.
@@ -407,11 +406,10 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(true, created_and_called_back_);
 
-  std::unordered_set<ListIdentifier> stores_to_look(
-      {linux_malware_id_, win_malware_id_});
   StoreAndHashPrefixes store_and_hash_prefixes;
-  v4_database_->GetStoresMatchingFullHash("anything", stores_to_look,
-                                          &store_and_hash_prefixes);
+  v4_database_->GetStoresMatchingFullHash(
+      "anything", StoresToCheck({linux_malware_id_, win_malware_id_}),
+      &store_and_hash_prefixes);
   EXPECT_TRUE(store_and_hash_prefixes.empty());
 }
 
@@ -435,18 +433,17 @@
       v4_database_->store_map_->at(win_malware_id_).get());
   store->set_hash_prefix_matches(true);
 
-  std::unordered_set<ListIdentifier> stores_to_look(
-      {linux_malware_id_, win_malware_id_});
   StoreAndHashPrefixes store_and_hash_prefixes;
-  v4_database_->GetStoresMatchingFullHash("anything", stores_to_look,
-                                          &store_and_hash_prefixes);
+  v4_database_->GetStoresMatchingFullHash(
+      "anything", StoresToCheck({linux_malware_id_, win_malware_id_}),
+      &store_and_hash_prefixes);
   EXPECT_EQ(1u, store_and_hash_prefixes.size());
   EXPECT_EQ(store_and_hash_prefixes.begin()->list_id, win_malware_id_);
   EXPECT_FALSE(store_and_hash_prefixes.begin()->hash_prefix.empty());
 }
 
 // Test to ensure the case that only some stores are reported to match a given
-// full hash because of stores_to_look.
+// full hash because of StoresToCheck.
 TEST_F(V4DatabaseTest, TestSomeStoresMatchFullHashBecauseOfStoresToMatch) {
   // Setup all stores to match the full hash.
   bool hash_prefix_matches = true;
@@ -461,11 +458,10 @@
   base::RunLoop().RunUntilIdle();
   EXPECT_EQ(true, created_and_called_back_);
 
-  std::unordered_set<ListIdentifier> stores_to_look({linux_malware_id_});
-  // Don't add win_malware_id_ to the stores_to_look.
+  // Don't add win_malware_id_ to the StoresToCheck.
   StoreAndHashPrefixes store_and_hash_prefixes;
-  v4_database_->GetStoresMatchingFullHash("anything", stores_to_look,
-                                          &store_and_hash_prefixes);
+  v4_database_->GetStoresMatchingFullHash(
+      "anything", StoresToCheck({linux_malware_id_}), &store_and_hash_prefixes);
   EXPECT_EQ(1u, store_and_hash_prefixes.size());
   EXPECT_EQ(store_and_hash_prefixes.begin()->list_id, linux_malware_id_);
   EXPECT_FALSE(store_and_hash_prefixes.begin()->hash_prefix.empty());
diff --git a/components/safe_browsing_db/v4_get_hash_protocol_manager.cc b/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
index dcd03e7..5994c4f 100644
--- a/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
+++ b/components/safe_browsing_db/v4_get_hash_protocol_manager.cc
@@ -142,10 +142,10 @@
   ~V4GetHashProtocolManagerFactoryImpl() override {}
   std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager(
       net::URLRequestContextGetter* request_context_getter,
-      const std::unordered_set<ListIdentifier>& stores_to_request,
+      const StoresToCheck& stores_to_check,
       const V4ProtocolConfig& config) override {
     return base::WrapUnique(new V4GetHashProtocolManager(
-        request_context_getter, stores_to_request, config));
+        request_context_getter, stores_to_check, config));
   }
 
  private:
@@ -211,12 +211,12 @@
 // static
 std::unique_ptr<V4GetHashProtocolManager> V4GetHashProtocolManager::Create(
     net::URLRequestContextGetter* request_context_getter,
-    const std::unordered_set<ListIdentifier>& stores_to_request,
+    const StoresToCheck& stores_to_check,
     const V4ProtocolConfig& config) {
   if (!factory_)
     factory_ = new V4GetHashProtocolManagerFactoryImpl();
   return factory_->CreateProtocolManager(request_context_getter,
-                                         stores_to_request, config);
+                                         stores_to_check, config);
 }
 
 // static
@@ -229,7 +229,7 @@
 
 V4GetHashProtocolManager::V4GetHashProtocolManager(
     net::URLRequestContextGetter* request_context_getter,
-    const std::unordered_set<ListIdentifier>& stores_to_request,
+    const StoresToCheck& stores_to_check,
     const V4ProtocolConfig& config)
     : gethash_error_count_(0),
       gethash_back_off_mult_(1),
@@ -238,8 +238,8 @@
       request_context_getter_(request_context_getter),
       url_fetcher_id_(0),
       clock_(new base::DefaultClock()) {
-  DCHECK(!stores_to_request.empty());
-  for (const ListIdentifier& store : stores_to_request) {
+  DCHECK(!stores_to_check.empty());
+  for (const ListIdentifier& store : stores_to_check) {
     platform_types_.insert(store.platform_type());
     threat_entry_types_.insert(store.threat_entry_type());
     threat_types_.insert(store.threat_type());
diff --git a/components/safe_browsing_db/v4_get_hash_protocol_manager.h b/components/safe_browsing_db/v4_get_hash_protocol_manager.h
index 29f49c1..44b05d7 100644
--- a/components/safe_browsing_db/v4_get_hash_protocol_manager.h
+++ b/components/safe_browsing_db/v4_get_hash_protocol_manager.h
@@ -147,7 +147,7 @@
   // Create an instance of the safe browsing v4 protocol manager.
   static std::unique_ptr<V4GetHashProtocolManager> Create(
       net::URLRequestContextGetter* request_context_getter,
-      const std::unordered_set<ListIdentifier>& stores_to_request,
+      const StoresToCheck& stores_to_check,
       const V4ProtocolConfig& config);
 
   // Makes the passed |factory| the factory used to instantiate
@@ -183,12 +183,11 @@
   void OnURLFetchComplete(const net::URLFetcher* source) override;
 
  protected:
-  // Constructs a V4GetHashProtocolManager that issues
-  // network requests using |request_context_getter|.
-  V4GetHashProtocolManager(
-      net::URLRequestContextGetter* request_context_getter,
-      const std::unordered_set<ListIdentifier>& stores_to_request,
-      const V4ProtocolConfig& config);
+  // Constructs a V4GetHashProtocolManager that issues network requests using
+  // |request_context_getter|.
+  V4GetHashProtocolManager(net::URLRequestContextGetter* request_context_getter,
+                           const StoresToCheck& stores_to_check,
+                           const V4ProtocolConfig& config);
 
  private:
   FRIEND_TEST_ALL_PREFIXES(V4GetHashProtocolManagerTest, TestGetHashRequest);
@@ -345,7 +344,7 @@
   virtual ~V4GetHashProtocolManagerFactory() {}
   virtual std::unique_ptr<V4GetHashProtocolManager> CreateProtocolManager(
       net::URLRequestContextGetter* request_context_getter,
-      const std::unordered_set<ListIdentifier>& stores_to_request,
+      const StoresToCheck& stores_to_check,
       const V4ProtocolConfig& config) = 0;
 
  private:
diff --git a/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc b/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
index c8b0542e..bb89fd9 100644
--- a/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
+++ b/components/safe_browsing_db/v4_get_hash_protocol_manager_unittest.cc
@@ -80,9 +80,8 @@
     config.client_name = kClient;
     config.version = kAppVer;
     config.key_param = kKeyParam;
-    std::unordered_set<ListIdentifier> stores_to_look(
-        {GetUrlMalwareId(), GetChromeUrlApiId()});
-    return V4GetHashProtocolManager::Create(NULL, stores_to_look, config);
+    StoresToCheck stores_to_check({GetUrlMalwareId(), GetChromeUrlApiId()});
+    return V4GetHashProtocolManager::Create(NULL, stores_to_check, config);
   }
 
   static void SetupFetcherToReturnOKResponse(
diff --git a/components/safe_browsing_db/v4_local_database_manager.cc b/components/safe_browsing_db/v4_local_database_manager.cc
index 6d46cde..9215dc7 100644
--- a/components/safe_browsing_db/v4_local_database_manager.cc
+++ b/components/safe_browsing_db/v4_local_database_manager.cc
@@ -52,11 +52,15 @@
 V4LocalDatabaseManager::PendingCheck::PendingCheck(
     Client* client,
     ClientCallbackType client_callback_type,
+    const StoresToCheck& stores_to_check,
     const GURL& url)
     : client(client),
       client_callback_type(client_callback_type),
       result_threat_type(SB_THREAT_TYPE_SAFE),
-      url(url) {}
+      stores_to_check(stores_to_check),
+      url(url) {
+  DCHECK_GT(ClientCallbackType::CHECK_MAX, client_callback_type);
+}
 
 V4LocalDatabaseManager::PendingCheck::~PendingCheck() {}
 
@@ -86,7 +90,14 @@
     pending_clients_.erase(it);
   }
 
-  // TODO(vakh): Handle the case of queued checks.
+  auto queued_it =
+      std::find_if(std::begin(queued_checks_), std::end(queued_checks_),
+                   [&client](const std::unique_ptr<PendingCheck>& check) {
+                     return check->client == client;
+                   });
+  if (queued_it != queued_checks_.end()) {
+    queued_checks_.erase(queued_it);
+  }
 }
 
 bool V4LocalDatabaseManager::CanCheckResourceType(
@@ -111,47 +122,21 @@
     return true;
   }
 
-  if (v4_database_) {
-    std::unordered_set<FullHash> full_hashes;
-    V4ProtocolManagerUtil::UrlToFullHashes(url, &full_hashes);
-
-    std::unordered_set<ListIdentifier> stores_to_look(
-        {GetUrlMalwareId(), GetUrlSocEngId()});
-    std::unordered_set<HashPrefix> matched_hash_prefixes;
-    std::unordered_set<ListIdentifier> matched_stores;
-    StoreAndHashPrefixes matched_store_and_hash_prefixes;
-    FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
-    for (const auto& full_hash : full_hashes) {
-      matched_store_and_hash_prefixes.clear();
-      v4_database_->GetStoresMatchingFullHash(full_hash, stores_to_look,
-                                              &matched_store_and_hash_prefixes);
-      if (!matched_store_and_hash_prefixes.empty()) {
-        full_hash_to_store_and_hash_prefixes[full_hash] =
-            matched_store_and_hash_prefixes;
-      }
-    }
-
-    if (full_hash_to_store_and_hash_prefixes.empty()) {
-      return true;
-    } else {
-      std::unique_ptr<PendingCheck> pending_check =
-          base::MakeUnique<PendingCheck>(
-              client, ClientCallbackType::CHECK_BROWSE_URL, url);
-
-      pending_clients_.insert(client);
-
-      v4_get_hash_protocol_manager_->GetFullHashes(
-          full_hash_to_store_and_hash_prefixes,
-          base::Bind(&V4LocalDatabaseManager::OnFullHashResponse,
-                     base::Unretained(this), base::Passed(&pending_check)));
-
-      return false;
-    }
-  } else {
-    // TODO(vakh): Queue the check and process it when the database becomes
-    // ready.
+  std::unique_ptr<PendingCheck> check = base::MakeUnique<PendingCheck>(
+      client, ClientCallbackType::CHECK_BROWSE_URL,
+      StoresToCheck({GetUrlMalwareId(), GetUrlSocEngId()}), url);
+  if (!v4_database_) {
+    queued_checks_.push_back(std::move(check));
     return false;
   }
+
+  FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+  if (!GetPrefixMatches(check, &full_hash_to_store_and_hash_prefixes)) {
+    return true;
+  }
+
+  PerformFullHashCheck(std::move(check), full_hash_to_store_and_hash_prefixes);
+  return false;
 }
 
 bool V4LocalDatabaseManager::CheckDownloadUrl(
@@ -255,6 +240,8 @@
 
   pending_clients_.clear();
 
+  RespondSafeToQueuedChecks();
+
   // Delete the V4Database. Any pending writes to disk are completed.
   // This operation happens on the task_runner on which v4_database_ operates
   // and doesn't block the IO thread.
@@ -285,6 +272,8 @@
     // The database is in place. Start fetching updates now.
     v4_update_protocol_manager_->ScheduleNextUpdate(
         v4_database_->GetStoreStateMap());
+
+    ProcessQueuedChecks();
   } else {
     // Schedule the deletion of v4_database off IO thread.
     V4Database::Destroy(std::move(v4_database));
@@ -298,6 +287,39 @@
   }
 }
 
+bool V4LocalDatabaseManager::GetPrefixMatches(
+    const std::unique_ptr<PendingCheck>& check,
+    FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  DCHECK(enabled_);
+  DCHECK(v4_database_);
+  DCHECK_GT(ClientCallbackType::CHECK_MAX, check->client_callback_type);
+
+  if (check->client_callback_type == ClientCallbackType::CHECK_BROWSE_URL) {
+    std::unordered_set<FullHash> full_hashes;
+    V4ProtocolManagerUtil::UrlToFullHashes(check->url, &full_hashes);
+
+    StoreAndHashPrefixes matched_store_and_hash_prefixes;
+    for (const auto& full_hash : full_hashes) {
+      matched_store_and_hash_prefixes.clear();
+      v4_database_->GetStoresMatchingFullHash(full_hash, check->stores_to_check,
+                                              &matched_store_and_hash_prefixes);
+      if (!matched_store_and_hash_prefixes.empty()) {
+        (*full_hash_to_store_and_hash_prefixes)[full_hash] =
+            matched_store_and_hash_prefixes;
+      }
+    }
+
+    // No hash prefixes found in the local database so that resource must be
+    // safe.
+    return !full_hash_to_store_and_hash_prefixes->empty();
+  }
+
+  NOTREACHED() << "Unexpected client_callback_type encountered";
+  return false;
+}
+
 void V4LocalDatabaseManager::GetSeverestThreatTypeAndMetadata(
     SBThreatType* result_threat_type,
     ThreatMetadata* metadata,
@@ -316,6 +338,14 @@
   }
 }
 
+StoresToCheck V4LocalDatabaseManager::GetStoresForFullHashRequests() {
+  StoresToCheck stores_for_full_hash;
+  for (auto it : list_infos_) {
+    stores_for_full_hash.insert(it.list_id());
+  }
+  return stores_for_full_hash;
+}
+
 // Returns the SBThreatType corresponding to a given SafeBrowsing list.
 SBThreatType V4LocalDatabaseManager::GetSBThreatTypeForList(
     const ListIdentifier& list_id) {
@@ -327,15 +357,6 @@
   return it->sb_threat_type();
 }
 
-std::unordered_set<ListIdentifier>
-V4LocalDatabaseManager::GetStoresForFullHashRequests() {
-  std::unordered_set<ListIdentifier> stores_for_full_hash;
-  for (auto it : list_infos_) {
-    stores_for_full_hash.insert(it.list_id());
-  }
-  return stores_for_full_hash;
-}
-
 void V4LocalDatabaseManager::OnFullHashResponse(
     std::unique_ptr<PendingCheck> pending_check,
     const std::vector<FullHashInfo>& full_hash_infos) {
@@ -356,8 +377,46 @@
   GetSeverestThreatTypeAndMetadata(&pending_check->result_threat_type,
                                    &pending_check->url_metadata,
                                    full_hash_infos);
-  RespondToClient(std::move(pending_check));
   pending_clients_.erase(it);
+  RespondToClient(std::move(pending_check));
+}
+
+void V4LocalDatabaseManager::PerformFullHashCheck(
+    std::unique_ptr<PendingCheck> check,
+    const FullHashToStoreAndHashPrefixesMap&
+        full_hash_to_store_and_hash_prefixes) {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+
+  DCHECK(enabled_);
+  DCHECK(!full_hash_to_store_and_hash_prefixes.empty());
+
+  pending_clients_.insert(check->client);
+
+  v4_get_hash_protocol_manager_->GetFullHashes(
+      full_hash_to_store_and_hash_prefixes,
+      base::Bind(&V4LocalDatabaseManager::OnFullHashResponse,
+                 base::Unretained(this), base::Passed(std::move(check))));
+}
+
+void V4LocalDatabaseManager::ProcessQueuedChecks() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  for (auto& it : queued_checks_) {
+    FullHashToStoreAndHashPrefixesMap full_hash_to_store_and_hash_prefixes;
+    if (!GetPrefixMatches(it, &full_hash_to_store_and_hash_prefixes)) {
+      RespondToClient(std::move(it));
+    } else {
+      PerformFullHashCheck(std::move(it), full_hash_to_store_and_hash_prefixes);
+    }
+  }
+  queued_checks_.clear();
+}
+
+void V4LocalDatabaseManager::RespondSafeToQueuedChecks() {
+  DCHECK_CURRENTLY_ON(BrowserThread::IO);
+  for (std::unique_ptr<PendingCheck>& it : queued_checks_) {
+    RespondToClient(std::move(it));
+  }
+  queued_checks_.clear();
 }
 
 void V4LocalDatabaseManager::RespondToClient(
diff --git a/components/safe_browsing_db/v4_local_database_manager.h b/components/safe_browsing_db/v4_local_database_manager.h
index 4dd4707..f9510c4 100644
--- a/components/safe_browsing_db/v4_local_database_manager.h
+++ b/components/safe_browsing_db/v4_local_database_manager.h
@@ -37,36 +37,6 @@
     CHECK_MAX
   };
 
-  // The information we need to return the response to the SafeBrowsing client
-  // that asked for the safety reputation of a URL if we can't determine that
-  // synchronously.
-  // TODO(vakh): In its current form, it only includes information for
-  // |CheckBrowseUrl| method. Extend it to serve other methods on |client|.
-  struct PendingCheck {
-    PendingCheck(Client* client,
-                 ClientCallbackType client_callback_type,
-                 const GURL& url);
-
-    ~PendingCheck();
-
-    // The SafeBrowsing client that's waiting for the safe/unsafe verdict.
-    Client* client;
-
-    // Determines which funtion from the |client| needs to be called once we
-    // know whether the URL in |url| is safe or unsafe.
-    ClientCallbackType client_callback_type;
-
-    // The threat verdict for the URL being checked.
-    SBThreatType result_threat_type;
-
-    // The URL that is being checked for being unsafe.
-    GURL url;
-
-    // The metadata associated with the full hash of the severest match found
-    // for that URL.
-    ThreatMetadata url_metadata;
-  };
-
   // Construct V4LocalDatabaseManager.
   // Must be initialized by calling StartOnIOThread() before using.
   V4LocalDatabaseManager(const base::FilePath& base_path);
@@ -104,7 +74,44 @@
   //
 
  protected:
-  std::unordered_set<ListIdentifier> GetStoresForFullHashRequests() override;
+  // The information we need to process a URL safety reputation request and
+  // respond to the SafeBrowsing client that asked for it.
+  // TODO(vakh): In its current form, it only includes information for
+  // |CheckBrowseUrl| method. Extend it to serve other methods on |client|.
+  struct PendingCheck {
+    PendingCheck(Client* client,
+                 ClientCallbackType client_callback_type,
+                 const StoresToCheck& stores_to_check,
+                 const GURL& url);
+
+    ~PendingCheck();
+
+    // The SafeBrowsing client that's waiting for the safe/unsafe verdict.
+    Client* client;
+
+    // Determines which funtion from the |client| needs to be called once we
+    // know whether the URL in |url| is safe or unsafe.
+    ClientCallbackType client_callback_type;
+
+    // The threat verdict for the URL being checked.
+    SBThreatType result_threat_type;
+
+    // The SafeBrowsing lists to check hash prefixes in.
+    StoresToCheck stores_to_check;
+
+    // The URL that is being checked for being unsafe.
+    GURL url;
+
+    // The metadata associated with the full hash of the severest match found
+    // for that URL.
+    ThreatMetadata url_metadata;
+  };
+
+  typedef std::vector<std::unique_ptr<PendingCheck>> QueuedChecks;
+
+  // The stores/lists to always get full hashes for, regardless of which store
+  // the hash prefix matched.
+  StoresToCheck GetStoresForFullHashRequests() override;
 
  private:
   friend class V4LocalDatabaseManagerTest;
@@ -128,6 +135,12 @@
   // Called when the database has been updated and schedules the next update.
   void DatabaseUpdated();
 
+  // Return the prefixes and the store they matched in, for a given URL. Returns
+  // true if a hash prefix match is found; false otherwise.
+  bool GetPrefixMatches(
+      const std::unique_ptr<PendingCheck>& check,
+      FullHashToStoreAndHashPrefixesMap* full_hash_to_store_and_hash_prefixes);
+
   // Finds the most severe |SBThreatType| and the corresponding |metadata| from
   // |full_hash_infos|.
   void GetSeverestThreatTypeAndMetadata(
@@ -144,6 +157,19 @@
   void OnFullHashResponse(std::unique_ptr<PendingCheck> pending_check,
                           const std::vector<FullHashInfo>& full_hash_infos);
 
+  // Performs the full hash checking of the URL in |check|.
+  void PerformFullHashCheck(std::unique_ptr<PendingCheck> check,
+                            const FullHashToStoreAndHashPrefixesMap&
+                                full_hash_to_store_and_hash_prefixes);
+
+  // When the database is ready to use, process the checks that were queued
+  // while the database was loading from disk.
+  void ProcessQueuedChecks();
+
+  // Called on StopOnIOThread, it responds to the clients that are waiting for
+  // the database to become available with the verdict as SAFE.
+  void RespondSafeToQueuedChecks();
+
   // Calls the appopriate method on the |client| object, based on the contents
   // of |pending_check|.
   void RespondToClient(std::unique_ptr<PendingCheck> pending_check);
@@ -182,6 +208,10 @@
   // SafeBrowsing service.
   PendingClients pending_clients_;
 
+  // The checks that need to be scheduled when the database becomes ready for
+  // use.
+  QueuedChecks queued_checks_;
+
   // The sequenced task runner for running safe browsing database operations.
   scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
diff --git a/components/safe_browsing_db/v4_local_database_manager_unittest.cc b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
index 580ed74..d3e75cb 100644
--- a/components/safe_browsing_db/v4_local_database_manager_unittest.cc
+++ b/components/safe_browsing_db/v4_local_database_manager_unittest.cc
@@ -25,7 +25,7 @@
 
   void GetStoresMatchingFullHash(
       const FullHash& full_hash,
-      const std::unordered_set<ListIdentifier>& stores_to_look,
+      const StoresToCheck& stores_to_check,
       StoreAndHashPrefixes* store_and_hash_prefixes) override {
     *store_and_hash_prefixes = store_and_hash_prefixes_;
   }
@@ -34,6 +34,22 @@
   const StoreAndHashPrefixes& store_and_hash_prefixes_;
 };
 
+class TestClient : public SafeBrowsingDatabaseManager::Client {
+ public:
+  TestClient(SBThreatType sb_threat_type, const GURL& url)
+      : expected_sb_threat_type(sb_threat_type), expected_url(url) {}
+
+  void OnCheckBrowseUrlResult(const GURL& url,
+                              SBThreatType threat_type,
+                              const ThreatMetadata& metadata) override {
+    DCHECK_EQ(expected_url, url);
+    DCHECK_EQ(expected_sb_threat_type, threat_type);
+  }
+
+  SBThreatType expected_sb_threat_type;
+  GURL expected_url;
+};
+
 class V4LocalDatabaseManagerTest : public PlatformTest {
  public:
   V4LocalDatabaseManagerTest() : task_runner_(new base::TestSimpleTaskRunner) {}
@@ -48,15 +64,11 @@
         make_scoped_refptr(new V4LocalDatabaseManager(base_dir_.GetPath()));
     v4_local_database_manager_->SetTaskRunnerForTest(task_runner_);
 
-    SetupLocalDatabaseManager();
+    StartLocalDatabaseManager();
   }
 
   void TearDown() override {
-    v4_local_database_manager_->StopOnIOThread(true);
-
-    // Force destruction of the database.
-    task_runner_->RunPendingTasks();
-    base::RunLoop().RunUntilIdle();
+    StopLocalDatabaseManager();
 
     PlatformTest::TearDown();
   }
@@ -65,18 +77,32 @@
     v4_local_database_manager_->enabled_ = false;
   }
 
+  const V4LocalDatabaseManager::QueuedChecks& GetQueuedChecks() {
+    return v4_local_database_manager_->queued_checks_;
+  }
+
   void ReplaceV4Database(const StoreAndHashPrefixes& store_and_hash_prefixes) {
     v4_local_database_manager_->v4_database_.reset(new FakeV4Database(
         task_runner_, base::MakeUnique<StoreMap>(), store_and_hash_prefixes));
   }
 
-  void SetupLocalDatabaseManager() {
+  void ResetV4Database() { v4_local_database_manager_->v4_database_.reset(); }
+
+  void StartLocalDatabaseManager() {
     v4_local_database_manager_->StartOnIOThread(NULL, V4ProtocolConfig());
 
     task_runner_->RunPendingTasks();
     base::RunLoop().RunUntilIdle();
   }
 
+  void StopLocalDatabaseManager() {
+    v4_local_database_manager_->StopOnIOThread(true);
+
+    // Force destruction of the database.
+    task_runner_->RunPendingTasks();
+    base::RunLoop().RunUntilIdle();
+  }
+
   base::ScopedTempDir base_dir_;
   scoped_refptr<base::TestSimpleTaskRunner> task_runner_;
   content::TestBrowserThreadBundle thread_bundle_;
@@ -162,4 +188,31 @@
   EXPECT_EQ("malware_popid", metadata.population_id);
 }
 
+TEST_F(V4LocalDatabaseManagerTest, TestChecksAreQueued) {
+  const GURL url("https://www.example.com/");
+  TestClient client(SB_THREAT_TYPE_SAFE, url);
+  EXPECT_TRUE(GetQueuedChecks().empty());
+  v4_local_database_manager_->CheckBrowseUrl(url, &client);
+  // The database is available so the check shouldn't get queued.
+  EXPECT_TRUE(GetQueuedChecks().empty());
+
+  ResetV4Database();
+  v4_local_database_manager_->CheckBrowseUrl(url, &client);
+  // The database is unavailable so the check should get queued.
+  EXPECT_EQ(1ul, GetQueuedChecks().size());
+
+  // The following function calls StartOnIOThread which should load the
+  // database from disk and cause the queued check to be performed.
+  StartLocalDatabaseManager();
+  EXPECT_TRUE(GetQueuedChecks().empty());
+
+  ResetV4Database();
+  v4_local_database_manager_->CheckBrowseUrl(url, &client);
+  // The database is unavailable so the check should get queued.
+  EXPECT_EQ(1ul, GetQueuedChecks().size());
+
+  StopLocalDatabaseManager();
+  EXPECT_TRUE(GetQueuedChecks().empty());
+}
+
 }  // namespace safe_browsing
diff --git a/components/safe_browsing_db/v4_protocol_manager_util.h b/components/safe_browsing_db/v4_protocol_manager_util.h
index 9ca00849..34e2412 100644
--- a/components/safe_browsing_db/v4_protocol_manager_util.h
+++ b/components/safe_browsing_db/v4_protocol_manager_util.h
@@ -297,6 +297,8 @@
   DISALLOW_COPY_AND_ASSIGN(V4ProtocolManagerUtil);
 };
 
+typedef std::unordered_set<ListIdentifier> StoresToCheck;
+
 }  // namespace safe_browsing
 
 namespace std {
diff --git a/components/sync/BUILD.gn b/components/sync/BUILD.gn
index 9569724..1ebece93 100644
--- a/components/sync/BUILD.gn
+++ b/components/sync/BUILD.gn
@@ -29,6 +29,7 @@
     "api/entity_change.h",
     "api/entity_data.cc",
     "api/entity_data.h",
+    "api/local_change_observer.h",
     "api/metadata_batch.cc",
     "api/metadata_batch.h",
     "api/metadata_change_list.h",
diff --git a/components/sync/api/fake_sync_change_processor.cc b/components/sync/api/fake_sync_change_processor.cc
index 0060cf0..a675151 100644
--- a/components/sync/api/fake_sync_change_processor.cc
+++ b/components/sync/api/fake_sync_change_processor.cc
@@ -33,6 +33,12 @@
   return syncer::SyncError();
 }
 
+void FakeSyncChangeProcessor::AddLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {}
+
+void FakeSyncChangeProcessor::RemoveLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {}
+
 const syncer::SyncChangeList& FakeSyncChangeProcessor::changes() const {
   return changes_;
 }
diff --git a/components/sync/api/fake_sync_change_processor.h b/components/sync/api/fake_sync_change_processor.h
index d599f55e..1498b2d 100644
--- a/components/sync/api/fake_sync_change_processor.h
+++ b/components/sync/api/fake_sync_change_processor.h
@@ -36,6 +36,9 @@
   syncer::SyncError UpdateDataTypeContext(ModelType type,
                                           ContextRefreshStatus refresh_status,
                                           const std::string& context) override;
+  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override;
+  void RemoveLocalChangeObserver(
+      syncer::LocalChangeObserver* observer) override;
 
   virtual const syncer::SyncChangeList& changes() const;
   virtual syncer::SyncChangeList& changes();
diff --git a/components/sync/api/local_change_observer.h b/components/sync/api/local_change_observer.h
new file mode 100644
index 0000000..1c9f7d2
--- /dev/null
+++ b/components/sync/api/local_change_observer.h
@@ -0,0 +1,32 @@
+// Copyright 2016 The Chromium 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_SYNC_API_LOCAL_CHANGE_OBSERVER_H_
+#define COMPONENTS_SYNC_API_LOCAL_CHANGE_OBSERVER_H_
+
+namespace syncer {
+
+class SyncChange;
+namespace syncable {
+class Entry;
+}  // namespace syncable
+
+// Interface for observers that want to be notified of local sync changes.
+// The OnLocalChange function will be called when a local change made through
+// ProcessSyncChanges is about to be applied to the directory. This is useful
+// for inspecting the specifics of sync data being written locally and comparing
+// it against the current state of the directory. Registering a local change
+// observer is done by calling the AddLocalChangeObserver function on an
+// instance of SyncChangeProcessor.
+class LocalChangeObserver {
+ public:
+  virtual ~LocalChangeObserver() {}
+  // Function called to notify observer of the local change. current_entry
+  // should reflect the state of the entry *before* change is applied.
+  virtual void OnLocalChange(const syncable::Entry* current_entry,
+                             const SyncChange& change) = 0;
+};
+}  // namespace syncer
+
+#endif  // COMPONENTS_SYNC_API_LOCAL_CHANGE_OBSERVER_H_
diff --git a/components/sync/api/sync_change_processor.cc b/components/sync/api/sync_change_processor.cc
index f954a6ac..3a0b6a0 100644
--- a/components/sync/api/sync_change_processor.cc
+++ b/components/sync/api/sync_change_processor.cc
@@ -18,4 +18,14 @@
   return syncer::SyncError();
 }
 
+void SyncChangeProcessor::AddLocalChangeObserver(
+    LocalChangeObserver* observer) {
+  NOTREACHED();
+}
+
+void SyncChangeProcessor::RemoveLocalChangeObserver(
+    LocalChangeObserver* observer) {
+  NOTREACHED();
+}
+
 }  // namespace syncer
diff --git a/components/sync/api/sync_change_processor.h b/components/sync/api/sync_change_processor.h
index d5884a2..2d31b8a9 100644
--- a/components/sync/api/sync_change_processor.h
+++ b/components/sync/api/sync_change_processor.h
@@ -20,6 +20,8 @@
 
 class SyncChange;
 
+class LocalChangeObserver;
+
 typedef std::vector<SyncChange> SyncChangeList;
 
 // An interface for services that handle receiving SyncChanges.
@@ -75,6 +77,12 @@
       ModelType type,
       ContextRefreshStatus refresh_status,
       const std::string& context);
+
+  // Adds an observer of local sync changes. This observer is notified when
+  // local sync changes are applied by GenericChangeProcessor. observer is
+  // not owned by the SyncChangeProcessor.
+  virtual void AddLocalChangeObserver(LocalChangeObserver* observer);
+  virtual void RemoveLocalChangeObserver(LocalChangeObserver* observer);
 };
 
 }  // namespace syncer
diff --git a/components/sync/driver/generic_change_processor.cc b/components/sync/driver/generic_change_processor.cc
index a54a6a75..0042c16 100644
--- a/components/sync/driver/generic_change_processor.cc
+++ b/components/sync/driver/generic_change_processor.cc
@@ -15,6 +15,7 @@
 #include "base/strings/utf_string_conversions.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "components/sync/api/data_type_error_handler.h"
+#include "components/sync/api/local_change_observer.h"
 #include "components/sync/api/sync_change.h"
 #include "components/sync/api/sync_error.h"
 #include "components/sync/api/syncable_service.h"
@@ -244,6 +245,16 @@
   return syncer::SyncError();
 }
 
+void GenericChangeProcessor::AddLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  local_change_observers_.AddObserver(observer);
+}
+
+void GenericChangeProcessor::RemoveLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  local_change_observers_.RemoveObserver(observer);
+}
+
 void GenericChangeProcessor::OnAttachmentUploaded(
     const syncer::AttachmentId& attachment_id) {
   syncer::WriteTransaction trans(FROM_HERE, share_handle());
@@ -366,11 +377,14 @@
   }
 }
 
-syncer::SyncError AttemptDelete(const syncer::SyncChange& change,
-                                syncer::ModelType type,
-                                const std::string& type_str,
-                                syncer::WriteNode* node,
-                                syncer::DataTypeErrorHandler* error_handler) {
+}  // namespace
+
+syncer::SyncError GenericChangeProcessor::AttemptDelete(
+    const syncer::SyncChange& change,
+    syncer::ModelType type,
+    const std::string& type_str,
+    syncer::WriteNode* node,
+    syncer::DataTypeErrorHandler* error_handler) {
   DCHECK_EQ(change.change_type(), syncer::SyncChange::ACTION_DELETE);
   if (change.sync_data().IsLocal()) {
     const std::string& tag = syncer::SyncDataLocal(change.sync_data()).GetTag();
@@ -405,6 +419,7 @@
                               type, error_handler);
     }
   }
+  NotifyLocalChangeObservers(node->GetEntry(), change);
   if (IsActOnceDataType(type))
     node->Drop();
   else
@@ -412,8 +427,6 @@
   return syncer::SyncError();
 }
 
-}  // namespace
-
 syncer::SyncError GenericChangeProcessor::ProcessSyncChanges(
     const tracked_objects::Location& from_here,
     const syncer::SyncChangeList& list_of_changes) {
@@ -553,6 +566,8 @@
       }
     }
   }
+  NotifyLocalChangeObservers(sync_node->GetEntry(), change);
+
   sync_node->SetTitle(change.sync_data().GetTitle());
   SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
 
@@ -617,6 +632,8 @@
     }
   }
 
+  NotifyLocalChangeObservers(sync_node->GetEntry(), change);
+
   sync_node->SetTitle(change.sync_data().GetTitle());
   SetNodeSpecifics(sync_data_local.GetSpecifics(), sync_node);
   syncer::AttachmentIdList attachment_ids = sync_data_local.GetAttachmentIds();
@@ -683,6 +700,13 @@
   }
 }
 
+void GenericChangeProcessor::NotifyLocalChangeObservers(
+    const syncer::syncable::Entry* current_entry,
+    const syncer::SyncChange& change) {
+  FOR_EACH_OBSERVER(syncer::LocalChangeObserver, local_change_observers_,
+                    OnLocalChange(current_entry, change));
+}
+
 std::unique_ptr<syncer::AttachmentService>
 GenericChangeProcessor::GetAttachmentService() const {
   return std::unique_ptr<syncer::AttachmentService>(
diff --git a/components/sync/driver/generic_change_processor.h b/components/sync/driver/generic_change_processor.h
index 36c08aa2..18ba548 100644
--- a/components/sync/driver/generic_change_processor.h
+++ b/components/sync/driver/generic_change_processor.h
@@ -30,6 +30,10 @@
 class WriteTransaction;
 
 typedef std::vector<syncer::SyncData> SyncDataList;
+
+namespace syncable {
+class Entry;
+}  // namespace syncable
 }  // namespace syncer
 
 namespace sync_driver {
@@ -82,6 +86,9 @@
       syncer::ModelType type,
       syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
       const std::string& context) override;
+  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override;
+  void RemoveLocalChangeObserver(
+      syncer::LocalChangeObserver* observer) override;
 
   // syncer::AttachmentService::Delegate implementation.
   void OnAttachmentUploaded(const syncer::AttachmentId& attachment_id) override;
@@ -113,6 +120,11 @@
   syncer::UserShare* share_handle() const override;
 
  private:
+  syncer::SyncError AttemptDelete(const syncer::SyncChange& change,
+                                  syncer::ModelType type,
+                                  const std::string& type_str,
+                                  syncer::WriteNode* node,
+                                  syncer::DataTypeErrorHandler* error_handler);
   // Logically part of ProcessSyncChanges.
   //
   // |new_attachments| is an output parameter containing newly added attachments
@@ -138,6 +150,11 @@
   // server.
   void UploadAllAttachmentsNotOnServer();
 
+  // Notify every registered local change observer that |change| is about to be
+  // applied to |current_entry|.
+  void NotifyLocalChangeObservers(const syncer::syncable::Entry* current_entry,
+                                  const syncer::SyncChange& change);
+
   const syncer::ModelType type_;
 
   // The SyncableService this change processor will forward changes on to.
@@ -166,6 +183,9 @@
   // attachments.
   std::unique_ptr<syncer::AttachmentService> attachment_service_;
 
+  // List of observers that want to be notified of local changes being written.
+  base::ObserverList<syncer::LocalChangeObserver> local_change_observers_;
+
   // Must be destroyed before attachment_service_ to ensure WeakPtrs are
   // invalidated before attachment_service_ is destroyed.
   // Can be NULL if attachment_service_ is NULL;
diff --git a/components/sync/driver/shared_change_processor.cc b/components/sync/driver/shared_change_processor.cc
index 60f010a..fc8eea8 100644
--- a/components/sync/driver/shared_change_processor.cc
+++ b/components/sync/driver/shared_change_processor.cc
@@ -21,7 +21,7 @@
 
 namespace syncer {
 class AttachmentService;
-}
+}  // namespace syncer
 
 namespace sync_driver {
 
@@ -259,6 +259,22 @@
                                                           context);
 }
 
+void SharedChangeProcessor::AddLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  DCHECK(backend_task_runner_.get());
+  DCHECK(backend_task_runner_->BelongsToCurrentThread());
+
+  generic_change_processor_->AddLocalChangeObserver(observer);
+}
+
+void SharedChangeProcessor::RemoveLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  DCHECK(backend_task_runner_.get());
+  DCHECK(backend_task_runner_->BelongsToCurrentThread());
+
+  generic_change_processor_->RemoveLocalChangeObserver(observer);
+}
+
 bool SharedChangeProcessor::SyncModelHasUserCreatedNodes(bool* has_nodes) {
   DCHECK(backend_task_runner_.get());
   DCHECK(backend_task_runner_->BelongsToCurrentThread());
diff --git a/components/sync/driver/shared_change_processor.h b/components/sync/driver/shared_change_processor.h
index 0edc3ac..5488ac3f 100644
--- a/components/sync/driver/shared_change_processor.h
+++ b/components/sync/driver/shared_change_processor.h
@@ -106,6 +106,8 @@
       syncer::ModelType type,
       syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
       const std::string& context);
+  virtual void AddLocalChangeObserver(syncer::LocalChangeObserver* observer);
+  virtual void RemoveLocalChangeObserver(syncer::LocalChangeObserver* observer);
   virtual bool SyncModelHasUserCreatedNodes(bool* has_nodes);
   virtual bool CryptoReadyIfNecessary();
 
diff --git a/components/sync/driver/shared_change_processor_ref.cc b/components/sync/driver/shared_change_processor_ref.cc
index 49df65eb..a989e1c2 100644
--- a/components/sync/driver/shared_change_processor_ref.cc
+++ b/components/sync/driver/shared_change_processor_ref.cc
@@ -33,6 +33,16 @@
                                                   context);
 }
 
+void SharedChangeProcessorRef::AddLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  change_processor_->AddLocalChangeObserver(observer);
+}
+
+void SharedChangeProcessorRef::RemoveLocalChangeObserver(
+    syncer::LocalChangeObserver* observer) {
+  change_processor_->RemoveLocalChangeObserver(observer);
+}
+
 syncer::SyncError SharedChangeProcessorRef::CreateAndUploadError(
     const tracked_objects::Location& from_here,
     const std::string& message) {
diff --git a/components/sync/driver/shared_change_processor_ref.h b/components/sync/driver/shared_change_processor_ref.h
index c0167b2..a8a9b9b 100644
--- a/components/sync/driver/shared_change_processor_ref.h
+++ b/components/sync/driver/shared_change_processor_ref.h
@@ -33,6 +33,9 @@
       syncer::ModelType type,
       syncer::SyncChangeProcessor::ContextRefreshStatus refresh_status,
       const std::string& context) override;
+  void AddLocalChangeObserver(syncer::LocalChangeObserver* observer) override;
+  void RemoveLocalChangeObserver(
+      syncer::LocalChangeObserver* observer) override;
 
   // syncer::SyncErrorFactory implementation.
   syncer::SyncError CreateAndUploadError(
diff --git a/components/sync_sessions/BUILD.gn b/components/sync_sessions/BUILD.gn
index b7ef585..1515037 100644
--- a/components/sync_sessions/BUILD.gn
+++ b/components/sync_sessions/BUILD.gn
@@ -7,6 +7,8 @@
     "favicon_cache.cc",
     "favicon_cache.h",
     "local_session_event_router.h",
+    "lost_navigations_recorder.cc",
+    "lost_navigations_recorder.h",
     "open_tabs_ui_delegate.cc",
     "open_tabs_ui_delegate.h",
     "revisit/bookmarks_by_url_provider_impl.cc",
@@ -90,6 +92,7 @@
   testonly = true
   sources = [
     "favicon_cache_unittest.cc",
+    "lost_navigations_recorder_unittest.cc",
     "revisit/bookmarks_page_revisit_observer_unittest.cc",
     "revisit/current_tab_matcher_unittest.cc",
     "revisit/offset_tab_matcher_unittest.cc",
@@ -112,6 +115,7 @@
     "//components/sessions:test_support",
     "//components/sync",
     "//components/sync:test_support_sync_api",
+    "//components/sync:test_support_sync_core",
     "//components/sync:test_support_sync_driver",
     "//testing/gmock",
     "//testing/gtest",
diff --git a/components/sync_sessions/lost_navigations_recorder.cc b/components/sync_sessions/lost_navigations_recorder.cc
new file mode 100644
index 0000000..5f9b1f9
--- /dev/null
+++ b/components/sync_sessions/lost_navigations_recorder.cc
@@ -0,0 +1,136 @@
+// Copyright 2016 The Chromium 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/metrics/histogram_macros.h"
+#include "base/stl_util.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/syncable/entry.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
+
+namespace sync_sessions {
+
+LostNavigationsRecorder::LostNavigationsRecorder()
+    : recorder_state_(RECORDER_STATE_NOT_SYNCING) {}
+
+LostNavigationsRecorder::~LostNavigationsRecorder() {}
+
+void LostNavigationsRecorder::OnLocalChange(
+    const syncer::syncable::Entry* current_entry,
+    const syncer::SyncChange& change) {
+  if (change.sync_data().GetSpecifics().session().has_tab()) {
+    TransitionState(current_entry->GetSyncing(),
+                    current_entry->GetIsUnsynced());
+  }
+  RecordChange(change);
+}
+
+// Record a change either by adjusting our list of tabs or by recording the set
+// of navigations in the updated tab.
+void LostNavigationsRecorder::RecordChange(const syncer::SyncChange& change) {
+  sync_pb::SessionSpecifics session_specifics =
+      change.sync_data().GetSpecifics().session();
+  if (session_specifics.has_header()) {
+    DeleteTabs(session_specifics.header());
+    return;
+  } else if (!session_specifics.has_tab()) {
+    // There isn't any data we care about if neither a tab or window is
+    // modified.
+    return;
+  }
+  sync_pb::SessionTab tab = session_specifics.tab();
+  id_type tab_id = tab.tab_id();
+
+  IdSet& latest = latest_navigation_ids_[tab_id];
+  latest.clear();
+
+  for (sync_pb::TabNavigation nav : tab.navigation()) {
+    id_type uid = nav.unique_id();
+    // Only record an id if it's "new" i.e. larger than the largest seen for
+    // that tab. If the id is smaller than this, it's not new; ids are generated
+    // in increasing order.
+    if (uid > max_recorded_for_tab_[tab_id]) {
+      recorded_navigation_ids_[tab_id].insert(uid);
+      max_recorded_for_tab_[tab_id] = uid;
+    }
+    latest.insert(nav.unique_id());
+  }
+}
+
+void LostNavigationsRecorder::DeleteTabs(const sync_pb::SessionHeader& header) {
+  IdSet new_tab_ids;
+  IdSet current_tab_ids;
+  // Find the set of tab ids that are still there after the deletion.
+  for (sync_pb::SessionWindow window : header.window()) {
+    for (id_type tab_id : window.tab()) {
+      new_tab_ids.insert(tab_id);
+    }
+  }
+  for (auto pair : recorded_navigation_ids_) {
+    current_tab_ids.insert(pair.first);
+  }
+  // The set of deleted tabs is the difference between the set of tabs before
+  // the pending change and the set of tabs following the pending change.
+  IdSet deleted_tabs =
+      base::STLSetDifference<IdSet>(current_tab_ids, new_tab_ids);
+  for (id_type tab_id : deleted_tabs) {
+    recorded_navigation_ids_.erase(tab_id);
+    latest_navigation_ids_.erase(tab_id);
+    max_recorded_for_tab_.erase(tab_id);
+  }
+}
+
+// Change the current state of the recorder, possibly triggering reconciliation,
+// based on the status of the directory entry. Reconciliation triggers on the
+// observation of two conditions.
+// 1) The entry transitioning into the syncing state
+// 2) If we miss the transition to syncing state, the entry transitioning into
+// the synced state.
+void LostNavigationsRecorder::TransitionState(bool is_syncing,
+                                              bool is_unsynced) {
+  switch (recorder_state_) {
+    case RECORDER_STATE_NOT_SYNCING:
+      // If a sync cycle is happening or already finished, reconcile.
+      // It's possible that this will trigger reconciliation multiple times per
+      // sync cycle; once per tab that finishes the cycle in the synced state
+      // and the user performs a navigation in. In theory this will cause
+      // under-counting, since reconciliation clears each tab's remembered set
+      // of navigations. In practice the number of unique tabs written to in
+      // between two adjacent sync cycles should be pretty low,
+      // making the undercounting tolerable.
+      if (is_syncing || !is_unsynced) {
+        ReconcileLostNavs();
+      }
+      // If we're currently in a sync cycle, remember that.
+      if (is_syncing) {
+        recorder_state_ = RECORDER_STATE_SYNCING;
+      }
+      break;
+    case RECORDER_STATE_SYNCING:
+      if (!is_syncing) {
+        recorder_state_ = RECORDER_STATE_NOT_SYNCING;
+      }
+      break;
+  }
+}
+
+// Reconcile the number of "lost" navigations by checking all the unique ids we
+// recorded against what was actually synced.
+void LostNavigationsRecorder::ReconcileLostNavs() {
+  for (auto pair : recorded_navigation_ids_) {
+    id_type tab_id = pair.first;
+    IdSet& latest = latest_navigation_ids_[tab_id];
+    IdSet& recorded = recorded_navigation_ids_[tab_id];
+    if (recorded.size() < 1) {
+      continue;
+    }
+
+    // The set of lost navigations is anything we recorded as new that's not
+    // present in latest.
+    IdSet lost_navs = base::STLSetDifference<IdSet>(recorded, latest);
+    int quantity_lost = lost_navs.size();
+    UMA_HISTOGRAM_COUNTS("Sync.LostNavigationCount", quantity_lost);
+    recorded.clear();
+  }
+}
+}  // namespace sync_sessions
diff --git a/components/sync_sessions/lost_navigations_recorder.h b/components/sync_sessions/lost_navigations_recorder.h
new file mode 100644
index 0000000..10b264f
--- /dev/null
+++ b/components/sync_sessions/lost_navigations_recorder.h
@@ -0,0 +1,55 @@
+// Copyright 2016 The Chromium 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_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
+#define COMPONENTS_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
+
+#include "base/macros.h"
+#include "components/sessions/core/session_id.h"
+#include "components/sync/api/local_change_observer.h"
+#include "components/sync/api/sync_change.h"
+#include "components/sync/protocol/session_specifics.pb.h"
+
+namespace sync_sessions {
+
+// Recorder class that tracks the number of navigations written locally that
+// aren't synced. This is done by recording set of locally observed navigations
+// and  reconciling these sets against what was ultimately synced. These
+// navigations ultimately feed chrome history, so losing them prevents them from
+// being reflected in the history page.
+class LostNavigationsRecorder : public syncer::LocalChangeObserver {
+ public:
+  typedef SessionID::id_type id_type;
+  typedef std::set<id_type> IdSet;
+  enum RecorderState { RECORDER_STATE_NOT_SYNCING, RECORDER_STATE_SYNCING };
+
+  LostNavigationsRecorder();
+  ~LostNavigationsRecorder() override;
+
+  // syncer::LocalChangeObserver implementation.
+  void OnLocalChange(const syncer::syncable::Entry* current_entry,
+                     const syncer::SyncChange& change) override;
+
+ private:
+  void RecordChange(const syncer::SyncChange& change);
+  void DeleteTabs(const sync_pb::SessionHeader& header);
+  void TransitionState(bool is_syncing, bool is_unsynced);
+  void ReconcileLostNavs();
+
+  // State that records whether the most recently observed directory state was
+  // syncing or not syncing.
+  RecorderState recorder_state_;
+
+  // The set of all navigation ids we've observed for each tab_id since the last
+  // sync.
+  std::map<id_type, IdSet> recorded_navigation_ids_;
+  // The set of navigation ids most recently recorded for each tab_id.
+  std::map<id_type, IdSet> latest_navigation_ids_;
+  // The maximum navigation_id recorded for each tab_id.
+  std::map<id_type, id_type> max_recorded_for_tab_;
+  DISALLOW_COPY_AND_ASSIGN(LostNavigationsRecorder);
+};
+};  // namespace sync_sessions
+
+#endif  // COMPONENTS_SYNC_SESSIONS_LOST_NAVIGATIONS_RECORDER_H_
diff --git a/components/sync_sessions/lost_navigations_recorder_unittest.cc b/components/sync_sessions/lost_navigations_recorder_unittest.cc
new file mode 100644
index 0000000..bffb921
--- /dev/null
+++ b/components/sync_sessions/lost_navigations_recorder_unittest.cc
@@ -0,0 +1,398 @@
+// Copyright 2016 The Chromium 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 <memory>
+
+#include "base/message_loop/message_loop.h"
+#include "base/test/histogram_tester.h"
+#include "components/sessions/core/session_id.h"
+#include "components/sync/core/attachments/attachment_service_proxy_for_test.h"
+#include "components/sync/syncable/entry.h"
+#include "components/sync/syncable/mutable_entry.h"
+#include "components/sync/syncable/syncable_base_transaction.h"
+#include "components/sync/syncable/syncable_read_transaction.h"
+#include "components/sync/syncable/syncable_write_transaction.h"
+#include "components/sync/test/engine/test_directory_setter_upper.h"
+#include "components/sync/test/engine/test_id_factory.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
+#include "components/sync_sessions/sessions_sync_manager.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using syncer::syncable::Entry;
+using syncer::syncable::Id;
+using syncer::syncable::MutableEntry;
+using syncer::syncable::WriteTransaction;
+
+namespace sync_sessions {
+namespace {
+typedef SessionID::id_type id_type;
+
+const char kTab1SyncTag[] = "tab-YWRkcjHvv74=";
+const char kTab2SyncTag[] = "tab-2FyZDHvv74=";
+
+class LostNavigationsRecorderTest : public testing::Test {
+ protected:
+  void SetUp() override {
+    dir_maker_.SetUp();
+    _id = 1;
+  }
+
+  void TearDown() override { dir_maker_.TearDown(); }
+
+  syncer::syncable::Directory* directory() { return dir_maker_.directory(); }
+
+  LostNavigationsRecorder* recorder() { return &recorder_; }
+
+  void AddNavigation(sync_pb::SessionSpecifics* tab_base,
+                     id_type id_override = -1) {
+    sync_pb::SessionTab* tab = tab_base->mutable_tab();
+    sync_pb::TabNavigation* navigation = tab->add_navigation();
+    navigation->set_page_transition(sync_pb::SyncEnums_PageTransition_TYPED);
+    navigation->set_unique_id(id_override > 0 ? id_override : _id++);
+  }
+
+  void BuildTabSpecifics(const std::string& tag,
+                         int tab_id,
+                         sync_pb::SessionSpecifics* tab_base,
+                         int num_unique_navs = 1) {
+    tab_base->set_session_tag(tag);
+    tab_base->set_tab_node_id(0);
+    sync_pb::SessionTab* tab = tab_base->mutable_tab();
+    tab->set_tab_id(tab_id);
+    tab->set_current_navigation_index(0);
+    for (int i = 0; i < num_unique_navs; ++i) {
+      AddNavigation(tab_base);
+    }
+  }
+
+  void BuildWindowSpecifics(int window_id,
+                            sync_pb::SessionSpecifics* window_base) {
+    sync_pb::SessionHeader* header = window_base->mutable_header();
+    sync_pb::SessionWindow* window = header->add_window();
+    window->set_window_id(window_id);
+  }
+
+  const Id& CreateEntry() {
+    WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+    MutableEntry mutable_entry(&wtrans, syncer::syncable::CREATE,
+                               syncer::SESSIONS, wtrans.root_id(),
+                               "entrynamutable_entry");
+    EXPECT_TRUE(mutable_entry.good());
+    return mutable_entry.GetId();
+  }
+
+  const syncer::SyncData CreateLocalData(
+      const sync_pb::SessionSpecifics& specifics,
+      const std::string& sync_tag) const {
+    sync_pb::EntitySpecifics entity;
+    entity.mutable_session()->CopyFrom(specifics);
+    return syncer::SyncData::CreateLocalData(sync_tag, sync_tag, entity);
+  }
+
+  syncer::SyncChange MakeChange(const std::string& sync_tag,
+                                const sync_pb::SessionSpecifics& specifics,
+                                syncer::SyncChange::SyncChangeType type) const {
+    return syncer::SyncChange(FROM_HERE, type,
+                              CreateLocalData(specifics, sync_tag));
+  }
+
+  void RecordChange(const Entry* entry, int num_unique_navs) {
+    sync_pb::EntitySpecifics specifics;
+    BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(),
+                      num_unique_navs);
+    RecordChange(entry, specifics);
+  }
+
+  void RecordChange(const Entry* entry, sync_pb::EntitySpecifics specifics) {
+    syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+                                           syncer::SyncChange::ACTION_UPDATE);
+    recorder()->OnLocalChange(entry, change);
+  }
+
+  void TriggerReconcile(MutableEntry* mutable_entry,
+                        bool trigger_by_syncing = true,
+                        sync_pb::EntitySpecifics* specifics = nullptr) {
+    mutable_entry->PutSyncing(trigger_by_syncing);
+    mutable_entry->PutIsUnsynced(trigger_by_syncing);
+    if (specifics == nullptr) {
+      RecordChange(mutable_entry, 0);
+    } else {
+      RecordChange(mutable_entry, *specifics);
+    }
+  }
+
+ private:
+  base::MessageLoop message_loop;
+  id_type _id;
+  LostNavigationsRecorder recorder_;
+  syncer::TestDirectorySetterUpper dir_maker_;
+};
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsNoneLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  RecordChange(&mutable_entry, 6);
+
+  TriggerReconcile(&mutable_entry);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsOneLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  RecordChange(&mutable_entry, 1);
+  RecordChange(&mutable_entry, 1);
+
+  TriggerReconcile(&mutable_entry);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 1, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsMultipleLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  RecordChange(&mutable_entry, 5);
+  RecordChange(&mutable_entry, 1);
+
+  TriggerReconcile(&mutable_entry);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 5, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesWhileSyncing) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  mutable_entry.PutIsUnsynced(true);
+  RecordChange(&mutable_entry, specifics);
+
+  mutable_entry.PutSyncing(true);
+  RecordChange(&mutable_entry, specifics);
+
+  specifics.mutable_session()->mutable_tab()->clear_navigation();
+  for (int i = 0; i < 5; i++) {
+    AddNavigation(specifics.mutable_session());
+    RecordChange(&mutable_entry, specifics);
+  }
+
+  TriggerReconcile(&mutable_entry, false);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesMultipleEntriesNoneLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  const Id& id2 = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+  mutable_entry.PutIsUnsynced(true);
+  mutable_entry2.PutIsUnsynced(true);
+
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::EntitySpecifics specifics2;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  BuildTabSpecifics(kTab2SyncTag, 2, specifics2.mutable_session(), 5);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry2, specifics2);
+
+  mutable_entry.PutSyncing(true);
+  mutable_entry2.PutSyncing(true);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry2, specifics2);
+
+  specifics.mutable_session()->mutable_tab()->clear_navigation();
+  specifics2.mutable_session()->mutable_tab()->clear_navigation();
+  for (int i = 0; i < 5; i++) {
+    AddNavigation(specifics.mutable_session());
+    AddNavigation(specifics2.mutable_session());
+
+    RecordChange(&mutable_entry, specifics);
+    RecordChange(&mutable_entry2, specifics2);
+  }
+
+  TriggerReconcile(&mutable_entry, false, &specifics);
+  TriggerReconcile(&mutable_entry2, false, &specifics2);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 4);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleWritesMultipleEntriesMultipleLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  const Id& id2 = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+  mutable_entry.PutIsUnsynced(true);
+  mutable_entry2.PutIsUnsynced(true);
+
+  sync_pb::EntitySpecifics specifics;
+  sync_pb::EntitySpecifics specifics2;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  BuildTabSpecifics(kTab2SyncTag, 2, specifics2.mutable_session(), 5);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry2, specifics2);
+
+  mutable_entry.PutSyncing(true);
+  mutable_entry2.PutSyncing(true);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry2, specifics2);
+
+  specifics.mutable_session()->mutable_tab()->clear_navigation();
+  specifics2.mutable_session()->mutable_tab()->clear_navigation();
+  for (int i = 0; i < 5; i++) {
+    AddNavigation(specifics.mutable_session());
+    AddNavigation(specifics2.mutable_session());
+
+    RecordChange(&mutable_entry, specifics);
+    RecordChange(&mutable_entry2, specifics2);
+  }
+
+  specifics.mutable_session()
+      ->mutable_tab()
+      ->mutable_navigation()
+      ->DeleteSubrange(0, 2);
+  specifics2.mutable_session()
+      ->mutable_tab()
+      ->mutable_navigation()
+      ->DeleteSubrange(0, 2);
+  RecordChange(&mutable_entry, specifics);
+  RecordChange(&mutable_entry, specifics2);
+
+  TriggerReconcile(&mutable_entry, false, &specifics);
+  TriggerReconcile(&mutable_entry2, false, &specifics2);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 2, 2);
+}
+
+TEST_F(LostNavigationsRecorderTest, NoWritesWhileSyncingMultipleLost) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+                                         syncer::SyncChange::ACTION_UPDATE);
+  mutable_entry.PutIsUnsynced(true);
+  recorder()->OnLocalChange(&mutable_entry, change);
+
+  specifics.mutable_session()->mutable_tab()->clear_navigation();
+  AddNavigation(specifics.mutable_session());
+  change = MakeChange(kTab1SyncTag, specifics.session(),
+                      syncer::SyncChange::ACTION_UPDATE);
+  recorder()->OnLocalChange(&mutable_entry, change);
+
+  mutable_entry.PutIsUnsynced(false);
+  recorder()->OnLocalChange(&mutable_entry, change);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 5, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, WindowChangeDoesNotTriggerReconcile) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  const Id& id2 = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  MutableEntry mutable_entry2(&wtrans, syncer::syncable::GET_BY_ID, id2);
+  mutable_entry.PutIsUnsynced(true);
+
+  RecordChange(&mutable_entry, 1);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildWindowSpecifics(1, specifics.mutable_session());
+  RecordChange(&mutable_entry2, specifics);
+
+  EXPECT_EQ(0ul,
+            histogram_tester.GetAllSamples("Sync.LostNavigationCount").size());
+}
+
+TEST_F(LostNavigationsRecorderTest, Samutable_entryNavigationSetAcrossStates) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  syncer::SyncChange change = MakeChange(kTab1SyncTag, specifics.session(),
+                                         syncer::SyncChange::ACTION_UPDATE);
+  mutable_entry.PutIsUnsynced(true);
+  recorder()->OnLocalChange(&mutable_entry, change);
+  recorder()->OnLocalChange(&mutable_entry, change);
+
+  mutable_entry.PutIsUnsynced(false);
+  recorder()->OnLocalChange(&mutable_entry, change);
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 0, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, RevisitPreviousNavs) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 3);
+  RecordChange(&mutable_entry, specifics);
+
+  AddNavigation(specifics.mutable_session());
+  RecordChange(&mutable_entry, specifics);
+
+  specifics.mutable_session()
+      ->mutable_tab()
+      ->mutable_navigation()
+      ->RemoveLast();
+  RecordChange(&mutable_entry, specifics);
+
+  TriggerReconcile(&mutable_entry, true, &specifics);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 1, 1);
+}
+
+TEST_F(LostNavigationsRecorderTest, MultipleNavsMultipleLostWithOverlap) {
+  base::HistogramTester histogram_tester;
+  const Id& id = CreateEntry();
+  WriteTransaction wtrans(FROM_HERE, syncer::syncable::UNITTEST, directory());
+  MutableEntry mutable_entry(&wtrans, syncer::syncable::GET_BY_ID, id);
+  mutable_entry.PutIsUnsynced(true);
+
+  sync_pb::EntitySpecifics specifics;
+  BuildTabSpecifics(kTab1SyncTag, 1, specifics.mutable_session(), 5);
+  RecordChange(&mutable_entry, specifics);
+
+  AddNavigation(specifics.mutable_session());
+  AddNavigation(specifics.mutable_session());
+
+  specifics.mutable_session()
+      ->mutable_tab()
+      ->mutable_navigation()
+      ->DeleteSubrange(0, 2);
+  RecordChange(&mutable_entry, specifics);
+
+  TriggerReconcile(&mutable_entry, true, &specifics);
+
+  histogram_tester.ExpectBucketCount("Sync.LostNavigationCount", 2, 1);
+}
+
+};  // namespace
+};  // namespace sync_sessions
diff --git a/components/sync_sessions/sessions_sync_manager.cc b/components/sync_sessions/sessions_sync_manager.cc
index a1e5d13..fd7fd50 100644
--- a/components/sync_sessions/sessions_sync_manager.cc
+++ b/components/sync_sessions/sessions_sync_manager.cc
@@ -7,6 +7,7 @@
 #include <algorithm>
 #include <utility>
 
+#include "base/memory/ptr_util.h"
 #include "base/metrics/field_trial.h"
 #include "base/metrics/histogram_macros.h"
 #include "build/build_config.h"
@@ -16,6 +17,7 @@
 #include "components/sync/api/time.h"
 #include "components/sync/device_info/local_device_info_provider.h"
 #include "components/sync/syncable/syncable_util.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
 #include "components/sync_sessions/sync_sessions_client.h"
 #include "components/sync_sessions/synced_tab_delegate.h"
 #include "components/sync_sessions/synced_window_delegate.h"
@@ -77,7 +79,7 @@
 // |local_device| is owned by ProfileSyncService, its lifetime exceeds
 // lifetime of SessionSyncManager.
 SessionsSyncManager::SessionsSyncManager(
-    SyncSessionsClient* sessions_client,
+    sync_sessions::SyncSessionsClient* sessions_client,
     sync_driver::SyncPrefs* sync_prefs,
     LocalDeviceInfoProvider* local_device,
     std::unique_ptr<LocalSessionEventRouter> router,
@@ -120,6 +122,10 @@
   error_handler_ = std::move(error_handler);
   sync_processor_ = std::move(sync_processor);
 
+  lost_navigations_recorder_ =
+      base::MakeUnique<sync_sessions::LostNavigationsRecorder>();
+  sync_processor_->AddLocalChangeObserver(lost_navigations_recorder_.get());
+
   local_session_header_node_id_ = TabNodePool::kInvalidTabNodeID;
 
   // Make sure we have a machine tag.  We do this now (versus earlier) as it's
@@ -436,8 +442,13 @@
 
 void SessionsSyncManager::StopSyncing(syncer::ModelType type) {
   local_event_router_->Stop();
+  if (sync_processor_.get() && lost_navigations_recorder_.get()) {
+    sync_processor_->RemoveLocalChangeObserver(
+        lost_navigations_recorder_.get());
+  }
   sync_processor_.reset(NULL);
   error_handler_.reset();
+  lost_navigations_recorder_.reset();
   session_tracker_.Clear();
   local_tab_map_.clear();
   local_tab_pool_.Clear();
diff --git a/components/sync_sessions/sessions_sync_manager.h b/components/sync_sessions/sessions_sync_manager.h
index 6735bcc..360601b 100644
--- a/components/sync_sessions/sessions_sync_manager.h
+++ b/components/sync_sessions/sessions_sync_manager.h
@@ -25,6 +25,7 @@
 #include "components/sync/driver/sync_prefs.h"
 #include "components/sync_sessions/favicon_cache.h"
 #include "components/sync_sessions/local_session_event_router.h"
+#include "components/sync_sessions/lost_navigations_recorder.h"
 #include "components/sync_sessions/open_tabs_ui_delegate.h"
 #include "components/sync_sessions/revisit/page_revisit_broadcaster.h"
 #include "components/sync_sessions/synced_session.h"
@@ -370,6 +371,9 @@
   // Owns revisiting instrumentation logic for page visit events.
   PageRevisitBroadcaster page_revisit_broadcaster_;
 
+  std::unique_ptr<sync_sessions::LostNavigationsRecorder>
+      lost_navigations_recorder_;
+
   // Callback to inform interested observer that new sessions data has arrived.
   base::Closure sessions_updated_callback_;
 
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index eefa129..1ce8e50 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -1074,17 +1074,11 @@
     "renderer_host/media/shared_memory_buffer_handle.h",
     "renderer_host/media/shared_memory_buffer_tracker.cc",
     "renderer_host/media/shared_memory_buffer_tracker.h",
-    "renderer_host/media/video_capture_buffer_handle.h",
-    "renderer_host/media/video_capture_buffer_pool.cc",
-    "renderer_host/media/video_capture_buffer_pool.h",
-    "renderer_host/media/video_capture_buffer_tracker.h",
-    "renderer_host/media/video_capture_buffer_tracker_factory.cc",
-    "renderer_host/media/video_capture_buffer_tracker_factory.h",
+    "renderer_host/media/video_capture_buffer_tracker_factory_impl.cc",
+    "renderer_host/media/video_capture_buffer_tracker_factory_impl.h",
     "renderer_host/media/video_capture_controller.cc",
     "renderer_host/media/video_capture_controller.h",
     "renderer_host/media/video_capture_controller_event_handler.h",
-    "renderer_host/media/video_capture_device_client.cc",
-    "renderer_host/media/video_capture_device_client.h",
     "renderer_host/media/video_capture_gpu_jpeg_decoder.cc",
     "renderer_host/media/video_capture_gpu_jpeg_decoder.h",
     "renderer_host/media/video_capture_host.cc",
diff --git a/content/browser/accessibility/browser_accessibility.cc b/content/browser/accessibility/browser_accessibility.cc
index 26e5b48..afcbd003 100644
--- a/content/browser/accessibility/browser_accessibility.cc
+++ b/content/browser/accessibility/browser_accessibility.cc
@@ -414,7 +414,7 @@
       else
         start = 0;
     }
-    return RelativeToAbsoluteBounds(gfx::RectF(bounds), false);
+    return bounds;
   }
 
   int end = start + len;
@@ -457,7 +457,7 @@
     int end_pixel_offset =
         local_end > 0 ? character_offsets[local_end - 1] : 0;
 
-    gfx::Rect child_rect = gfx::ToEnclosingRect(child->GetLocation());
+    gfx::Rect child_rect = child->GetPageBoundsRect();
     auto text_direction = static_cast<ui::AXTextDirection>(
         child->GetIntAttribute(ui::AX_ATTR_TEXT_DIRECTION));
     gfx::Rect child_overlap_rect;
@@ -501,7 +501,7 @@
       bounds.Union(child_overlap_rect);
   }
 
-  return RelativeToAbsoluteBounds(gfx::RectF(bounds), false);
+  return bounds;
 }
 
 gfx::Rect BrowserAccessibility::GetScreenBoundsForRange(int start, int len)
diff --git a/content/browser/download/quarantine_win.cc b/content/browser/download/quarantine_win.cc
index f45a694..59605bf9 100644
--- a/content/browser/download/quarantine_win.cc
+++ b/content/browser/download/quarantine_win.cc
@@ -82,16 +82,6 @@
 void RecordAttachmentServicesSaveResult(const base::FilePath& file,
                                         HRESULT hr) {
   bool file_exists = base::PathExists(file);
-  if (SUCCEEDED(hr)) {
-    bool motw_exists = file_exists && ZoneIdentifierPresentForFile(file);
-    RecordAttachmentServicesResult(
-        file_exists
-            ? motw_exists ? AttachmentServicesResult::SUCCESS_WITH_MOTW
-                          : AttachmentServicesResult::SUCCESS_WITHOUT_MOTW
-            : AttachmentServicesResult::SUCCESS_WITHOUT_FILE);
-    return;
-  }
-
   switch (hr) {
     case INET_E_SECURITY_PROBLEM:
       RecordAttachmentServicesResult(
@@ -107,12 +97,26 @@
 
     case E_ACCESSDENIED:
     case ERROR_ACCESS_DENIED:
+      // ERROR_ACCESS_DENIED is not a valid HRESULT. However,
+      // IAttachmentExecute::Save() is known to return it and other system error
+      // codes in practice.
       RecordAttachmentServicesResult(
           file_exists ? AttachmentServicesResult::ACCESS_DENIED_WITH_FILE
                       : AttachmentServicesResult::ACCESS_DENIED_WITHOUT_FILE);
       break;
 
     default:
+      if (SUCCEEDED(hr)) {
+        bool motw_exists = file_exists && ZoneIdentifierPresentForFile(file);
+        RecordAttachmentServicesResult(
+            file_exists
+                ? motw_exists ? AttachmentServicesResult::SUCCESS_WITH_MOTW
+                              : AttachmentServicesResult::SUCCESS_WITHOUT_MOTW
+                : AttachmentServicesResult::SUCCESS_WITHOUT_FILE);
+        return;
+      }
+
+      // Failure codes.
       RecordAttachmentServicesResult(
           file_exists ? AttachmentServicesResult::OTHER_WITH_FILE
                       : AttachmentServicesResult::OTHER_WITHOUT_FILE);
diff --git a/content/browser/download/quarantine_win_unittest.cc b/content/browser/download/quarantine_win_unittest.cc
index f0229f5..95bdc63 100644
--- a/content/browser/download/quarantine_win_unittest.cc
+++ b/content/browser/download/quarantine_win_unittest.cc
@@ -6,11 +6,13 @@
 
 #include <wininet.h>
 
-#include "content/browser/download/quarantine.h"
 #include "base/files/file_path.h"
 #include "base/files/file_util.h"
 #include "base/files/scoped_temp_dir.h"
+#include "base/macros.h"
 #include "base/test/histogram_tester.h"
+#include "base/test/test_file_util.h"
+#include "content/browser/download/quarantine.h"
 #include "net/base/filename_util.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "url/gurl.h"
@@ -27,6 +29,8 @@
 const base::FilePath::CharType kMotwStreamSuffix[] =
     FILE_PATH_LITERAL(":Zone.Identifier");
 
+const char kTestData[] = "Hello world!";
+
 const char* const kUntrustedURLs[] = {
     "http://example.com/foo",
     "https://example.com/foo",
@@ -68,7 +72,8 @@
 
   for (const auto source_url : kLocalSourceURLs) {
     SCOPED_TRACE(::testing::Message() << "Trying URL " << source_url);
-    ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+    ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+              base::WriteFile(test_file, kTestData, arraysize(kTestData)));
 
     EXPECT_EQ(
         QuarantineFileResult::OK,
@@ -107,7 +112,8 @@
 
   for (const auto source_url : kUntrustedURLs) {
     SCOPED_TRACE(::testing::Message() << "Trying URL " << source_url);
-    ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+    ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+              base::WriteFile(test_file, kTestData, arraysize(kTestData)));
     EXPECT_EQ(
         QuarantineFileResult::OK,
         QuarantineFile(test_file, GURL(source_url), GURL(), kDummyClientGuid));
@@ -145,7 +151,8 @@
 
   for (const auto referrer_url : unsafe_referrers) {
     SCOPED_TRACE(::testing::Message() << "Trying URL " << referrer_url);
-    ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+    ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+              base::WriteFile(test_file, kTestData, arraysize(kTestData)));
     EXPECT_EQ(QuarantineFileResult::OK,
               QuarantineFile(test_file, GURL("http://example.com/good"),
                              GURL(referrer_url), kDummyClientGuid));
@@ -175,7 +182,8 @@
   base::ScopedTempDir test_dir;
   ASSERT_TRUE(test_dir.CreateUniqueTempDir());
   base::FilePath test_file = test_dir.path().AppendASCII("foo.exe");
-  ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+  ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+            base::WriteFile(test_file, kTestData, arraysize(kTestData)));
 
   EXPECT_EQ(QuarantineFileResult::OK,
             QuarantineFile(test_file, GURL(), GURL(), kDummyClientGuid));
@@ -195,6 +203,7 @@
 // the file is passed to AVScanFile, then there wouldn't be a MOTW attached to
 // it and the test would fail.
 TEST(QuarantineWinTest, EmptyFile) {
+  base::HistogramTester histogram_tester;
   base::ScopedTempDir test_dir;
   ASSERT_TRUE(test_dir.CreateUniqueTempDir());
   base::FilePath test_file = test_dir.path().AppendASCII("foo.exe");
@@ -207,6 +216,9 @@
   ASSERT_TRUE(base::ReadFileToString(
       base::FilePath(test_file.value() + kMotwStreamSuffix), &motw_contents));
   EXPECT_STREQ(kMotwForInternetZone, motw_contents.c_str());
+
+  // Attachment services shouldn't have been invoked at all.
+  histogram_tester.ExpectTotalCount("Download.AttachmentServices.Result", 0);
 }
 
 // If there is no client GUID supplied to the QuarantineFile() call, then rather
@@ -217,7 +229,8 @@
   base::ScopedTempDir test_dir;
   ASSERT_TRUE(test_dir.CreateUniqueTempDir());
   base::FilePath test_file = test_dir.path().AppendASCII("foo.exe");
-  ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+  ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+            base::WriteFile(test_file, kTestData, arraysize(kTestData)));
 
   EXPECT_EQ(QuarantineFileResult::OK,
             QuarantineFile(test_file, net::FilePathToFileURL(test_file), GURL(),
@@ -235,7 +248,8 @@
   base::ScopedTempDir test_dir;
   ASSERT_TRUE(test_dir.CreateUniqueTempDir());
   base::FilePath test_file = test_dir.path().AppendASCII("foo.exe");
-  ASSERT_EQ(5, base::WriteFile(test_file, "Hello", 5u));
+  ASSERT_EQ(static_cast<int>(arraysize(kTestData)),
+            base::WriteFile(test_file, kTestData, arraysize(kTestData)));
 
   std::string source_url("http://example.com/");
   source_url.append(INTERNET_MAX_URL_LENGTH * 2, 'a');
diff --git a/content/browser/frame_host/navigation_controller_impl.cc b/content/browser/frame_host/navigation_controller_impl.cc
index c0ddb1b..4466dab2 100644
--- a/content/browser/frame_host/navigation_controller_impl.cc
+++ b/content/browser/frame_host/navigation_controller_impl.cc
@@ -772,7 +772,8 @@
 bool NavigationControllerImpl::RendererDidNavigate(
     RenderFrameHostImpl* rfh,
     const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
-    LoadCommittedDetails* details) {
+    LoadCommittedDetails* details,
+    bool is_navigation_within_page) {
   is_initial_navigation_ = false;
 
   // Save the previous state before we clobber it.
@@ -799,8 +800,7 @@
   details->type = ClassifyNavigation(rfh, params);
 
   // is_in_page must be computed before the entry gets committed.
-  details->is_in_page = IsURLInPageNavigation(params.url, params.origin,
-                                              params.was_within_same_page, rfh);
+  details->is_in_page = is_navigation_within_page;
 
   switch (details->type) {
     case NAVIGATION_TYPE_NEW_PAGE:
diff --git a/content/browser/frame_host/navigation_controller_impl.h b/content/browser/frame_host/navigation_controller_impl.h
index 20bb0f6..f1dd023 100644
--- a/content/browser/frame_host/navigation_controller_impl.h
+++ b/content/browser/frame_host/navigation_controller_impl.h
@@ -149,7 +149,8 @@
   bool RendererDidNavigate(
       RenderFrameHostImpl* rfh,
       const FrameHostMsg_DidCommitProvisionalLoad_Params& params,
-      LoadCommittedDetails* details);
+      LoadCommittedDetails* details,
+      bool is_navigation_within_page);
 
   // Notifies us that we just became active. This is used by the WebContentsImpl
   // so that we know to load URLs that were pending as "lazy" loads.
diff --git a/content/browser/frame_host/navigation_controller_impl_browsertest.cc b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
index 405e6500..e88f507f 100644
--- a/content/browser/frame_host/navigation_controller_impl_browsertest.cc
+++ b/content/browser/frame_host/navigation_controller_impl_browsertest.cc
@@ -27,6 +27,7 @@
 #include "content/public/browser/resource_dispatcher_host_delegate.h"
 #include "content/public/browser/resource_throttle.h"
 #include "content/public/browser/web_contents.h"
+#include "content/public/browser/web_contents_delegate.h"
 #include "content/public/browser/web_contents_observer.h"
 #include "content/public/common/bindings_policy.h"
 #include "content/public/common/browser_side_navigation_policy.h"
@@ -5968,7 +5969,7 @@
   EXPECT_EQ(start_url.GetOrigin().spec(), origin + "/");
 }
 
-// A BrowserMessageFilter that delays FrameHostMsg_DidCommitProvisionaLoad IPC
+// A BrowserMessageFilter that delays FrameHostMsg_DidCommitProvisionalLoad IPC
 // message for a specified URL, navigates the WebContents back and then
 // processes the commit message.
 class GoBackAndCommitFilter : public BrowserMessageFilter {
@@ -5996,7 +5997,7 @@
     if (message.type() != FrameHostMsg_DidCommitProvisionalLoad::ID)
       return false;
 
-    // Parse the IPC message so the URL can be checked agains the expected one.
+    // Parse the IPC message so the URL can be checked against the expected one.
     base::PickleIterator iter(message);
     FrameHostMsg_DidCommitProvisionalLoad_Params validated_params;
     if (!IPC::ParamTraits<FrameHostMsg_DidCommitProvisionalLoad_Params>::Read(
@@ -6137,4 +6138,100 @@
   EXPECT_FALSE(favicon_status3.valid);
 }
 
+namespace {
+
+// A BrowserMessageFilter that delays the FrameHostMsg_RunJavaScriptMessage IPC
+// message until a commit happens on a given WebContents. This allows testing a
+// race condition.
+class AllowDialogIPCOnCommitFilter : public BrowserMessageFilter,
+                                     public WebContentsDelegate {
+ public:
+  AllowDialogIPCOnCommitFilter(WebContents* web_contents)
+      : BrowserMessageFilter(FrameMsgStart),
+        render_frame_host_(web_contents->GetMainFrame()) {
+    web_contents_observer_.Observe(web_contents);
+  }
+
+ protected:
+  ~AllowDialogIPCOnCommitFilter() override {}
+
+ private:
+  // BrowserMessageFilter:
+  bool OnMessageReceived(const IPC::Message& message) override {
+    DCHECK_CURRENTLY_ON(BrowserThread::IO);
+    if (message.type() != FrameHostMsg_RunJavaScriptMessage::ID)
+      return false;
+
+    // Suspend the message.
+    web_contents_observer_.SetCallback(
+        base::Bind(&RenderFrameHost::OnMessageReceived,
+                   base::Unretained(render_frame_host_), message));
+    return true;
+  }
+
+  // WebContentsDelegate:
+  JavaScriptDialogManager* GetJavaScriptDialogManager(
+      WebContents* source) override {
+    CHECK(false);
+    return nullptr;  // agh compiler
+  }
+
+  // Separate because WebContentsObserver and BrowserMessageFilter each have an
+  // OnMessageReceived function; this is the simplest way to disambiguate.
+  class : public WebContentsObserver {
+   public:
+    using Callback = base::Callback<bool()>;
+
+    using WebContentsObserver::Observe;
+
+    void SetCallback(Callback callback) { callback_ = callback; }
+
+   private:
+    void DidNavigateAnyFrame(RenderFrameHost* render_frame_host,
+                             const LoadCommittedDetails& details,
+                             const FrameNavigateParams& params) override {
+      DCHECK_CURRENTLY_ON(BrowserThread::UI);
+
+      // Resume the message.
+      callback_.Run();
+    }
+
+    Callback callback_;
+  } web_contents_observer_;
+
+  RenderFrameHost* render_frame_host_;
+
+  DISALLOW_COPY_AND_ASSIGN(AllowDialogIPCOnCommitFilter);
+};
+
+}  // namespace
+
+// Check that swapped out frames cannot spawn JavaScript dialogs.
+IN_PROC_BROWSER_TEST_F(NavigationControllerBrowserTest,
+                       NoDialogsFromSwappedOutFrames) {
+  // Start on a normal page.
+  GURL url1 = embedded_test_server()->GetURL(
+      "/navigation_controller/beforeunload_dialog.html");
+  EXPECT_TRUE(NavigateToURL(shell(), url1));
+
+  // Add a filter to allow us to force an IPC race.
+  WebContents* web_contents = shell()->web_contents();
+  scoped_refptr<AllowDialogIPCOnCommitFilter> filter =
+      new AllowDialogIPCOnCommitFilter(web_contents);
+  web_contents->SetDelegate(filter.get());
+  web_contents->GetMainFrame()->GetProcess()->AddFilter(filter.get());
+
+  // Use a chrome:// url to force the second page to be in a different process.
+  GURL url2(std::string(kChromeUIScheme) + url::kStandardSchemeSeparator +
+            kChromeUIGpuHost);
+  EXPECT_TRUE(NavigateToURL(shell(), url2));
+
+  // What happens now is that attempting to unload the first page will trigger a
+  // JavaScript alert but allow navigation. The alert IPC will be suspended by
+  // the message filter. The commit of the second page will unblock the IPC. If
+  // the dialog IPC is allowed to spawn a dialog, the call by the WebContents to
+  // its delegate to get the JavaScriptDialogManager will cause a CHECK and the
+  // test will fail.
+}
+
 }  // namespace content
diff --git a/content/browser/frame_host/navigator_impl.cc b/content/browser/frame_host/navigator_impl.cc
index aafb3ccf..0060835 100644
--- a/content/browser/frame_host/navigator_impl.cc
+++ b/content/browser/frame_host/navigator_impl.cc
@@ -562,8 +562,8 @@
 
   int old_entry_count = controller_->GetEntryCount();
   LoadCommittedDetails details;
-  bool did_navigate = controller_->RendererDidNavigate(render_frame_host,
-                                                       params, &details);
+  bool did_navigate = controller_->RendererDidNavigate(
+      render_frame_host, params, &details, is_navigation_within_page);
 
   // If the history length and/or offset changed, update other renderers in the
   // FrameTree.
diff --git a/content/browser/frame_host/render_frame_host_impl.cc b/content/browser/frame_host/render_frame_host_impl.cc
index 8da6a4d..1cf8c1fe 100644
--- a/content/browser/frame_host/render_frame_host_impl.cc
+++ b/content/browser/frame_host/render_frame_host_impl.cc
@@ -1585,6 +1585,11 @@
     const GURL& frame_url,
     JavaScriptMessageType type,
     IPC::Message* reply_msg) {
+  if (!is_active()) {
+    JavaScriptDialogClosed(reply_msg, true, base::string16(), true);
+    return;
+  }
+
   int32_t message_length = static_cast<int32_t>(message.length());
   if (GetParent()) {
     UMA_HISTOGRAM_COUNTS("JSDialogs.CharacterCount.Subframe", message_length);
diff --git a/content/browser/loader/mime_sniffing_resource_handler.cc b/content/browser/loader/mime_sniffing_resource_handler.cc
index 1c157df..25a4794 100644
--- a/content/browser/loader/mime_sniffing_resource_handler.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler.cc
@@ -414,7 +414,8 @@
   std::unique_ptr<ResourceHandler> handler(
       host_->CreateResourceHandlerForDownload(request(),
                                               true,  // is_content_initiated
-                                              must_download));
+                                              must_download,
+                                              false /* is_new_request */));
   intercepting_handler_->UseNewHandler(std::move(handler), std::string());
   return true;
 }
diff --git a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
index ed407eb1..4964e28 100644
--- a/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
+++ b/content/browser/loader/mime_sniffing_resource_handler_unittest.cc
@@ -151,7 +151,8 @@
   std::unique_ptr<ResourceHandler> CreateResourceHandlerForDownload(
       net::URLRequest* request,
       bool is_content_initiated,
-      bool must_download) override {
+      bool must_download,
+      bool is_new_request) override {
     return CreateNewResourceHandler();
   }
 
diff --git a/content/browser/loader/mojo_async_resource_handler_unittest.cc b/content/browser/loader/mojo_async_resource_handler_unittest.cc
index d20c649..5386d6e 100644
--- a/content/browser/loader/mojo_async_resource_handler_unittest.cc
+++ b/content/browser/loader/mojo_async_resource_handler_unittest.cc
@@ -84,6 +84,7 @@
                         ResourceContext* resource_context,
                         bool is_content_initiated,
                         bool must_download,
+                        bool is_new_request,
                         ScopedVector<ResourceThrottle>* throttles) override {
     ADD_FAILURE() << "DownloadStarting should not be called.";
   }
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc
index 2b3539ed..aa3e925 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.cc
+++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -648,15 +648,17 @@
 ResourceDispatcherHostImpl::CreateResourceHandlerForDownload(
     net::URLRequest* request,
     bool is_content_initiated,
-    bool must_download) {
+    bool must_download,
+    bool is_new_request) {
   DCHECK(!create_download_handler_intercept_.is_null());
   // TODO(ananta)
   // Find a better way to create the download handler and notifying the
   // delegate of the download start.
   std::unique_ptr<ResourceHandler> handler =
       create_download_handler_intercept_.Run(request);
-  handler = HandleDownloadStarted(request, std::move(handler),
-                                  is_content_initiated, must_download);
+  handler =
+      HandleDownloadStarted(request, std::move(handler), is_content_initiated,
+                            must_download, is_new_request);
   return handler;
 }
 
@@ -2353,8 +2355,9 @@
           blob_context->context()->GetBlobDataFromPublicURL(
               request->original_url()));
     }
-    handler = HandleDownloadStarted(request.get(), std::move(handler),
-                                    is_content_initiated, true);
+    handler = HandleDownloadStarted(
+        request.get(), std::move(handler), is_content_initiated,
+        true /* force_download */, true /* is_new_request */);
   }
   BeginRequestInternal(std::move(request), std::move(handler));
 }
@@ -2684,14 +2687,15 @@
     net::URLRequest* request,
     std::unique_ptr<ResourceHandler> handler,
     bool is_content_initiated,
-    bool must_download) {
+    bool must_download,
+    bool is_new_request) {
   if (delegate()) {
     const ResourceRequestInfoImpl* request_info(
         ResourceRequestInfoImpl::ForRequest(request));
     ScopedVector<ResourceThrottle> throttles;
-    delegate()->DownloadStarting(
-        request, request_info->GetContext(), is_content_initiated, true,
-        &throttles);
+    delegate()->DownloadStarting(request, request_info->GetContext(),
+                                 is_content_initiated, true, is_new_request,
+                                 &throttles);
     if (!throttles.empty()) {
       handler.reset(new ThrottlingResourceHandler(std::move(handler), request,
                                                   std::move(throttles)));
diff --git a/content/browser/loader/resource_dispatcher_host_impl.h b/content/browser/loader/resource_dispatcher_host_impl.h
index 76e6d282..1d42442 100644
--- a/content/browser/loader/resource_dispatcher_host_impl.h
+++ b/content/browser/loader/resource_dispatcher_host_impl.h
@@ -234,7 +234,8 @@
   virtual std::unique_ptr<ResourceHandler> CreateResourceHandlerForDownload(
       net::URLRequest* request,
       bool is_content_initiated,
-      bool must_download);
+      bool must_download,
+      bool is_new_request);
 
   // Called to determine whether the response to |request| should be intercepted
   // and handled as a stream. Streams are used to pass direct access to a
@@ -651,7 +652,8 @@
       net::URLRequest* request,
       std::unique_ptr<ResourceHandler> handler,
       bool is_content_initiated,
-      bool must_download);
+      bool must_download,
+      bool is_new_request);
 
   LoaderMap pending_loaders_;
 
diff --git a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
index 60d20ff..9b08283 100644
--- a/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
+++ b/content/browser/media/capture/web_contents_video_capture_device_unittest.cc
@@ -20,8 +20,7 @@
 #include "build/build_config.h"
 #include "content/browser/browser_thread_impl.h"
 #include "content/browser/frame_host/render_frame_host_impl.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h"
 #include "content/browser/renderer_host/render_view_host_factory.h"
 #include "content/browser/renderer_host/render_widget_host_impl.h"
 #include "content/browser/web_contents/web_contents_impl.h"
@@ -38,6 +37,7 @@
 #include "media/base/video_frame.h"
 #include "media/base/video_util.h"
 #include "media/base/yuv_convert.h"
+#include "media/capture/video/video_capture_buffer_pool_impl.h"
 #include "skia/ext/platform_canvas.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -333,7 +333,8 @@
       const base::Closure& error_callback)
       : report_callback_(report_callback),
         error_callback_(error_callback) {
-    buffer_pool_ = new VideoCaptureBufferPoolImpl(2);
+    buffer_pool_ = new media::VideoCaptureBufferPoolImpl(
+        base::MakeUnique<VideoCaptureBufferTrackerFactoryImpl>(), 2);
   }
   ~StubClient() override {}
 
@@ -352,10 +353,11 @@
                       media::VideoPixelFormat format,
                       media::VideoPixelStorage storage) override {
     CHECK_EQ(format, media::PIXEL_FORMAT_I420);
-    int buffer_id_to_drop = VideoCaptureBufferPool::kInvalidId;  // Ignored.
+    int buffer_id_to_drop =
+        media::VideoCaptureBufferPool::kInvalidId;  // Ignored.
     const int buffer_id = buffer_pool_->ReserveForProducer(
         dimensions, format, storage, &buffer_id_to_drop);
-    if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+    if (buffer_id == media::VideoCaptureBufferPool::kInvalidId)
       return NULL;
 
     return std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>(
@@ -406,7 +408,7 @@
     CHECK_EQ(format, media::PIXEL_FORMAT_I420);
     const int buffer_id =
         buffer_pool_->ResurrectLastForProducer(dimensions, format, storage);
-    if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+    if (buffer_id == media::VideoCaptureBufferPool::kInvalidId)
       return nullptr;
     return std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>(
         new AutoReleaseBuffer(
@@ -423,9 +425,10 @@
  private:
   class AutoReleaseBuffer : public media::VideoCaptureDevice::Client::Buffer {
    public:
-    AutoReleaseBuffer(const scoped_refptr<VideoCaptureBufferPool>& pool,
-                      std::unique_ptr<VideoCaptureBufferHandle> buffer_handle,
-                      int buffer_id)
+    AutoReleaseBuffer(
+        const scoped_refptr<media::VideoCaptureBufferPool>& pool,
+        std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle,
+        int buffer_id)
         : id_(buffer_id),
           pool_(pool),
           buffer_handle_(std::move(buffer_handle)) {
@@ -450,11 +453,11 @@
     ~AutoReleaseBuffer() override { pool_->RelinquishProducerReservation(id_); }
 
     const int id_;
-    const scoped_refptr<VideoCaptureBufferPool> pool_;
-    const std::unique_ptr<VideoCaptureBufferHandle> buffer_handle_;
+    const scoped_refptr<media::VideoCaptureBufferPool> pool_;
+    const std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle_;
   };
 
-  scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
+  scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_;
   base::Callback<void(SkColor, const gfx::Size&)> report_callback_;
   base::Closure error_callback_;
 
diff --git a/content/browser/renderer_host/DEPS b/content/browser/renderer_host/DEPS
index 3c872db..79ab5a9 100644
--- a/content/browser/renderer_host/DEPS
+++ b/content/browser/renderer_host/DEPS
@@ -3,7 +3,6 @@
   "+components/display_compositor",
   "+services/ui/public",
   "+third_party/zlib",
-  "+third_party/libyuv",
 
   # The renderer_host files should only call upwards in the layering via the
   # delegate interfaces.
diff --git a/content/browser/renderer_host/media/gpu_memory_buffer_handle.h b/content/browser/renderer_host/media/gpu_memory_buffer_handle.h
index 05e5ccf6..4dd61a22 100644
--- a/content/browser/renderer_host/media/gpu_memory_buffer_handle.h
+++ b/content/browser/renderer_host/media/gpu_memory_buffer_handle.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_GPU_MEMORY_BUFFER_HANDLE_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_GPU_MEMORY_BUFFER_HANDLE_H_
 
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
 
 namespace content {
 
@@ -13,7 +13,7 @@
 
 // A simple proxy that implements the BufferHandle interface, providing
 // accessors to GpuMemoryBufferTracker's memory and properties.
-class GpuMemoryBufferBufferHandle : public VideoCaptureBufferHandle {
+class GpuMemoryBufferBufferHandle : public media::VideoCaptureBufferHandle {
  public:
   // |tracker| must outlive GpuMemoryBufferBufferHandle. This is ensured since
   // a tracker is pinned until ownership of this GpuMemoryBufferBufferHandle
diff --git a/content/browser/renderer_host/media/gpu_memory_buffer_tracker.cc b/content/browser/renderer_host/media/gpu_memory_buffer_tracker.cc
index b4e601c9..a19461f7 100644
--- a/content/browser/renderer_host/media/gpu_memory_buffer_tracker.cc
+++ b/content/browser/renderer_host/media/gpu_memory_buffer_tracker.cc
@@ -58,7 +58,7 @@
   return true;
 }
 
-std::unique_ptr<VideoCaptureBufferHandle>
+std::unique_ptr<media::VideoCaptureBufferHandle>
 GpuMemoryBufferTracker::GetBufferHandle() {
   DCHECK_EQ(gpu_memory_buffers_.size(),
             media::VideoFrame::NumPlanes(pixel_format()));
diff --git a/content/browser/renderer_host/media/gpu_memory_buffer_tracker.h b/content/browser/renderer_host/media/gpu_memory_buffer_tracker.h
index e12a88ce..c3f13d16 100644
--- a/content/browser/renderer_host/media/gpu_memory_buffer_tracker.h
+++ b/content/browser/renderer_host/media/gpu_memory_buffer_tracker.h
@@ -5,13 +5,13 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_GPU_MEMORY_BUFFER_TRACKER_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_GPU_MEMORY_BUFFER_TRACKER_H_
 
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker.h"
+#include "media/capture/video/video_capture_buffer_tracker.h"
 
 namespace content {
 
 // Tracker specifics for GpuMemoryBuffer. Owns GpuMemoryBuffers and its
 // associated pixel dimensions.
-class GpuMemoryBufferTracker final : public VideoCaptureBufferTracker {
+class GpuMemoryBufferTracker final : public media::VideoCaptureBufferTracker {
  public:
   GpuMemoryBufferTracker();
   ~GpuMemoryBufferTracker() override;
@@ -21,7 +21,7 @@
             media::VideoPixelStorage storage_type,
             base::Lock* lock) override;
 
-  std::unique_ptr<VideoCaptureBufferHandle> GetBufferHandle() override;
+  std::unique_ptr<media::VideoCaptureBufferHandle> GetBufferHandle() override;
 
   bool ShareToProcess(base::ProcessHandle process_handle,
                       base::SharedMemoryHandle* new_handle) override;
diff --git a/content/browser/renderer_host/media/shared_memory_buffer_handle.h b/content/browser/renderer_host/media/shared_memory_buffer_handle.h
index 3f327528..da29983 100644
--- a/content/browser/renderer_host/media/shared_memory_buffer_handle.h
+++ b/content/browser/renderer_host/media/shared_memory_buffer_handle.h
@@ -5,7 +5,7 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_SHARED_MEMORY_BUFFER_HANDLE_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_SHARED_MEMORY_BUFFER_HANDLE_H_
 
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
 
 namespace content {
 
@@ -13,7 +13,7 @@
 
 // A simple proxy that implements the BufferHandle interface, providing
 // accessors to SharedMemTracker's memory and properties.
-class SharedMemoryBufferHandle : public VideoCaptureBufferHandle {
+class SharedMemoryBufferHandle : public media::VideoCaptureBufferHandle {
  public:
   // |tracker| must outlive SimpleBufferHandle. This is ensured since a
   // tracker is pinned until ownership of this SimpleBufferHandle is returned
diff --git a/content/browser/renderer_host/media/shared_memory_buffer_tracker.cc b/content/browser/renderer_host/media/shared_memory_buffer_tracker.cc
index 27dca64e..af9235be 100644
--- a/content/browser/renderer_host/media/shared_memory_buffer_tracker.cc
+++ b/content/browser/renderer_host/media/shared_memory_buffer_tracker.cc
@@ -30,7 +30,7 @@
   return shared_memory_.CreateAndMapAnonymous(mapped_size_);
 }
 
-std::unique_ptr<VideoCaptureBufferHandle>
+std::unique_ptr<media::VideoCaptureBufferHandle>
 SharedMemoryBufferTracker::GetBufferHandle() {
   return base::MakeUnique<SharedMemoryBufferHandle>(this);
 }
diff --git a/content/browser/renderer_host/media/shared_memory_buffer_tracker.h b/content/browser/renderer_host/media/shared_memory_buffer_tracker.h
index 2aad666..81504378 100644
--- a/content/browser/renderer_host/media/shared_memory_buffer_tracker.h
+++ b/content/browser/renderer_host/media/shared_memory_buffer_tracker.h
@@ -5,12 +5,13 @@
 #ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_SHARED_MEMORY_BUFFER_TRACKER_H_
 #define CONTENT_BROWSER_RENDERER_HOST_MEDIA_SHARED_MEMORY_BUFFER_TRACKER_H_
 
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker.h"
+#include "media/capture/video/video_capture_buffer_tracker.h"
 
 namespace content {
 
 // Tracker specifics for SharedMemory.
-class SharedMemoryBufferTracker final : public VideoCaptureBufferTracker {
+class SharedMemoryBufferTracker final
+    : public media::VideoCaptureBufferTracker {
  public:
   SharedMemoryBufferTracker();
 
@@ -19,7 +20,7 @@
             media::VideoPixelStorage storage_type,
             base::Lock* lock) override;
 
-  std::unique_ptr<VideoCaptureBufferHandle> GetBufferHandle() override;
+  std::unique_ptr<media::VideoCaptureBufferHandle> GetBufferHandle() override;
   bool ShareToProcess(base::ProcessHandle process_handle,
                       base::SharedMemoryHandle* new_handle) override;
   bool ShareToProcess2(int plane,
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc b/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
index 9933c76..e31d446 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_buffer_pool_unittest.cc
@@ -4,7 +4,7 @@
 
 // Unit test for VideoCaptureBufferPool.
 
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
+#include "media/capture/video/video_capture_buffer_pool.h"
 
 #include <stddef.h>
 #include <stdint.h>
@@ -24,9 +24,10 @@
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "components/display_compositor/buffer_queue.h"
 #include "content/browser/gpu/browser_gpu_memory_buffer_manager.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
 #include "media/base/video_frame.h"
+#include "media/capture/video/video_capture_buffer_pool_impl.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -48,6 +49,10 @@
 
 static const int kTestBufferPoolSize = 3;
 
+// Note that this test does not exercise the class VideoCaptureBufferPool
+// in isolation. The "unit under test" is an instance of VideoCaptureBufferPool
+// with some context that is specific to renderer_host/media, and therefore
+// this test must live here and not in media/capture/video.
 class VideoCaptureBufferPoolTest
     : public testing::TestWithParam<PixelFormatAndStorage> {
  protected:
@@ -119,8 +124,8 @@
   // This is a generic Buffer tracker
   class Buffer {
    public:
-    Buffer(const scoped_refptr<VideoCaptureBufferPool> pool,
-           std::unique_ptr<VideoCaptureBufferHandle> buffer_handle,
+    Buffer(const scoped_refptr<media::VideoCaptureBufferPool> pool,
+           std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle,
            int id)
         : id_(id), pool_(pool), buffer_handle_(std::move(buffer_handle)) {}
     ~Buffer() { pool_->RelinquishProducerReservation(id()); }
@@ -130,13 +135,15 @@
 
    private:
     const int id_;
-    const scoped_refptr<VideoCaptureBufferPool> pool_;
-    const std::unique_ptr<VideoCaptureBufferHandle> buffer_handle_;
+    const scoped_refptr<media::VideoCaptureBufferPool> pool_;
+    const std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle_;
   };
 
   VideoCaptureBufferPoolTest()
       : expected_dropped_id_(0),
-        pool_(new VideoCaptureBufferPoolImpl(kTestBufferPoolSize)) {}
+        pool_(new media::VideoCaptureBufferPoolImpl(
+            base::MakeUnique<VideoCaptureBufferTrackerFactoryImpl>(),
+            kTestBufferPoolSize)) {}
 
 #if !defined(OS_ANDROID)
   void SetUp() override {
@@ -161,11 +168,11 @@
     const int buffer_id = pool_->ReserveForProducer(
         dimensions, format_and_storage.pixel_format,
         format_and_storage.pixel_storage, &buffer_id_to_drop);
-    if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+    if (buffer_id == media::VideoCaptureBufferPool::kInvalidId)
       return std::unique_ptr<Buffer>();
     EXPECT_EQ(expected_dropped_id_, buffer_id_to_drop);
 
-    std::unique_ptr<VideoCaptureBufferHandle> buffer_handle =
+    std::unique_ptr<media::VideoCaptureBufferHandle> buffer_handle =
         pool_->GetBufferHandle(buffer_id);
     return std::unique_ptr<Buffer>(
         new Buffer(pool_, std::move(buffer_handle), buffer_id));
@@ -177,7 +184,7 @@
     const int buffer_id = pool_->ResurrectLastForProducer(
         dimensions, format_and_storage.pixel_format,
         format_and_storage.pixel_storage);
-    if (buffer_id == VideoCaptureBufferPool::kInvalidId)
+    if (buffer_id == media::VideoCaptureBufferPool::kInvalidId)
       return std::unique_ptr<Buffer>();
     return std::unique_ptr<Buffer>(
         new Buffer(pool_, pool_->GetBufferHandle(buffer_id), buffer_id));
@@ -185,7 +192,7 @@
 
   base::MessageLoop loop_;
   int expected_dropped_id_;
-  scoped_refptr<VideoCaptureBufferPool> pool_;
+  scoped_refptr<media::VideoCaptureBufferPool> pool_;
 
  private:
 #if !defined(OS_ANDROID)
@@ -204,7 +211,7 @@
       size_hi, 0.0, GetParam().pixel_format, GetParam().pixel_storage);
 
   // Reallocation won't happen for the first part of the test.
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
 
   // The buffer pool should have zero utilization before any buffers have been
   // reserved.
@@ -334,7 +341,7 @@
   ASSERT_EQ(3.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
   void* const memory_pointer_hi = buffer2->data();
   buffer2.reset();  // Frees it.
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
   ASSERT_EQ(2.0 / kTestBufferPoolSize, pool_->GetBufferPoolUtilization());
   buffer2 = ReserveBuffer(size_lo, GetParam());
   void* const memory_pointer_lo = buffer2->data();
@@ -369,7 +376,7 @@
 // Tests that a previously-released buffer can be immediately resurrected under
 // normal conditions.
 TEST_P(VideoCaptureBufferPoolTest, ResurrectsLastBuffer) {
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
 
   // At the start, there should be nothing to resurrect.
   std::unique_ptr<Buffer> resurrected =
@@ -413,7 +420,7 @@
 
 // Tests that a buffer cannot be resurrected if its properties do not match.
 TEST_P(VideoCaptureBufferPoolTest, DoesNotResurrectIfPropertiesNotMatched) {
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
 
   // Reserve a 10x10 buffer, fill it with 0xcd values, and release it.
   std::unique_ptr<Buffer> original =
@@ -463,7 +470,7 @@
 // Tests that the buffers are managed by the pool such that the last-released
 // buffer is kept around as long as possible (for successful resurrection).
 TEST_P(VideoCaptureBufferPoolTest, AvoidsClobberingForResurrectingLastBuffer) {
-  ExpectDroppedId(VideoCaptureBufferPool::kInvalidId);
+  ExpectDroppedId(media::VideoCaptureBufferPool::kInvalidId);
 
   // Reserve a 10x10 buffer, fill it with 0xde values, and release it.
   std::unique_ptr<Buffer> original =
diff --git a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h
deleted file mode 100644
index e687471..0000000
--- a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// Copyright 2016 The Chromium 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_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
-
-#include <memory>
-
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker.h"
-
-namespace content {
-
-class VideoCaptureBufferTrackerFactory {
- public:
-  static std::unique_ptr<VideoCaptureBufferTracker> CreateTracker(
-      media::VideoPixelStorage storage);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
diff --git a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.cc b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.cc
similarity index 79%
rename from content/browser/renderer_host/media/video_capture_buffer_tracker_factory.cc
rename to content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.cc
index c58f564..1d2831b 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory.cc
+++ b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.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 "content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h"
 
 #include "base/memory/ptr_util.h"
 
@@ -11,9 +11,8 @@
 
 namespace content {
 
-// static
-std::unique_ptr<VideoCaptureBufferTracker>
-VideoCaptureBufferTrackerFactory::CreateTracker(
+std::unique_ptr<media::VideoCaptureBufferTracker>
+VideoCaptureBufferTrackerFactoryImpl::CreateTracker(
     media::VideoPixelStorage storage) {
   switch (storage) {
     case media::PIXEL_STORAGE_GPUMEMORYBUFFER:
@@ -22,7 +21,7 @@
       return base::MakeUnique<SharedMemoryBufferTracker>();
   }
   NOTREACHED();
-  return std::unique_ptr<VideoCaptureBufferTracker>();
+  return std::unique_ptr<media::VideoCaptureBufferTracker>();
 }
 
 }  // namespace content
diff --git a/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h
new file mode 100644
index 0000000..a256963
--- /dev/null
+++ b/content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium 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_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_IMPL_H_
+#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_IMPL_H_
+
+#include <memory>
+
+#include "content/common/content_export.h"
+#include "media/capture/video/video_capture_buffer_tracker_factory.h"
+
+namespace content {
+
+class CONTENT_EXPORT VideoCaptureBufferTrackerFactoryImpl
+    : public media::VideoCaptureBufferTrackerFactory {
+ public:
+  std::unique_ptr<media::VideoCaptureBufferTracker> CreateTracker(
+      media::VideoPixelStorage storage) override;
+};
+
+}  // namespace content
+
+#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_IMPL_H_
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
index c922822..c594c3b 100644
--- a/content/browser/renderer_host/media/video_capture_controller.cc
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
@@ -18,13 +18,14 @@
 #include "build/build_config.h"
 #include "components/display_compositor/gl_helper.h"
 #include "content/browser/renderer_host/media/media_stream_manager.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
-#include "content/browser/renderer_host/media/video_capture_device_client.h"
+#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory_impl.h"
 #include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h"
 #include "content/browser/renderer_host/media/video_capture_manager.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/common/content_switches.h"
 #include "media/base/video_frame.h"
+#include "media/capture/video/video_capture_buffer_pool_impl.h"
+#include "media/capture/video/video_capture_device_client.h"
 
 #if !defined(OS_ANDROID)
 #include "content/browser/compositor/image_transport_factory.h"
@@ -79,14 +80,14 @@
 #endif
 }
 
-std::unique_ptr<VideoCaptureJpegDecoder> CreateGpuJpegDecoder(
-    const VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) {
+std::unique_ptr<media::VideoCaptureJpegDecoder> CreateGpuJpegDecoder(
+    const media::VideoCaptureJpegDecoder::DecodeDoneCB& decode_done_cb) {
   return base::MakeUnique<VideoCaptureGpuJpegDecoder>(decode_done_cb);
 }
 
-// Decorator for VideoFrameReceiver that forwards all incoming calls
+// Decorator for media::VideoFrameReceiver that forwards all incoming calls
 // to the Browser IO thread.
-class VideoFrameReceiverOnIOThread : public VideoFrameReceiver {
+class VideoFrameReceiverOnIOThread : public media::VideoFrameReceiver {
  public:
   explicit VideoFrameReceiverOnIOThread(
       const base::WeakPtr<VideoFrameReceiver>& receiver)
@@ -176,7 +177,9 @@
 };
 
 VideoCaptureController::VideoCaptureController(int max_buffers)
-    : buffer_pool_(new VideoCaptureBufferPoolImpl(max_buffers)),
+    : buffer_pool_(new media::VideoCaptureBufferPoolImpl(
+          base::MakeUnique<VideoCaptureBufferTrackerFactoryImpl>(),
+          max_buffers)),
       state_(VIDEO_CAPTURE_STATE_STARTED),
       has_received_frames_(false),
       weak_ptr_factory_(this) {
@@ -191,7 +194,7 @@
 std::unique_ptr<media::VideoCaptureDevice::Client>
 VideoCaptureController::NewDeviceClient() {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
-  return base::MakeUnique<VideoCaptureDeviceClient>(
+  return base::MakeUnique<media::VideoCaptureDeviceClient>(
       base::MakeUnique<VideoFrameReceiverOnIOThread>(
           this->GetWeakPtrForIOThread()),
       buffer_pool_,
@@ -408,7 +411,7 @@
     const scoped_refptr<VideoFrame>& frame) {
   DCHECK_CURRENTLY_ON(BrowserThread::IO);
   const int buffer_id = buffer->id();
-  DCHECK_NE(buffer_id, VideoCaptureBufferPool::kInvalidId);
+  DCHECK_NE(buffer_id, media::VideoCaptureBufferPool::kInvalidId);
 
   int count = 0;
   if (state_ == VIDEO_CAPTURE_STATE_STARTED) {
diff --git a/content/browser/renderer_host/media/video_capture_controller.h b/content/browser/renderer_host/media/video_capture_controller.h
index 9674bdd0..25c826b 100644
--- a/content/browser/renderer_host/media/video_capture_controller.h
+++ b/content/browser/renderer_host/media/video_capture_controller.h
@@ -52,24 +52,15 @@
 #include "content/common/content_export.h"
 #include "content/common/media/video_capture.h"
 #include "media/base/video_capture_types.h"
-#include "media/capture/video/video_capture_device.h"
+#include "media/capture/video/video_frame_receiver.h"
+
+namespace media {
+class VideoCaptureBufferPool;
+}
 
 namespace content {
-class VideoCaptureBufferPool;
 
-class CONTENT_EXPORT VideoFrameReceiver {
- public:
-  virtual ~VideoFrameReceiver(){};
-
-  virtual void OnIncomingCapturedVideoFrame(
-      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
-      const scoped_refptr<media::VideoFrame>& frame) = 0;
-  virtual void OnError() = 0;
-  virtual void OnLog(const std::string& message) = 0;
-  virtual void OnBufferDestroyed(int buffer_id_to_drop) = 0;
-};
-
-class CONTENT_EXPORT VideoCaptureController : public VideoFrameReceiver {
+class CONTENT_EXPORT VideoCaptureController : public media::VideoFrameReceiver {
  public:
   // |max_buffers| is the maximum number of video frame buffers in-flight at any
   // one time.  This value should be based on the logical capacity of the
@@ -137,7 +128,7 @@
 
   bool has_received_frames() const { return has_received_frames_; }
 
-  // Implementation of VideoFrameReceiver interface:
+  // Implementation of media::VideoFrameReceiver interface:
   void OnIncomingCapturedVideoFrame(
       std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
       const scoped_refptr<media::VideoFrame>& frame) override;
@@ -164,7 +155,7 @@
                                const ControllerClients& clients);
 
   // The pool of shared-memory buffers used for capturing.
-  const scoped_refptr<VideoCaptureBufferPool> buffer_pool_;
+  const scoped_refptr<media::VideoCaptureBufferPool> buffer_pool_;
 
   // All clients served by this controller.
   ControllerClients controller_clients_;
diff --git a/content/browser/renderer_host/media/video_capture_device_client_unittest.cc b/content/browser/renderer_host/media/video_capture_device_client_unittest.cc
index 2260efb..507af16 100644
--- a/content/browser/renderer_host/media/video_capture_device_client_unittest.cc
+++ b/content/browser/renderer_host/media/video_capture_device_client_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 "content/browser/renderer_host/media/video_capture_device_client.h"
+#include "media/capture/video/video_capture_device_client.h"
 
 #include <stddef.h>
 
@@ -15,10 +15,10 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "build/build_config.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
 #include "content/browser/renderer_host/media/video_capture_controller.h"
 #include "content/public/test/test_browser_thread_bundle.h"
 #include "media/base/limits.h"
+#include "media/capture/video/video_capture_buffer_pool.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -49,6 +49,11 @@
   }
 };
 
+// Note that this test does not exercise the class VideoCaptureDeviceClient
+// in isolation. The "unit under test" is an instance of
+// VideoCaptureDeviceClient with some context that is specific to
+// renderer_host/media, and therefore this test must live here and not in
+// media/capture/video.
 class VideoCaptureDeviceClientTest : public ::testing::Test {
  public:
   VideoCaptureDeviceClientTest()
diff --git a/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h b/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
index 9367df2..672735eb 100644
--- a/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
+++ b/content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h
@@ -18,7 +18,7 @@
 #include "base/single_thread_task_runner.h"
 #include "base/threading/thread.h"
 #include "content/common/content_export.h"
-#include "media/capture/video/video_capture_device.h"
+#include "media/capture/video/video_capture_jpeg_decoder.h"
 #include "media/video/jpeg_decode_accelerator.h"
 
 namespace gpu {
@@ -31,40 +31,6 @@
 
 namespace content {
 
-class CONTENT_EXPORT VideoCaptureJpegDecoder {
- public:
-  // Enumeration of decoder status. The enumeration is published for clients to
-  // decide the behavior according to STATUS.
-  enum STATUS {
-    INIT_PENDING,  // Default value while waiting initialization finished.
-    INIT_PASSED,   // Initialization succeed.
-    FAILED,        // JPEG decode is not supported, initialization failed, or
-                   // decode error.
-  };
-
-  using DecodeDoneCB = base::Callback<void(
-      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>,
-      const scoped_refptr<media::VideoFrame>&)>;
-
-  virtual ~VideoCaptureJpegDecoder() {}
-
-  // Creates and intializes decoder asynchronously.
-  virtual void Initialize() = 0;
-
-  // Returns initialization status.
-  virtual STATUS GetStatus() const = 0;
-
-  // Decodes a JPEG picture.
-  virtual void DecodeCapturedData(
-      const uint8_t* data,
-      size_t in_buffer_size,
-      const media::VideoCaptureFormat& frame_format,
-      base::TimeTicks reference_time,
-      base::TimeDelta timestamp,
-      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
-          out_buffer) = 0;
-};
-
 // Adapter to GpuJpegDecodeAccelerator for VideoCaptureDevice::Client. It takes
 // care of GpuJpegDecodeAccelerator creation, shared memory, and threading
 // issues.
@@ -73,7 +39,7 @@
 // on the same thread. JpegDecodeAccelerator::Client methods should be called on
 // the IO thread.
 class CONTENT_EXPORT VideoCaptureGpuJpegDecoder
-    : public VideoCaptureJpegDecoder,
+    : public media::VideoCaptureJpegDecoder,
       public media::JpegDecodeAccelerator::Client,
       public base::NonThreadSafe,
       public base::SupportsWeakPtr<VideoCaptureGpuJpegDecoder> {
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 5fb4834..fe65bc1d0 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.cc
+++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -440,6 +440,9 @@
       has_composition_text_(false),
       accept_return_character_(false),
       begin_frame_source_(nullptr),
+      needs_begin_frames_(false),
+      needs_flush_input_(false),
+      added_frame_observer_(false),
       synthetic_move_sent_(false),
       cursor_visibility_state_in_renderer_(UNKNOWN),
 #if defined(OS_WIN)
@@ -712,10 +715,25 @@
 }
 
 void RenderWidgetHostViewAura::SetNeedsBeginFrames(bool needs_begin_frames) {
+  needs_begin_frames_ = needs_begin_frames;
+  UpdateNeedsBeginFramesInternal();
+}
+
+void RenderWidgetHostViewAura::OnSetNeedsFlushInput() {
+  needs_flush_input_ = true;
+  UpdateNeedsBeginFramesInternal();
+}
+
+void RenderWidgetHostViewAura::UpdateNeedsBeginFramesInternal() {
   if (!begin_frame_source_)
     return;
 
-  if (needs_begin_frames)
+  bool needs_frame = needs_begin_frames_ || needs_flush_input_;
+  if (needs_frame == added_frame_observer_)
+    return;
+
+  added_frame_observer_ = needs_frame;
+  if (needs_frame)
     begin_frame_source_->AddObserver(this);
   else
     begin_frame_source_->RemoveObserver(this);
@@ -723,6 +741,9 @@
 
 void RenderWidgetHostViewAura::OnBeginFrame(
     const cc::BeginFrameArgs& args) {
+  needs_flush_input_ = false;
+  host_->FlushInput();
+  UpdateNeedsBeginFramesInternal();
   host_->Send(new ViewMsg_BeginFrame(host_->GetRoutingID(), args));
   last_begin_frame_args_ = args;
 }
@@ -2924,12 +2945,12 @@
 
 void RenderWidgetHostViewAura::SetBeginFrameSource(
     cc::BeginFrameSource* source) {
-  bool needs_begin_frames = host_->needs_begin_frames();
-  if (begin_frame_source_ && needs_begin_frames)
+  if (begin_frame_source_ && added_frame_observer_) {
     begin_frame_source_->RemoveObserver(this);
+    added_frame_observer_ = false;
+  }
   begin_frame_source_ = source;
-  if (begin_frame_source_ && needs_begin_frames)
-    begin_frame_source_->AddObserver(this);
+  UpdateNeedsBeginFramesInternal();
 }
 
 bool RenderWidgetHostViewAura::IsAutoResizeEnabled() const {
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h
index 190d5c9..c465b46e 100644
--- a/content/browser/renderer_host/render_widget_host_view_aura.h
+++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -162,6 +162,7 @@
   void EndFrameSubscription() override;
   bool HasAcceleratedSurface(const gfx::Size& desired_size) override;
   gfx::Rect GetBoundsInRootWindow() override;
+  void OnSetNeedsFlushInput() override;
   void WheelEventAck(const blink::WebMouseWheelEvent& event,
                      InputEventAckState ack_result) override;
   void GestureEventAck(const blink::WebGestureEvent& event,
@@ -532,6 +533,9 @@
   // Forwards a mouse event to this view's parent window delegate.
   void ForwardMouseEventToParent(ui::MouseEvent* event);
 
+  // Adds/Removes frame observer based on state.
+  void UpdateNeedsBeginFramesInternal();
+
   // Returns the RenderViewHostDelegateView instance for this view. Returns
   // NULL on failure.
   RenderViewHostDelegateView* GetRenderViewHostDelegateView();
@@ -592,8 +596,16 @@
   // The begin frame source being observed.  Null if none.
   cc::BeginFrameSource* begin_frame_source_;
   cc::BeginFrameArgs last_begin_frame_args_;
+
+  // Whether a request for begin frames has been issued.
   bool needs_begin_frames_;
 
+  // Whether a request to flush input has been issued.
+  bool needs_flush_input_;
+
+  // Whether we have added ourselves as a frame observer or not.
+  bool added_frame_observer_;
+
   // Used to record the last position of the mouse.
   // While the mouse is locked, they store the last known position just as mouse
   // lock was entered.
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 9a2f0da1..75ad48f 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.h
+++ b/content/browser/renderer_host/render_widget_host_view_mac.h
@@ -320,6 +320,7 @@
 
   bool LockMouse() override;
   void UnlockMouse() override;
+  void OnSetNeedsFlushInput() override;
   void GestureEventAck(const blink::WebGestureEvent& event,
                        InputEventAckState ack_result) override;
 
@@ -500,6 +501,9 @@
   // Get the focused view that should be used for retrieving the text selection.
   RenderWidgetHostViewBase* GetFocusedViewForTextSelection();
 
+  // Adds/Removes frame observer based on state.
+  void UpdateNeedsBeginFramesInternal();
+
   // The associated view. This is weak and is inserted into the view hierarchy
   // to own this RenderWidgetHostViewMac object. Set to nil at the start of the
   // destructor.
@@ -545,6 +549,12 @@
   gfx::Range composition_range_;
   std::vector<gfx::Rect> composition_bounds_;
 
+  // Whether a request for begin frames has been issued.
+  bool needs_begin_frames_;
+
+  // Whether a request to flush input has been issued.
+  bool needs_flush_input_;
+
   // Factory used to safely scope delayed calls to ShutdownHost().
   base::WeakPtrFactory<RenderWidgetHostViewMac> weak_factory_;
 
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 b5444dc9..fa22008 100644
--- a/content/browser/renderer_host/render_widget_host_view_mac.mm
+++ b/content/browser/renderer_host/render_widget_host_view_mac.mm
@@ -415,6 +415,9 @@
 
 void RenderWidgetHostViewMac::BrowserCompositorMacSendBeginFrame(
     const cc::BeginFrameArgs& args) {
+  needs_flush_input_ = false;
+  render_widget_host_->FlushInput();
+  UpdateNeedsBeginFramesInternal();
   render_widget_host_->Send(
       new ViewMsg_BeginFrame(render_widget_host_->GetRoutingID(), args));
 }
@@ -451,6 +454,8 @@
       allow_pause_for_resize_or_repaint_(true),
       is_guest_view_hack_(is_guest_view_hack),
       fullscreen_parent_host_view_(nullptr),
+      needs_begin_frames_(false),
+      needs_flush_input_(false),
       weak_factory_(this) {
   // |cocoa_view_| owns us and we will be deleted when |cocoa_view_|
   // goes away.  Since we autorelease it, our caller must put
@@ -1188,7 +1193,18 @@
 }
 
 void RenderWidgetHostViewMac::SetNeedsBeginFrames(bool needs_begin_frames) {
-  browser_compositor_->SetNeedsBeginFrames(needs_begin_frames);
+  needs_begin_frames_ = needs_begin_frames;
+  UpdateNeedsBeginFramesInternal();
+}
+
+void RenderWidgetHostViewMac::OnSetNeedsFlushInput() {
+  needs_flush_input_ = true;
+  UpdateNeedsBeginFramesInternal();
+}
+
+void RenderWidgetHostViewMac::UpdateNeedsBeginFramesInternal() {
+  browser_compositor_->SetNeedsBeginFrames(needs_begin_frames_ ||
+                                           needs_flush_input_);
 }
 
 void RenderWidgetHostViewMac::KillSelf() {
diff --git a/content/child/child_thread_impl.cc b/content/child/child_thread_impl.cc
index 26a2c45..3b534c2 100644
--- a/content/child/child_thread_impl.cc
+++ b/content/child/child_thread_impl.cc
@@ -896,11 +896,8 @@
   int32_t routing_id = static_cast<int32_t>(reinterpret_cast<uintptr_t>(
       associated_interface_provider_bindings_.dispatch_context()));
   Listener* route = router_.GetRoute(routing_id);
-  base::debug::Alias(&name);
-  base::debug::Alias(&request);
-  base::debug::Alias(&routing_id);
-  base::debug::Alias(&route);
-  route->OnAssociatedInterfaceRequest(name, request.PassHandle());
+  if (route)
+    route->OnAssociatedInterfaceRequest(name, request.PassHandle());
 }
 
 bool ChildThreadImpl::IsInBrowserProcess() const {
diff --git a/content/public/browser/resource_dispatcher_host_delegate.cc b/content/public/browser/resource_dispatcher_host_delegate.cc
index 229e49f..0928d79 100644
--- a/content/public/browser/resource_dispatcher_host_delegate.cc
+++ b/content/public/browser/resource_dispatcher_host_delegate.cc
@@ -32,8 +32,8 @@
     ResourceContext* resource_context,
     bool is_content_initiated,
     bool must_download,
-    ScopedVector<ResourceThrottle>* throttles) {
-}
+    bool is_new_request,
+    ScopedVector<ResourceThrottle>* throttles) {}
 
 ResourceDispatcherHostLoginDelegate*
     ResourceDispatcherHostDelegate::CreateLoginDelegate(
diff --git a/content/public/browser/resource_dispatcher_host_delegate.h b/content/public/browser/resource_dispatcher_host_delegate.h
index db515bf0..dfaeacd6 100644
--- a/content/public/browser/resource_dispatcher_host_delegate.h
+++ b/content/public/browser/resource_dispatcher_host_delegate.h
@@ -55,10 +55,14 @@
 
   // Allows an embedder to add additional resource handlers for a download.
   // |must_download| is set if the request must be handled as a download.
+  // |is_new_request| is true if this is a call for a new, unstarted request
+  // which also means that RequestBeginning has not been and will not be
+  // called for this request.
   virtual void DownloadStarting(net::URLRequest* request,
                                 ResourceContext* resource_context,
                                 bool is_content_initiated,
                                 bool must_download,
+                                bool is_new_request,
                                 ScopedVector<ResourceThrottle>* throttles);
 
   // Creates a ResourceDispatcherHostLoginDelegate that asks the user for a
diff --git a/content/test/data/navigation_controller/beforeunload_dialog.html b/content/test/data/navigation_controller/beforeunload_dialog.html
new file mode 100644
index 0000000..8e3c825e
--- /dev/null
+++ b/content/test/data/navigation_controller/beforeunload_dialog.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+<script>
+window.addEventListener("beforeunload", function (event) {
+  setTimeout(function() {
+    window.alert("hi");
+  }, 0);
+});
+</script>
+</head>
+<body>
+</body>
+</html>
diff --git a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
index dbf43ef..e5498dc 100644
--- a/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
+++ b/content/test/gpu/gpu_tests/webgl2_conformance_expectations.py
@@ -511,7 +511,7 @@
                'tex-2d-rgb-rgb-unsigned_short_5_6_5.html',
                ['linux'], bug=627525)
 
-    # Multi-vendor failures.
+    # Linux Multi-vendor failures.
 
     self.Fail('deqp/data/gles3/shaders/functions.html',
         ['linux', 'amd', 'intel'], bug=483282)
@@ -525,12 +525,6 @@
     self.Fail('deqp/data/gles3/shaders/linkage.html',
         ['linux', 'amd', 'intel'], bug=483282)
 
-    # Linux with ANGLE only
-    self.Fail('conformance2/textures/misc/tex-unpack-params.html',
-        ['linux', 'opengl'], bug=483282)
-    self.Fail('conformance2/reading/read-pixels-pack-parameters.html',
-        ['linux', 'opengl'], bug=483282)
-
     # Linux without ANGLE only
     self.Flaky('conformance2/buffers/getBufferSubData.html',
                ['linux', 'no_angle'], bug=650123)
diff --git a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
index cf81ae5..8c57b5c 100644
--- a/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
+++ b/extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder_svc.cc
@@ -6,6 +6,7 @@
 
 #include "base/bind.h"
 #include "base/task_runner_util.h"
+#include "base/threading/thread.h"
 #include "base/threading/thread_task_runner_handle.h"
 #include "extensions/renderer/api/display_source/wifi_display/wifi_display_video_encoder.h"
 #include "third_party/openh264/src/codec/api/svc/codec_api.h"
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc b/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc
index 86855a8..8e84b7d 100644
--- a/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc
+++ b/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.cc
@@ -35,8 +35,7 @@
     : GpuMemoryBufferImpl(id, size, format, callback),
       pixmap_(std::move(pixmap)),
       planes_(planes),
-      fd_(std::move(fd)),
-      data_(nullptr) {}
+      fd_(std::move(fd)) {}
 
 GpuMemoryBufferImplOzoneNativePixmap::~GpuMemoryBufferImplOzoneNativePixmap() {}
 
@@ -101,33 +100,24 @@
 
 bool GpuMemoryBufferImplOzoneNativePixmap::Map() {
   DCHECK(!mapped_);
-  DCHECK(!data_);
-  data_ = pixmap_->Map();
-  if (!data_)
-    return false;
-  mapped_ = true;
+  mapped_ = pixmap_->Map();
   return mapped_;
 }
 
 void* GpuMemoryBufferImplOzoneNativePixmap::memory(size_t plane) {
   DCHECK(mapped_);
-  DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_));
-  return data_;
+  return pixmap_->GetMemoryAddress(plane);
 }
 
 void GpuMemoryBufferImplOzoneNativePixmap::Unmap() {
   DCHECK(mapped_);
-  DCHECK(data_);
   pixmap_->Unmap();
   mapped_ = false;
-  data_ = nullptr;
 }
 
 int GpuMemoryBufferImplOzoneNativePixmap::stride(size_t plane) const {
   DCHECK_LT(plane, gfx::NumberOfPlanesForBufferFormat(format_));
-  int stride;
-  pixmap_->GetStride(&stride);
-  return stride;
+  return pixmap_->GetStride(plane);
 }
 
 gfx::GpuMemoryBufferHandle GpuMemoryBufferImplOzoneNativePixmap::GetHandle()
diff --git a/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h b/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h
index 450d102..50ececf 100644
--- a/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h
+++ b/gpu/ipc/client/gpu_memory_buffer_impl_ozone_native_pixmap.h
@@ -60,7 +60,6 @@
   std::unique_ptr<ui::ClientNativePixmap> pixmap_;
   std::vector<gfx::NativePixmapPlane> planes_;
   base::ScopedFD fd_;
-  void* data_;
 
   DISALLOW_COPY_AND_ASSIGN(GpuMemoryBufferImplOzoneNativePixmap);
 };
diff --git a/infra/config/recipes.cfg b/infra/config/recipes.cfg
index 8aaba70..675bcd00 100644
--- a/infra/config/recipes.cfg
+++ b/infra/config/recipes.cfg
@@ -5,13 +5,13 @@
   project_id: "build"
   url: "https://chromium.googlesource.com/chromium/tools/build.git"
   branch: "master"
-  revision: "567475a8f817b58253b6e305bf5eb5c980f04bc6"
+  revision: "046b3dd73b69f40caec94eddedfbb0221d15cb74"
 }
 deps {
   project_id: "depot_tools"
   url: "https://chromium.googlesource.com/chromium/tools/depot_tools.git"
   branch: "master"
-  revision: "3e1cde7a87d6cb600d6bf3b5860b72da8c121c59"
+  revision: "3574740929abd37c45db1d2f8a2c3799bdfe77c5"
 }
 deps {
   project_id: "recipe_engine"
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index 42c306f..7583843 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -112,6 +112,16 @@
     "webui/url_data_manager_ios_backend.h",
     "webui/url_data_manager_ios_backend.mm",
     "webui/url_data_source_ios.mm",
+    "webui/url_data_source_ios_impl.cc",
+    "webui/url_data_source_ios_impl.h",
+    "webui/url_fetcher_block_adapter.h",
+    "webui/url_fetcher_block_adapter.mm",
+    "webui/web_ui_ios_controller_factory_registry.cc",
+    "webui/web_ui_ios_controller_factory_registry.h",
+    "webui/web_ui_ios_data_source_impl.h",
+    "webui/web_ui_ios_data_source_impl.mm",
+    "webui/web_ui_ios_impl.h",
+    "webui/web_ui_ios_impl.mm",
   ]
 
   libs = [ "WebKit.framework" ]
@@ -282,16 +292,6 @@
     "web_state/web_view_internal_creation_util.mm",
     "web_state/wk_web_view_security_util.h",
     "web_state/wk_web_view_security_util.mm",
-    "webui/url_data_source_ios_impl.cc",
-    "webui/url_data_source_ios_impl.h",
-    "webui/url_fetcher_block_adapter.h",
-    "webui/url_fetcher_block_adapter.mm",
-    "webui/web_ui_ios_controller_factory_registry.cc",
-    "webui/web_ui_ios_controller_factory_registry.h",
-    "webui/web_ui_ios_data_source_impl.h",
-    "webui/web_ui_ios_data_source_impl.mm",
-    "webui/web_ui_ios_impl.h",
-    "webui/web_ui_ios_impl.mm",
   ]
 
   libs = [ "WebKit.framework" ]
diff --git a/ios/web/webui/url_fetcher_block_adapter.mm b/ios/web/webui/url_fetcher_block_adapter.mm
index deb6178a..df7e1fa 100644
--- a/ios/web/webui/url_fetcher_block_adapter.mm
+++ b/ios/web/webui/url_fetcher_block_adapter.mm
@@ -8,6 +8,10 @@
 #include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_context_getter.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 URLFetcherBlockAdapter::URLFetcherBlockAdapter(
diff --git a/ios/web/webui/web_ui_ios_data_source_impl.mm b/ios/web/webui/web_ui_ios_data_source_impl.mm
index 1f44034..efb9e793 100644
--- a/ios/web/webui/web_ui_ios_data_source_impl.mm
+++ b/ios/web/webui/web_ui_ios_data_source_impl.mm
@@ -13,6 +13,10 @@
 #include "ui/base/webui/jstemplate_builder.h"
 #include "ui/base/webui/web_ui_util.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 namespace web {
 
 // static
diff --git a/ios/web/webui/web_ui_ios_impl.mm b/ios/web/webui/web_ui_ios_impl.mm
index 619b2e6..9123ed3 100644
--- a/ios/web/webui/web_ui_ios_impl.mm
+++ b/ios/web/webui/web_ui_ios_impl.mm
@@ -15,6 +15,10 @@
 #include "ios/web/public/webui/web_ui_ios_message_handler.h"
 #include "ios/web/web_state/web_state_impl.h"
 
+#if !defined(__has_feature) || !__has_feature(objc_arc)
+#error "This file requires ARC support."
+#endif
+
 using web::WebUIIOSController;
 
 namespace web {
diff --git a/media/capture/BUILD.gn b/media/capture/BUILD.gn
index a6340f5..d5ebd5c6 100644
--- a/media/capture/BUILD.gn
+++ b/media/capture/BUILD.gn
@@ -47,12 +47,22 @@
     "video/mac/video_capture_device_mac.h",
     "video/mac/video_capture_device_mac.mm",
     "video/scoped_result_callback.h",
+    "video/video_capture_buffer_handle.h",
+    "video/video_capture_buffer_pool.h",
+    "video/video_capture_buffer_pool_impl.cc",
+    "video/video_capture_buffer_pool_impl.h",
+    "video/video_capture_buffer_tracker.h",
+    "video/video_capture_buffer_tracker_factory.h",
     "video/video_capture_device.cc",
     "video/video_capture_device.h",
+    "video/video_capture_device_client.cc",
+    "video/video_capture_device_client.h",
     "video/video_capture_device_descriptor.cc",
     "video/video_capture_device_descriptor.h",
     "video/video_capture_device_factory.cc",
     "video/video_capture_device_factory.h",
+    "video/video_capture_jpeg_decoder.h",
+    "video/video_frame_receiver.h",
     "video/win/capability_list_win.cc",
     "video/win/capability_list_win.h",
     "video/win/filter_base_win.cc",
@@ -79,6 +89,7 @@
     "//media",
     "//media/mojo/interfaces:image_capture",
     "//skia",
+    "//third_party/libyuv",
     "//ui/display",
     "//ui/gfx",
   ]
@@ -138,7 +149,6 @@
       "video/blob_utils.cc",
       "video/blob_utils.h",
     ]
-    deps += [ "//third_party/libyuv" ]
   }
 }
 
diff --git a/media/capture/video/DEPS b/media/capture/video/DEPS
index 896f509..6ed765f7 100644
--- a/media/capture/video/DEPS
+++ b/media/capture/video/DEPS
@@ -1,3 +1,4 @@
 include_rules = [
   "+mojo/public/cpp/bindings",
-]
\ No newline at end of file
+  "+third_party/libyuv",
+]
diff --git a/content/browser/renderer_host/media/video_capture_buffer_handle.h b/media/capture/video/video_capture_buffer_handle.h
similarity index 68%
rename from content/browser/renderer_host/media/video_capture_buffer_handle.h
rename to media/capture/video/video_capture_buffer_handle.h
index 1e17004..d9c4cc62 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_handle.h
+++ b/media/capture/video/video_capture_buffer_handle.h
@@ -2,17 +2,18 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_HANDLE_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_HANDLE_H_
+#ifndef MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_BUFFER_HANDLE_H_
+#define MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_BUFFER_HANDLE_H_
 
 #include "base/files/file.h"
+#include "media/capture/capture_export.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
-namespace content {
+namespace media {
 
 // Abstraction of a pool's buffer data buffer and size for clients.
-class VideoCaptureBufferHandle {
+class CAPTURE_EXPORT VideoCaptureBufferHandle {
  public:
   virtual ~VideoCaptureBufferHandle() {}
   virtual gfx::Size dimensions() const = 0;
@@ -24,6 +25,6 @@
 #endif
 };
 
-}  // namespace content
+}  // namespace media
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_HANDLE_H_
+#endif  // MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_BUFFER_HANDLE_H_
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool.h b/media/capture/video/video_capture_buffer_pool.h
similarity index 62%
rename from content/browser/renderer_host/media/video_capture_buffer_pool.h
rename to media/capture/video/video_capture_buffer_pool.h
index 4dc59ac..0f0a4920 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool.h
+++ b/media/capture/video/video_capture_buffer_pool.h
@@ -1,33 +1,41 @@
-// Copyright (c) 2013 The Chromium Authors. All rights reserved.
+// Copyright 2016 The Chromium 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_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_
+#ifndef MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_H_
 
-#include <stddef.h>
-
-#include <map>
-
-#include "base/files/file.h"
-#include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "base/memory/shared_memory.h"
-#include "base/process/process.h"
-#include "base/synchronization/lock.h"
-#include "build/build_config.h"
-#include "content/common/content_export.h"
 #include "media/base/video_capture_types.h"
-#include "media/base/video_frame.h"
+#include "media/capture/capture_export.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gpu_memory_buffer.h"
 
-namespace content {
+namespace media {
 
 class VideoCaptureBufferHandle;
-class VideoCaptureBufferTracker;
 
-class CONTENT_EXPORT VideoCaptureBufferPool
+// A thread-safe class that does the bookkeeping and lifetime management for a
+// pool of pixel buffers cycled between an in-process producer (e.g. a
+// VideoCaptureDevice) and a set of out-of-process consumers. The pool is
+// intended to be orchestrated by a VideoCaptureDevice::Client, but is designed
+// to outlive the controller if necessary. The pixel buffers may be backed by a
+// SharedMemory, but this is not compulsory.
+//
+// Producers get a buffer by calling ReserveForProducer(), and may pass on their
+// ownership to the consumer by calling HoldForConsumers(), or drop the buffer
+// (without further processing) by calling RelinquishProducerReservation().
+// Consumers signal that they are done with the buffer by calling
+// RelinquishConsumerHold().
+//
+// Buffers are allocated on demand, but there will never be more than |count|
+// buffers in existence at any time. Buffers are identified by an int value
+// called |buffer_id|. -1 (kInvalidId) is never a valid ID, and is returned by
+// some methods to indicate failure. The active set of buffer ids may change
+// over the lifetime of the buffer pool, as existing buffers are freed and
+// reallocated at larger size. When reallocation occurs, new buffer IDs will
+// circulate.
+class CAPTURE_EXPORT VideoCaptureBufferPool
     : public base::RefCountedThreadSafe<VideoCaptureBufferPool> {
  public:
   static constexpr int kInvalidId = -1;
@@ -102,84 +110,6 @@
   friend class base::RefCountedThreadSafe<VideoCaptureBufferPool>;
 };
 
-// A thread-safe class that does the bookkeeping and lifetime management for a
-// pool of pixel buffers cycled between an in-process producer (e.g. a
-// VideoCaptureDevice) and a set of out-of-process consumers. The pool is
-// intended to be orchestrated by a VideoCaptureDevice::Client, but is designed
-// to outlive the controller if necessary. The pixel buffers may be backed by a
-// SharedMemory, but this is not compulsory.
-//
-// Producers get a buffer by calling ReserveForProducer(), and may pass on their
-// ownership to the consumer by calling HoldForConsumers(), or drop the buffer
-// (without further processing) by calling RelinquishProducerReservation().
-// Consumers signal that they are done with the buffer by calling
-// RelinquishConsumerHold().
-//
-// Buffers are allocated on demand, but there will never be more than |count|
-// buffers in existence at any time. Buffers are identified by an int value
-// called |buffer_id|. -1 (kInvalidId) is never a valid ID, and is returned by
-// some methods to indicate failure. The active set of buffer ids may change
-// over the lifetime of the buffer pool, as existing buffers are freed and
-// reallocated at larger size. When reallocation occurs, new buffer IDs will
-// circulate.
-class CONTENT_EXPORT VideoCaptureBufferPoolImpl
-    : public VideoCaptureBufferPool {
- public:
-  explicit VideoCaptureBufferPoolImpl(int count);
+}  // namespace media
 
-  // Implementation of VideoCaptureBufferPool interface:
-  bool ShareToProcess(int buffer_id,
-                      base::ProcessHandle process_handle,
-                      base::SharedMemoryHandle* new_handle) override;
-  bool ShareToProcess2(int buffer_id,
-                       int plane,
-                       base::ProcessHandle process_handle,
-                       gfx::GpuMemoryBufferHandle* new_handle) override;
-  std::unique_ptr<VideoCaptureBufferHandle> GetBufferHandle(
-      int buffer_id) override;
-  int ReserveForProducer(const gfx::Size& dimensions,
-                         media::VideoPixelFormat format,
-                         media::VideoPixelStorage storage,
-                         int* buffer_id_to_drop) override;
-  void RelinquishProducerReservation(int buffer_id) override;
-  int ResurrectLastForProducer(const gfx::Size& dimensions,
-                               media::VideoPixelFormat format,
-                               media::VideoPixelStorage storage) override;
-  double GetBufferPoolUtilization() const override;
-  void HoldForConsumers(int buffer_id, int num_clients) override;
-  void RelinquishConsumerHold(int buffer_id, int num_clients) override;
-
- private:
-  friend class base::RefCountedThreadSafe<VideoCaptureBufferPoolImpl>;
-  ~VideoCaptureBufferPoolImpl() override;
-
-  int ReserveForProducerInternal(const gfx::Size& dimensions,
-                                 media::VideoPixelFormat format,
-                                 media::VideoPixelStorage storage,
-                                 int* tracker_id_to_drop);
-
-  VideoCaptureBufferTracker* GetTracker(int buffer_id);
-
-  // The max number of buffers that the pool is allowed to have at any moment.
-  const int count_;
-
-  // Protects everything below it.
-  mutable base::Lock lock_;
-
-  // The ID of the next buffer.
-  int next_buffer_id_;
-
-  // The ID of the buffer last relinquished by the producer (a candidate for
-  // resurrection).
-  int last_relinquished_buffer_id_;
-
-  // The buffers, indexed by the first parameter, a buffer id.
-  using TrackerMap = std::map<int, VideoCaptureBufferTracker*>;
-  TrackerMap trackers_;
-
-  DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureBufferPoolImpl);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_POOL_H_
+#endif  // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_H_
diff --git a/content/browser/renderer_host/media/video_capture_buffer_pool.cc b/media/capture/video/video_capture_buffer_pool_impl.cc
similarity index 93%
rename from content/browser/renderer_host/media/video_capture_buffer_pool.cc
rename to media/capture/video/video_capture_buffer_pool_impl.cc
index bc335a8c..cce7ef0 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_pool.cc
+++ b/media/capture/video/video_capture_buffer_pool_impl.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 "content/browser/renderer_host/media/video_capture_buffer_pool.h"
+#include "media/capture/video/video_capture_buffer_pool_impl.h"
 
 #include <memory>
 
@@ -10,17 +10,19 @@
 #include "base/memory/ptr_util.h"
 #include "base/stl_util.h"
 #include "build/build_config.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_tracker_factory.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_tracker.h"
 #include "ui/gfx/buffer_format_util.h"
 
-namespace content {
+namespace media {
 
-VideoCaptureBufferPoolImpl::VideoCaptureBufferPoolImpl(int count)
+VideoCaptureBufferPoolImpl::VideoCaptureBufferPoolImpl(
+    std::unique_ptr<VideoCaptureBufferTrackerFactory> buffer_tracker_factory,
+    int count)
     : count_(count),
       next_buffer_id_(0),
-      last_relinquished_buffer_id_(kInvalidId) {
+      last_relinquished_buffer_id_(kInvalidId),
+      buffer_tracker_factory_(std::move(buffer_tracker_factory)) {
   DCHECK_GT(count, 0);
 }
 
@@ -236,7 +238,7 @@
   const int buffer_id = next_buffer_id_++;
 
   std::unique_ptr<VideoCaptureBufferTracker> tracker =
-      VideoCaptureBufferTrackerFactory::CreateTracker(storage_type);
+      buffer_tracker_factory_->CreateTracker(storage_type);
   // TODO(emircan): We pass the lock here to solve GMB allocation issue, see
   // crbug.com/545238.
   if (!tracker->Init(dimensions, pixel_format, storage_type, &lock_)) {
@@ -256,4 +258,4 @@
   return (it == trackers_.end()) ? NULL : it->second;
 }
 
-}  // namespace content
+}  // namespace media
diff --git a/media/capture/video/video_capture_buffer_pool_impl.h b/media/capture/video/video_capture_buffer_pool_impl.h
new file mode 100644
index 0000000..aa94367
--- /dev/null
+++ b/media/capture/video/video_capture_buffer_pool_impl.h
@@ -0,0 +1,95 @@
+// Copyright (c) 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 MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_IMPL_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_IMPL_H_
+
+#include <stddef.h>
+
+#include <map>
+
+#include "base/files/file.h"
+#include "base/macros.h"
+#include "base/memory/ref_counted.h"
+#include "base/memory/shared_memory.h"
+#include "base/process/process.h"
+#include "base/synchronization/lock.h"
+#include "build/build_config.h"
+#include "media/base/video_capture_types.h"
+#include "media/base/video_frame.h"
+#include "media/capture/capture_export.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_pool.h"
+#include "media/capture/video/video_capture_buffer_tracker_factory.h"
+#include "ui/gfx/geometry/size.h"
+#include "ui/gfx/gpu_memory_buffer.h"
+
+namespace media {
+
+class CAPTURE_EXPORT VideoCaptureBufferPoolImpl
+    : public VideoCaptureBufferPool {
+ public:
+  explicit VideoCaptureBufferPoolImpl(
+      std::unique_ptr<VideoCaptureBufferTrackerFactory> buffer_tracker_factory,
+      int count);
+
+  // Implementation of VideoCaptureBufferPool interface:
+  bool ShareToProcess(int buffer_id,
+                      base::ProcessHandle process_handle,
+                      base::SharedMemoryHandle* new_handle) override;
+  bool ShareToProcess2(int buffer_id,
+                       int plane,
+                       base::ProcessHandle process_handle,
+                       gfx::GpuMemoryBufferHandle* new_handle) override;
+  std::unique_ptr<VideoCaptureBufferHandle> GetBufferHandle(
+      int buffer_id) override;
+  int ReserveForProducer(const gfx::Size& dimensions,
+                         media::VideoPixelFormat format,
+                         media::VideoPixelStorage storage,
+                         int* buffer_id_to_drop) override;
+  void RelinquishProducerReservation(int buffer_id) override;
+  int ResurrectLastForProducer(const gfx::Size& dimensions,
+                               media::VideoPixelFormat format,
+                               media::VideoPixelStorage storage) override;
+  double GetBufferPoolUtilization() const override;
+  void HoldForConsumers(int buffer_id, int num_clients) override;
+  void RelinquishConsumerHold(int buffer_id, int num_clients) override;
+
+ private:
+  friend class base::RefCountedThreadSafe<VideoCaptureBufferPoolImpl>;
+  ~VideoCaptureBufferPoolImpl() override;
+
+  int ReserveForProducerInternal(const gfx::Size& dimensions,
+                                 media::VideoPixelFormat format,
+                                 media::VideoPixelStorage storage,
+                                 int* tracker_id_to_drop);
+
+  VideoCaptureBufferTracker* GetTracker(int buffer_id);
+
+  // The max number of buffers that the pool is allowed to have at any moment.
+  const int count_;
+
+  // Protects everything below it.
+  mutable base::Lock lock_;
+
+  // The ID of the next buffer.
+  int next_buffer_id_;
+
+  // The ID of the buffer last relinquished by the producer (a candidate for
+  // resurrection).
+  int last_relinquished_buffer_id_;
+
+  // The buffers, indexed by the first parameter, a buffer id.
+  using TrackerMap = std::map<int, VideoCaptureBufferTracker*>;
+  TrackerMap trackers_;
+
+  const std::unique_ptr<VideoCaptureBufferTrackerFactory>
+      buffer_tracker_factory_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(VideoCaptureBufferPoolImpl);
+};
+
+}  // namespace media
+
+#endif  // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_POOL_IMPL_H_
diff --git a/content/browser/renderer_host/media/video_capture_buffer_tracker.h b/media/capture/video/video_capture_buffer_tracker.h
similarity index 88%
rename from content/browser/renderer_host/media/video_capture_buffer_tracker.h
rename to media/capture/video/video_capture_buffer_tracker.h
index 182d42f..778459209 100644
--- a/content/browser/renderer_host/media/video_capture_buffer_tracker.h
+++ b/media/capture/video/video_capture_buffer_tracker.h
@@ -2,22 +2,22 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_H_
+#ifndef MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_H_
 
 #include <memory>
 
 #include "base/synchronization/lock.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
 #include "media/base/video_capture_types.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
 
-namespace content {
+namespace media {
 
 // Keeps track of the state of a given mappable resource. Each
 // VideoCaptureBufferTracker carries indication of pixel format and storage
 // type. This is a base class for implementations using different kinds of
 // storage.
-class VideoCaptureBufferTracker {
+class CAPTURE_EXPORT VideoCaptureBufferTracker {
  public:
   VideoCaptureBufferTracker()
       : max_pixel_count_(0),
@@ -75,4 +75,4 @@
 
 }  // namespace content
 
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_BUFFER_TRACKER_H_
+#endif  // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_H_
diff --git a/media/capture/video/video_capture_buffer_tracker_factory.h b/media/capture/video/video_capture_buffer_tracker_factory.h
new file mode 100644
index 0000000..2828a5b
--- /dev/null
+++ b/media/capture/video/video_capture_buffer_tracker_factory.h
@@ -0,0 +1,26 @@
+// Copyright (c) 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 MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
+#define MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
+
+#include <memory>
+
+#include "media/base/video_capture_types.h"
+#include "media/capture/capture_export.h"
+
+namespace media {
+
+class VideoCaptureBufferTracker;
+
+class CAPTURE_EXPORT VideoCaptureBufferTrackerFactory {
+ public:
+  virtual ~VideoCaptureBufferTrackerFactory() {}
+  virtual std::unique_ptr<VideoCaptureBufferTracker> CreateTracker(
+      VideoPixelStorage storage_type) = 0;
+};
+
+}  // namespace media
+
+#endif  // MEDIA_VIDEO_CAPTURE_VIDEO_CAPTURE_BUFFER_TRACKER_FACTORY_H_
diff --git a/content/browser/renderer_host/media/video_capture_device_client.cc b/media/capture/video/video_capture_device_client.cc
similarity index 88%
rename from content/browser/renderer_host/media/video_capture_device_client.cc
rename to media/capture/video/video_capture_device_client.cc
index a70f5992..368af81 100644
--- a/content/browser/renderer_host/media/video_capture_device_client.cc
+++ b/media/capture/video/video_capture_device_client.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 "content/browser/renderer_host/media/video_capture_device_client.h"
+#include "media/capture/video/video_capture_device_client.h"
 
 #include <algorithm>
 #include <utility>
@@ -14,21 +14,21 @@
 #include "base/strings/stringprintf.h"
 #include "base/trace_event/trace_event.h"
 #include "build/build_config.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_handle.h"
-#include "content/browser/renderer_host/media/video_capture_buffer_pool.h"
-#include "content/browser/renderer_host/media/video_capture_controller.h"
-#include "content/browser/renderer_host/media/video_capture_gpu_jpeg_decoder.h"
 #include "media/base/bind_to_current_loop.h"
 #include "media/base/media_switches.h"
 #include "media/base/video_capture_types.h"
 #include "media/base/video_frame.h"
+#include "media/capture/video/video_capture_buffer_handle.h"
+#include "media/capture/video/video_capture_buffer_pool.h"
+#include "media/capture/video/video_capture_jpeg_decoder.h"
+#include "media/capture/video/video_frame_receiver.h"
 #include "third_party/libyuv/include/libyuv.h"
 
 using media::VideoCaptureFormat;
 using media::VideoFrame;
 using media::VideoFrameMetadata;
 
-namespace content {
+namespace media {
 
 // Class combining a Client::Buffer interface implementation and a pool buffer
 // implementation to guarantee proper cleanup on destruction on our side.
@@ -118,8 +118,8 @@
   if (rotation == 90 || rotation == 270)
     std::swap(destination_width, destination_height);
 
-  DCHECK_EQ(0, rotation % 90)
-      << " Rotation must be a multiple of 90, now: " << rotation;
+  DCHECK_EQ(0, rotation % 90) << " Rotation must be a multiple of 90, now: "
+                              << rotation;
   libyuv::RotationMode rotation_mode = libyuv::kRotate0;
   if (rotation == 90)
     rotation_mode = libyuv::kRotate90;
@@ -180,10 +180,10 @@
       origin_colorspace = libyuv::FOURCC_UYVY;
       break;
     case media::PIXEL_FORMAT_RGB24:
-      // Linux RGB24 defines red at lowest byte address,
-      // see http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html.
-      // Windows RGB24 defines blue at lowest byte,
-      // see https://msdn.microsoft.com/en-us/library/windows/desktop/dd407253
+// Linux RGB24 defines red at lowest byte address,
+// see http://linuxtv.org/downloads/v4l-dvb-apis/packed-rgb.html.
+// Windows RGB24 defines blue at lowest byte,
+// see https://msdn.microsoft.com/en-us/library/windows/desktop/dd407253
 #if defined(OS_LINUX)
       origin_colorspace = libyuv::FOURCC_RAW;
 #elif defined(OS_WIN)
@@ -220,13 +220,13 @@
   DCHECK_GE(static_cast<size_t>(length), frame_format.ImageAllocationSize());
 
   if (external_jpeg_decoder_) {
-    const VideoCaptureGpuJpegDecoder::STATUS status =
+    const VideoCaptureJpegDecoder::STATUS status =
         external_jpeg_decoder_->GetStatus();
-    if (status == VideoCaptureGpuJpegDecoder::FAILED) {
+    if (status == VideoCaptureJpegDecoder::FAILED) {
       external_jpeg_decoder_.reset();
-    } else if (status == VideoCaptureGpuJpegDecoder::INIT_PASSED &&
-        frame_format.pixel_format == media::PIXEL_FORMAT_MJPEG &&
-        rotation == 0 && !flip) {
+    } else if (status == VideoCaptureJpegDecoder::INIT_PASSED &&
+               frame_format.pixel_format == media::PIXEL_FORMAT_MJPEG &&
+               rotation == 0 && !flip) {
       external_jpeg_decoder_->DecodeCapturedData(data, length, frame_format,
                                                  reference_time, timestamp,
                                                  std::move(buffer));
@@ -234,30 +234,21 @@
     }
   }
 
-  if (libyuv::ConvertToI420(data,
-                            length,
-                            y_plane_data,
-                            yplane_stride,
-                            u_plane_data,
-                            uv_plane_stride,
-                            v_plane_data,
-                            uv_plane_stride,
-                            crop_x,
-                            crop_y,
+  if (libyuv::ConvertToI420(data, length, y_plane_data, yplane_stride,
+                            u_plane_data, uv_plane_stride, v_plane_data,
+                            uv_plane_stride, crop_x, crop_y,
                             frame_format.frame_size.width(),
                             (flip ? -1 : 1) * frame_format.frame_size.height(),
-                            new_unrotated_width,
-                            new_unrotated_height,
-                            rotation_mode,
-                            origin_colorspace) != 0) {
+                            new_unrotated_width, new_unrotated_height,
+                            rotation_mode, origin_colorspace) != 0) {
     DLOG(WARNING) << "Failed to convert buffer's pixel format to I420 from "
                   << media::VideoPixelFormatToString(frame_format.pixel_format);
     return;
   }
 
-  const VideoCaptureFormat output_format = VideoCaptureFormat(
-      dimensions, frame_format.frame_rate,
-      media::PIXEL_FORMAT_I420, output_pixel_storage);
+  const VideoCaptureFormat output_format =
+      VideoCaptureFormat(dimensions, frame_format.frame_rate,
+                         media::PIXEL_FORMAT_I420, output_pixel_storage);
   OnIncomingCapturedBuffer(std::move(buffer), output_format, reference_time,
                            timestamp);
 }
@@ -358,8 +349,7 @@
   receiver_->OnError();
 }
 
-void VideoCaptureDeviceClient::OnLog(
-    const std::string& message) {
+void VideoCaptureDeviceClient::OnLog(const std::string& message) {
   receiver_->OnLog(message);
 }
 
@@ -412,4 +402,4 @@
   return std::unique_ptr<Buffer>();
 }
 
-}  // namespace content
+}  // namespace media
diff --git a/content/browser/renderer_host/media/video_capture_device_client.h b/media/capture/video/video_capture_device_client.h
similarity index 92%
rename from content/browser/renderer_host/media/video_capture_device_client.h
rename to media/capture/video/video_capture_device_client.h
index ac63f8b..821c58d 100644
--- a/content/browser/renderer_host/media/video_capture_device_client.h
+++ b/media/capture/video/video_capture_device_client.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
-#define CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
+#ifndef MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_DEVICE_CLIENT_H_
+#define MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_DEVICE_CLIENT_H_
 
 #include <stddef.h>
 #include <stdint.h>
@@ -13,10 +13,10 @@
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
 #include "base/memory/weak_ptr.h"
-#include "content/common/content_export.h"
+#include "media/capture/capture_export.h"
 #include "media/capture/video/video_capture_device.h"
 
-namespace content {
+namespace media {
 class VideoCaptureBufferPool;
 class VideoFrameReceiver;
 class VideoCaptureJpegDecoder;
@@ -39,7 +39,7 @@
 // GpuMemoryBuffers into Texture backed VideoFrames. This class creates and
 // manages the necessary entities to interact with the GPU process, notably an
 // offscreen Context to avoid janking the UI thread.
-class CONTENT_EXPORT VideoCaptureDeviceClient
+class CAPTURE_EXPORT VideoCaptureDeviceClient
     : public media::VideoCaptureDevice::Client,
       public base::SupportsWeakPtr<VideoCaptureDeviceClient> {
  public:
@@ -125,7 +125,6 @@
   DISALLOW_COPY_AND_ASSIGN(VideoCaptureDeviceClient);
 };
 
+}  // namespace media
 
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_RENDERER_HOST_MEDIA_VIDEO_CAPTURE_DEVICE_CLIENT_H_
+#endif  // MEDIA_CAPTURE_VIDEO_VIDEO_CAPTURE_DEVICE_CLIENT_H_
diff --git a/media/capture/video/video_capture_jpeg_decoder.h b/media/capture/video/video_capture_jpeg_decoder.h
new file mode 100644
index 0000000..e9d91dc
--- /dev/null
+++ b/media/capture/video/video_capture_jpeg_decoder.h
@@ -0,0 +1,45 @@
+// Copyright 2016 The Chromium 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/callback.h"
+#include "media/capture/capture_export.h"
+#include "media/capture/video/video_capture_device.h"
+
+namespace media {
+
+class CAPTURE_EXPORT VideoCaptureJpegDecoder {
+ public:
+  // Enumeration of decoder status. The enumeration is published for clients to
+  // decide the behavior according to STATUS.
+  enum STATUS {
+    INIT_PENDING,  // Default value while waiting initialization finished.
+    INIT_PASSED,   // Initialization succeed.
+    FAILED,        // JPEG decode is not supported, initialization failed, or
+                   // decode error.
+  };
+
+  using DecodeDoneCB = base::Callback<void(
+      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>,
+      const scoped_refptr<media::VideoFrame>&)>;
+
+  virtual ~VideoCaptureJpegDecoder() {}
+
+  // Creates and intializes decoder asynchronously.
+  virtual void Initialize() = 0;
+
+  // Returns initialization status.
+  virtual STATUS GetStatus() const = 0;
+
+  // Decodes a JPEG picture.
+  virtual void DecodeCapturedData(
+      const uint8_t* data,
+      size_t in_buffer_size,
+      const media::VideoCaptureFormat& frame_format,
+      base::TimeTicks reference_time,
+      base::TimeDelta timestamp,
+      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer>
+          out_buffer) = 0;
+};
+
+}  // namespace media
diff --git a/media/capture/video/video_frame_receiver.h b/media/capture/video/video_frame_receiver.h
new file mode 100644
index 0000000..df2dabc
--- /dev/null
+++ b/media/capture/video/video_frame_receiver.h
@@ -0,0 +1,24 @@
+// Copyright 2016 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/capture/capture_export.h"
+#include "media/capture/video/video_capture_device.h"
+
+namespace media {
+
+// Callback interface for VideoCaptureDeviceClient to communicate with its
+// clients.
+class CAPTURE_EXPORT VideoFrameReceiver {
+ public:
+  virtual ~VideoFrameReceiver(){};
+
+  virtual void OnIncomingCapturedVideoFrame(
+      std::unique_ptr<media::VideoCaptureDevice::Client::Buffer> buffer,
+      const scoped_refptr<media::VideoFrame>& frame) = 0;
+  virtual void OnError() = 0;
+  virtual void OnLog(const std::string& message) = 0;
+  virtual void OnBufferDestroyed(int buffer_id_to_drop) = 0;
+};
+
+}  // namespace media
diff --git a/media/gpu/video_decode_accelerator_unittest.cc b/media/gpu/video_decode_accelerator_unittest.cc
index 70bc4399..aa905e71 100644
--- a/media/gpu/video_decode_accelerator_unittest.cc
+++ b/media/gpu/video_decode_accelerator_unittest.cc
@@ -372,7 +372,7 @@
   handle.native_pixmap_handle.fds.emplace_back(
       base::FileDescriptor(duped_fd, true));
   handle.native_pixmap_handle.planes.emplace_back(
-      pixmap_->GetDmaBufPitch(0), pixmap_->GetDmaBufOffset(0),
+      pixmap_->GetDmaBufPitch(0), pixmap_->GetDmaBufOffset(0), 0,
       pixmap_->GetDmaBufModifier(0));
 #endif
   return handle;
diff --git a/net/quic/core/congestion_control/general_loss_algorithm.cc b/net/quic/core/congestion_control/general_loss_algorithm.cc
index 6415f2c..6c82329a 100644
--- a/net/quic/core/congestion_control/general_loss_algorithm.cc
+++ b/net/quic/core/congestion_control/general_loss_algorithm.cc
@@ -87,7 +87,10 @@
     // there are retransmittable packets in flight.
     // This also implements a timer-protected variant of FACK.
     if ((!it->retransmittable_frames.empty() &&
-         unacked_packets.largest_sent_packet() == largest_newly_acked) ||
+         (FLAGS_quic_largest_sent_retransmittable
+              ? unacked_packets.largest_sent_retransmittable_packet()
+              : unacked_packets.largest_sent_packet()) <=
+             largest_newly_acked) ||
         (loss_type_ == kTime || loss_type_ == kAdaptiveTime)) {
       QuicTime when_lost = it->sent_time + loss_delay;
       if (time < when_lost) {
diff --git a/net/quic/core/congestion_control/general_loss_algorithm_test.cc b/net/quic/core/congestion_control/general_loss_algorithm_test.cc
index fef1ccb..107674d 100644
--- a/net/quic/core/congestion_control/general_loss_algorithm_test.cc
+++ b/net/quic/core/congestion_control/general_loss_algorithm_test.cc
@@ -44,6 +44,14 @@
                                    true);
   }
 
+  void SendAckPacket(QuicPacketNumber packet_number) {
+    SerializedPacket packet(kDefaultPathId, packet_number,
+                            PACKET_1BYTE_PACKET_NUMBER, nullptr, kDefaultLength,
+                            0, true, false);
+    unacked_packets_.AddSentPacket(&packet, 0, NOT_RETRANSMISSION, clock_.Now(),
+                                   false);
+  }
+
   void VerifyLosses(QuicPacketNumber largest_newly_acked,
                     QuicPacketNumber* losses_expected,
                     size_t num_losses) {
@@ -184,6 +192,28 @@
   EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
 }
 
+TEST_F(GeneralLossAlgorithmTest, EarlyRetransmitWithLargerUnackablePackets) {
+  FLAGS_quic_largest_sent_retransmittable = true;
+  // Transmit 2 data packets and one ack.
+  SendDataPacket(1);
+  SendDataPacket(2);
+  SendAckPacket(3);
+  clock_.AdvanceTime(rtt_stats_.smoothed_rtt());
+
+  // Early retransmit when the final packet gets acked and the first is nacked.
+  unacked_packets_.IncreaseLargestObserved(2);
+  unacked_packets_.RemoveFromInFlight(2);
+  VerifyLosses(2, nullptr, 0);
+  EXPECT_EQ(clock_.Now() + 0.25 * rtt_stats_.smoothed_rtt(),
+            loss_algorithm_.GetLossTimeout());
+
+  // The packet should be lost once the loss timeout is reached.
+  clock_.AdvanceTime(0.25 * rtt_stats_.latest_rtt());
+  QuicPacketNumber lost[] = {1};
+  VerifyLosses(2, lost, arraysize(lost));
+  EXPECT_EQ(QuicTime::Zero(), loss_algorithm_.GetLossTimeout());
+}
+
 TEST_F(GeneralLossAlgorithmTest, AlwaysLosePacketSent1RTTEarlier) {
   // Transmit 1 packet and then wait an rtt plus 1ms.
   SendDataPacket(1);
diff --git a/net/quic/core/congestion_control/simulation/quic_endpoint.cc b/net/quic/core/congestion_control/simulation/quic_endpoint.cc
index 9e3dde1..bbf35328 100644
--- a/net/quic/core/congestion_control/simulation/quic_endpoint.cc
+++ b/net/quic/core/congestion_control/simulation/quic_endpoint.cc
@@ -165,7 +165,7 @@
 }
 
 QuicEndpoint::Writer::Writer(QuicEndpoint* endpoint)
-    : QuicDefaultPacketWriter(0), endpoint_(endpoint) {}
+    : endpoint_(endpoint), is_blocked_(false) {}
 
 QuicEndpoint::Writer::~Writer() {}
 
@@ -184,7 +184,7 @@
   // Instead of losing a packet, become write-blocked when the egress queue is
   // full.
   if (endpoint_->nic_tx_queue_.packets_queued() > kTxQueueSize) {
-    set_write_blocked(true);
+    is_blocked_ = true;
     return WriteResult(WRITE_STATUS_BLOCKED, 0);
   }
 
diff --git a/net/quic/core/congestion_control/simulation/quic_endpoint.h b/net/quic/core/congestion_control/simulation/quic_endpoint.h
index d12e11ea..0ce4b3d 100644
--- a/net/quic/core/congestion_control/simulation/quic_endpoint.h
+++ b/net/quic/core/congestion_control/simulation/quic_endpoint.h
@@ -92,7 +92,7 @@
 
  private:
   // A Writer object that writes into the |nic_tx_queue_|.
-  class Writer : public QuicDefaultPacketWriter {
+  class Writer : public QuicPacketWriter {
    public:
     explicit Writer(QuicEndpoint* endpoint);
     ~Writer() override;
@@ -102,9 +102,18 @@
                             const IPAddress& self_address,
                             const IPEndPoint& peer_address,
                             PerPacketOptions* options) override;
+    bool IsWriteBlockedDataBuffered() const override { return false; }
+    bool IsWriteBlocked() const override { return is_blocked_; }
+    void SetWritable() override { is_blocked_ = false; }
+    QuicByteCount GetMaxPacketSize(
+        const IPEndPoint& /*peer_address*/) const override {
+      return kMaxPacketSize;
+    }
 
    private:
     QuicEndpoint* endpoint_;
+
+    bool is_blocked_;
   };
 
   // Write stream data until |bytes_to_transfer_| is zero or the connection is
diff --git a/net/quic/core/crypto/crypto_server_test.cc b/net/quic/core/crypto/crypto_server_test.cc
index c148e9b..43fad918 100644
--- a/net/quic/core/crypto/crypto_server_test.cc
+++ b/net/quic/core/crypto/crypto_server_test.cc
@@ -480,7 +480,6 @@
 }
 
 TEST_P(CryptoServerTest, RejectNotTooLarge) {
-  FLAGS_quic_use_chlo_packet_size = true;
   // When the CHLO packet is large enough, ensure that a full REJ is sent.
   chlo_packet_size_ *= 2;
 
diff --git a/net/quic/core/crypto/quic_crypto_server_config.cc b/net/quic/core/crypto/quic_crypto_server_config.cc
index 66860e7..0853835 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.cc
+++ b/net/quic/core/crypto/quic_crypto_server_config.cc
@@ -231,7 +231,8 @@
       source_address_token_lifetime_secs_(86400),
       server_nonce_strike_register_max_entries_(1 << 10),
       server_nonce_strike_register_window_secs_(120),
-      enable_serving_sct_(false) {
+      enable_serving_sct_(false),
+      rejection_observer_(nullptr) {
   DCHECK(proof_source_.get());
   source_address_token_boxer_.SetKeys(
       {DeriveSourceAddressTokenKey(source_address_token_secret)});
@@ -645,6 +646,10 @@
                    use_stateless_rejects, server_designated_connection_id, rand,
                    compressed_certs_cache, params, *crypto_proof,
                    total_framing_overhead, chlo_packet_size, out);
+    if (FLAGS_quic_export_rej_for_all_rejects &&
+        rejection_observer_ != nullptr) {
+      rejection_observer_->OnRejectionBuilt(info.reject_reasons, out);
+    }
     return QUIC_NO_ERROR;
   }
 
@@ -1518,14 +1523,9 @@
   // max_unverified_size is the number of bytes that the certificate chain,
   // signature, and (optionally) signed certificate timestamp can consume before
   // we will demand a valid source-address token.
-  const size_t old_max_unverified_size =
-      client_hello.size() * chlo_multiplier_ - kREJOverheadBytes;
-  const size_t new_max_unverified_size =
+  const size_t max_unverified_size =
       chlo_multiplier_ * (chlo_packet_size - total_framing_overhead) -
       kREJOverheadBytes;
-  const size_t max_unverified_size = FLAGS_quic_use_chlo_packet_size
-                                         ? new_max_unverified_size
-                                         : old_max_unverified_size;
   static_assert(kClientHelloMinimumSize * kMultiplier >= kREJOverheadBytes,
                 "overhead calculation may underflow");
   bool should_return_sct =
@@ -1544,13 +1544,11 @@
       }
     }
   } else {
-    if (FLAGS_quic_use_chlo_packet_size) {
-      DLOG(WARNING) << "Sending inchoate REJ for hostname: " << info.sni
-                    << " signature: " << crypto_proof.signature.size()
-                    << " cert: " << compressed.size() << " sct:" << sct_size
-                    << " total: " << total_size
-                    << " max: " << max_unverified_size;
-    }
+    DLOG(WARNING) << "Sending inchoate REJ for hostname: " << info.sni
+                  << " signature: " << crypto_proof.signature.size()
+                  << " cert: " << compressed.size() << " sct:" << sct_size
+                  << " total: " << total_size
+                  << " max: " << max_unverified_size;
   }
 }
 
diff --git a/net/quic/core/crypto/quic_crypto_server_config.h b/net/quic/core/crypto/quic_crypto_server_config.h
index 48449ad..12316b1b 100644
--- a/net/quic/core/crypto/quic_crypto_server_config.h
+++ b/net/quic/core/crypto/quic_crypto_server_config.h
@@ -128,6 +128,20 @@
   DISALLOW_COPY_AND_ASSIGN(BuildServerConfigUpdateMessageResultCallback);
 };
 
+// Object that is interested in built rejections (which include REJ, SREJ and
+// cheap SREJ).
+class RejectionObserver {
+ public:
+  RejectionObserver() = default;
+  virtual ~RejectionObserver() {}
+  // Called after a rejection is built.
+  virtual void OnRejectionBuilt(const std::vector<uint32_t>& reasons,
+                                CryptoHandshakeMessage* out) const = 0;
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(RejectionObserver);
+};
+
 // QuicCryptoServerConfig contains the crypto configuration of a QUIC server.
 // Unlike a client, a QUIC server can have multiple configurations active in
 // order to support clients resuming with a previous configuration.
@@ -427,6 +441,12 @@
   // Returns the number of configs this object owns.
   int NumberOfConfigs() const;
 
+  // Callers retain the ownership of |rejection_observer| which must outlive the
+  // config.
+  void set_rejection_observer(RejectionObserver* rejection_observer) {
+    rejection_observer_ = rejection_observer;
+  }
+
  private:
   friend class test::QuicCryptoServerConfigPeer;
   friend struct QuicCryptoProof;
@@ -784,6 +804,9 @@
   // Enable serving SCT or not.
   bool enable_serving_sct_;
 
+  // Does not own this observer.
+  RejectionObserver* rejection_observer_;
+
   DISALLOW_COPY_AND_ASSIGN(QuicCryptoServerConfig);
 };
 
diff --git a/net/quic/core/quic_connection.cc b/net/quic/core/quic_connection.cc
index 6985d7d..c93735b 100644
--- a/net/quic/core/quic_connection.cc
+++ b/net/quic/core/quic_connection.cc
@@ -1298,6 +1298,15 @@
   stats_.bytes_received += packet.length();
   ++stats_.packets_received;
 
+  // Ensure the time coming from the packet reader is within a minute of now.
+  if (FLAGS_quic_allow_large_send_deltas &&
+      std::abs((packet.receipt_time() - clock_->ApproximateNow()).ToSeconds()) >
+          60) {
+    QUIC_BUG << "Packet receipt time:"
+             << packet.receipt_time().ToDebuggingValue()
+             << " too far from current time:"
+             << clock_->ApproximateNow().ToDebuggingValue();
+  }
   time_of_last_received_packet_ = packet.receipt_time();
   DVLOG(1) << ENDPOINT << "time of last received packet: "
            << time_of_last_received_packet_.ToDebuggingValue();
diff --git a/net/quic/core/quic_flags_list.h b/net/quic/core/quic_flags_list.h
index ffda3d9..a2859c6 100644
--- a/net/quic/core/quic_flags_list.h
+++ b/net/quic/core/quic_flags_list.h
@@ -72,10 +72,6 @@
 // versions less than 33.
 QUIC_FLAG(bool, FLAGS_quic_require_handshake_confirmation_pre33, false)
 
-// If true, use the CHLO packet size, not message size when determining how
-// large a REJ can be.
-QUIC_FLAG(bool, FLAGS_quic_use_chlo_packet_size, true)
-
 // If true, defer creation of new connection till its CHLO arrives.
 QUIC_FLAG(bool, FLAGS_quic_buffer_packet_till_chlo, true)
 
@@ -102,7 +98,7 @@
 // If true, only open limited number of quic sessions per epoll event. Leave the
 // rest to next event. This flag can be turned on only if
 // --quic_buffer_packet_till_chlo is true.
-QUIC_FLAG(bool, FLAGS_quic_limit_num_new_sessions_per_epoll_loop, false)
+QUIC_FLAG(bool, FLAGS_quic_limit_num_new_sessions_per_epoll_loop, true)
 
 // If true, lazy allocate and early release memeory used in
 // QuicStreamSequencerBuffer to buffer incoming data.
@@ -136,3 +132,17 @@
 // As the Linux kernel does, limit QUIC's Cubic congestion control to
 // only increase the CWND 1 packet for every two packets acked.
 QUIC_FLAG(bool, FLAGS_quic_limit_cubic_cwnd_increase, true)
+
+// If true, export reject reasons for all rejects, i.e., rejects,
+// stateless rejects and cheap stateless rejects.
+QUIC_FLAG(bool, FLAGS_quic_export_rej_for_all_rejects, true)
+
+// Allow large send deltas to be used as RTT samples.
+QUIC_FLAG(bool, FLAGS_quic_allow_large_send_deltas, true)
+
+// Engage early retransmit anytime the largest acked is greater than
+// or equal to the largest retransmittable packet.
+QUIC_FLAG(bool, FLAGS_quic_largest_sent_retransmittable, true)
+
+// If true, close connection when sequencer buffer enter into unexpected state.
+QUIC_FLAG(bool, FLAGS_quic_stream_sequencer_buffer_debug, true)
diff --git a/net/quic/core/quic_headers_stream.h b/net/quic/core/quic_headers_stream.h
index 89a8c3f..603dd45 100644
--- a/net/quic/core/quic_headers_stream.h
+++ b/net/quic/core/quic_headers_stream.h
@@ -167,9 +167,6 @@
   SpdyFramer spdy_framer_;
   std::unique_ptr<SpdyFramerVisitor> spdy_framer_visitor_;
 
-  // Either empty, or contains the complete list of headers.
-  QuicHeaderList header_list_;
-
   DISALLOW_COPY_AND_ASSIGN(QuicHeadersStream);
 };
 
diff --git a/net/quic/core/quic_multipath_sent_packet_manager.cc b/net/quic/core/quic_multipath_sent_packet_manager.cc
index 0800a6a..5d46ec10 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager.cc
+++ b/net/quic/core/quic_multipath_sent_packet_manager.cc
@@ -354,12 +354,6 @@
   path_manager->OnConnectionMigration(path_id, type);
 }
 
-bool QuicMultipathSentPacketManager::IsHandshakeConfirmed() const {
-  QuicSentPacketManagerInterface* path_manager =
-      MaybeGetSentPacketManagerForActivePath(kDefaultPathId);
-  return path_manager != nullptr && path_manager->IsHandshakeConfirmed();
-}
-
 void QuicMultipathSentPacketManager::SetDebugDelegate(
     DebugDelegate* debug_delegate) {
   for (PathSentPacketManagerInfo path_manager_info : path_managers_info_) {
diff --git a/net/quic/core/quic_multipath_sent_packet_manager.h b/net/quic/core/quic_multipath_sent_packet_manager.h
index c805280..75b35dd 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager.h
+++ b/net/quic/core/quic_multipath_sent_packet_manager.h
@@ -143,8 +143,6 @@
   void OnConnectionMigration(QuicPathId path_id,
                              PeerAddressChangeType type) override;
 
-  bool IsHandshakeConfirmed() const override;
-
   // Sets debug delegate for all active paths.
   void SetDebugDelegate(DebugDelegate* debug_delegate) override;
 
diff --git a/net/quic/core/quic_multipath_sent_packet_manager_test.cc b/net/quic/core/quic_multipath_sent_packet_manager_test.cc
index 62177aa..bcff44d 100644
--- a/net/quic/core/quic_multipath_sent_packet_manager_test.cc
+++ b/net/quic/core/quic_multipath_sent_packet_manager_test.cc
@@ -275,11 +275,6 @@
       multipath_manager_.OnConnectionMigration(kTestPathId3, PORT_CHANGE), "");
 }
 
-TEST_F(QuicMultipathSentPacketManagerTest, IsHandshakeConfirmed) {
-  EXPECT_CALL(*manager_0_, IsHandshakeConfirmed()).WillOnce(Return(true));
-  EXPECT_TRUE(multipath_manager_.IsHandshakeConfirmed());
-}
-
 TEST_F(QuicMultipathSentPacketManagerTest, SetDebugDelegate) {
   EXPECT_CALL(*manager_0_, SetDebugDelegate(nullptr));
   EXPECT_CALL(*manager_1_, SetDebugDelegate(nullptr));
diff --git a/net/quic/core/quic_protocol.h b/net/quic/core/quic_protocol.h
index 72a5b69c..8906879 100644
--- a/net/quic/core/quic_protocol.h
+++ b/net/quic/core/quic_protocol.h
@@ -724,8 +724,12 @@
   // maintains too many gaps.
   QUIC_TOO_MANY_FRAME_GAPS = 93,
 
+  // Sequencer buffer get into weird state where continuing read/write will lead
+  // to crash.
+  QUIC_STREAM_SEQUENCER_INVALID_STATE = 95,
+
   // No error. Used as bound while iterating.
-  QUIC_LAST_ERROR = 95,
+  QUIC_LAST_ERROR = 96,
 };
 
 typedef std::array<char, 32> DiversificationNonce;
diff --git a/net/quic/core/quic_sent_packet_manager.cc b/net/quic/core/quic_sent_packet_manager.cc
index 5a97b1e..7738e34 100644
--- a/net/quic/core/quic_sent_packet_manager.cc
+++ b/net/quic/core/quic_sent_packet_manager.cc
@@ -632,9 +632,6 @@
     if (!it->in_flight || it->retransmittable_frames.empty()) {
       continue;
     }
-    if (!handshake_confirmed_) {
-      DCHECK(!it->has_crypto_handshake);
-    }
     MarkForRetransmission(packet_number, TLP_RETRANSMISSION);
     return true;
   }
@@ -743,7 +740,8 @@
 
   QuicTime::Delta send_delta = ack_receive_time - transmission_info.sent_time;
   const int kMaxSendDeltaSeconds = 30;
-  if (send_delta.ToSeconds() > kMaxSendDeltaSeconds) {
+  if (!FLAGS_quic_allow_large_send_deltas &&
+      send_delta.ToSeconds() > kMaxSendDeltaSeconds) {
     // send_delta can be very high if local clock is changed mid-connection.
     LOG(WARNING) << "Excessive send delta: " << send_delta.ToSeconds()
                  << ", setting to: " << kMaxSendDeltaSeconds
@@ -946,9 +944,6 @@
   send_algorithm_->OnConnectionMigration();
 }
 
-bool QuicSentPacketManager::IsHandshakeConfirmed() const {
-  return handshake_confirmed_;
-}
 
 void QuicSentPacketManager::SetDebugDelegate(DebugDelegate* debug_delegate) {
   debug_delegate_ = debug_delegate;
diff --git a/net/quic/core/quic_sent_packet_manager.h b/net/quic/core/quic_sent_packet_manager.h
index 17e2203..b442951 100644
--- a/net/quic/core/quic_sent_packet_manager.h
+++ b/net/quic/core/quic_sent_packet_manager.h
@@ -189,8 +189,6 @@
   // Called when peer address changes and the connection migrates.
   void OnConnectionMigration(QuicPathId, PeerAddressChangeType type) override;
 
-  bool IsHandshakeConfirmed() const override;
-
   void SetDebugDelegate(DebugDelegate* debug_delegate) override;
 
   QuicPacketNumber GetLargestObserved(QuicPathId) const override;
diff --git a/net/quic/core/quic_sent_packet_manager_interface.h b/net/quic/core/quic_sent_packet_manager_interface.h
index c366ed6..7d80e6f 100644
--- a/net/quic/core/quic_sent_packet_manager_interface.h
+++ b/net/quic/core/quic_sent_packet_manager_interface.h
@@ -165,8 +165,6 @@
   virtual void OnConnectionMigration(QuicPathId path_id,
                                      PeerAddressChangeType type) = 0;
 
-  virtual bool IsHandshakeConfirmed() const = 0;
-
   virtual void SetDebugDelegate(DebugDelegate* debug_delegate) = 0;
 
   virtual QuicPacketNumber GetLargestObserved(QuicPathId path_id) const = 0;
diff --git a/net/quic/core/quic_stream_sequencer.cc b/net/quic/core/quic_stream_sequencer.cc
index 4a6ea83..45f1e88c 100644
--- a/net/quic/core/quic_stream_sequencer.cc
+++ b/net/quic/core/quic_stream_sequencer.cc
@@ -9,8 +9,10 @@
 #include <string>
 #include <utility>
 
+#include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_clock.h"
 #include "net/quic/core/quic_flags.h"
@@ -21,6 +23,7 @@
 
 using base::IntToString;
 using base::StringPiece;
+using base::StringPrintf;
 using std::min;
 using std::numeric_limits;
 using std::string;
@@ -135,7 +138,17 @@
 
 int QuicStreamSequencer::Readv(const struct iovec* iov, size_t iov_len) {
   DCHECK(!blocked_);
-  size_t bytes_read = buffered_frames_.Readv(iov, iov_len);
+  string error_details;
+  size_t bytes_read;
+  QuicErrorCode read_error =
+      buffered_frames_.Readv(iov, iov_len, &bytes_read, &error_details);
+  if (FLAGS_quic_stream_sequencer_buffer_debug && read_error != QUIC_NO_ERROR) {
+    string details = StringPrintf("Stream %" PRIu32 ": %s", stream_->id(),
+                                  error_details.c_str());
+    stream_->CloseConnectionWithDetails(read_error, details);
+    return static_cast<int>(bytes_read);
+  }
+
   stream_->AddBytesConsumed(bytes_read);
   return static_cast<int>(bytes_read);
 }
diff --git a/net/quic/core/quic_stream_sequencer_buffer.cc b/net/quic/core/quic_stream_sequencer_buffer.cc
index 0c55fe75..fcb617fb6 100644
--- a/net/quic/core/quic_stream_sequencer_buffer.cc
+++ b/net/quic/core/quic_stream_sequencer_buffer.cc
@@ -4,11 +4,14 @@
 
 #include "net/quic/core/quic_stream_sequencer_buffer.h"
 
+#include "base/format_macros.h"
 #include "base/logging.h"
 #include "base/strings/string_number_conversions.h"
+#include "base/strings/stringprintf.h"
 #include "net/quic/core/quic_bug_tracker.h"
 #include "net/quic/core/quic_flags.h"
 
+using base::StringPrintf;
 using std::min;
 using std::string;
 
@@ -76,11 +79,15 @@
   frame_arrival_time_map_.clear();
 }
 
-void QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
-  DCHECK(blocks_[idx] != nullptr);
+bool QuicStreamSequencerBuffer::RetireBlock(size_t idx) {
+  if (FLAGS_quic_stream_sequencer_buffer_debug && blocks_[idx] == nullptr) {
+    QUIC_BUG << "Try to retire block twice";
+    return false;
+  }
   delete blocks_[idx];
   blocks_[idx] = nullptr;
   DVLOG(1) << "Retired block with index: " << idx;
+  return true;
 }
 
 QuicErrorCode QuicStreamSequencerBuffer::OnStreamData(
@@ -181,6 +188,20 @@
       }
     }
 
+    if (FLAGS_quic_stream_sequencer_buffer_debug &&
+        write_block_num >= blocks_count_) {
+      *error_details = StringPrintf(
+          "QuicStreamSequencerBuffer error: OnStreamData() exceed array bounds."
+          "write offset = %" PRIu64 " write_block_num = %" PRIuS
+          " blocks_count_ = %" PRIuS,
+          offset, write_block_num, blocks_count_);
+      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+    }
+    if (blocks_ == nullptr) {
+      *error_details =
+          "QuicStreamSequencerBuffer error: OnStreamData() blocks_ is null";
+      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+    }
     if (blocks_[write_block_num] == nullptr) {
       // TODO(danzh): Investigate if using a freelist would improve performance.
       // Same as RetireBlock().
@@ -190,6 +211,23 @@
     const size_t bytes_to_copy = min<size_t>(bytes_avail, source_remaining);
     char* dest = blocks_[write_block_num]->buffer + write_block_offset;
     DVLOG(1) << "Write at offset: " << offset << " length: " << bytes_to_copy;
+
+    if (FLAGS_quic_stream_sequencer_buffer_debug &&
+        (dest == nullptr || source == nullptr)) {
+      *error_details = StringPrintf(
+          "QuicStreamSequencerBuffer error: OnStreamData()"
+          " dest == nullptr: %s"
+          " source == nullptr: %s"
+          " Writing at offset %" PRIu64
+          " Gaps: %s"
+          " Remaining frames: %s"
+          " total_bytes_read_ = %" PRIu64,
+          (dest == nullptr ? "true" : "false"),
+          (source == nullptr ? "true" : "false"), offset,
+          GapsDebugString().c_str(), ReceivedFramesDebugString().c_str(),
+          total_bytes_read_);
+      return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+    }
     memcpy(dest, source, bytes_to_copy);
     source += bytes_to_copy;
     source_remaining -= bytes_to_copy;
@@ -237,9 +275,11 @@
   }
 }
 
-size_t QuicStreamSequencerBuffer::Readv(const iovec* dest_iov,
-                                        size_t dest_count) {
-  size_t bytes_read = 0;
+QuicErrorCode QuicStreamSequencerBuffer::Readv(const iovec* dest_iov,
+                                               size_t dest_count,
+                                               size_t* bytes_read,
+                                               string* error_details) {
+  *bytes_read = 0;
   for (size_t i = 0; i < dest_count && ReadableBytes() > 0; ++i) {
     char* dest = reinterpret_cast<char*>(dest_iov[i].iov_base);
     size_t dest_remaining = dest_iov[i].iov_len;
@@ -251,28 +291,47 @@
           min<size_t>(ReadableBytes(), block_capacity - start_offset_in_block);
       size_t bytes_to_copy =
           min<size_t>(bytes_available_in_block, dest_remaining);
-      DCHECK_GT(bytes_to_copy, 0u);
-      DCHECK_NE(static_cast<BufferBlock*>(nullptr), blocks_[block_idx]);
+      DCHECK_GT(bytes_to_copy, 0UL);
+      if (FLAGS_quic_stream_sequencer_buffer_debug &&
+          (blocks_[block_idx] == nullptr || dest == nullptr)) {
+        *error_details = StringPrintf(
+            "QuicStreamSequencerBuffer error:"
+            " Readv() dest == nullptr: %s"
+            " blocks_[%" PRIuS "] == nullptr: %s",
+            (dest == nullptr ? "true" : "false"), block_idx,
+            (blocks_[block_idx] == nullptr ? "true" : "false"));
+        return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+      }
       memcpy(dest, blocks_[block_idx]->buffer + start_offset_in_block,
              bytes_to_copy);
       dest += bytes_to_copy;
       dest_remaining -= bytes_to_copy;
       num_bytes_buffered_ -= bytes_to_copy;
       total_bytes_read_ += bytes_to_copy;
-      bytes_read += bytes_to_copy;
+      *bytes_read += bytes_to_copy;
 
-      // Retire the block if all the data is read out
-      // and no other data is stored in this block.
+      // Retire the block if all the data is read out and no other data is
+      // stored in this block.
+      // In case of failing to retire a block which is ready to retire, return
+      // immediately.
       if (bytes_to_copy == bytes_available_in_block) {
-        RetireBlockIfEmpty(block_idx);
+        bool retire_successfully = RetireBlockIfEmpty(block_idx);
+        if (FLAGS_quic_stream_sequencer_buffer_debug && !retire_successfully) {
+          *error_details = StringPrintf(
+              "QuicStreamSequencerBuffer error: fail to retire block %" PRIuS
+              " as the block is already released + total_bytes_read_ = %" PRIu64
+              " Gaps: %s",
+              block_idx, total_bytes_read_, GapsDebugString().c_str());
+          return QUIC_STREAM_SEQUENCER_INVALID_STATE;
+        }
       }
     }
   }
 
-  if (bytes_read > 0) {
+  if (*bytes_read > 0) {
     UpdateFrameArrivalMap(total_bytes_read_);
   }
-  return bytes_read;
+  return QUIC_NO_ERROR;
 }
 
 int QuicStreamSequencerBuffer::GetReadableRegions(struct iovec* iov,
@@ -447,21 +506,20 @@
   return GetBlockIndex(total_bytes_read_);
 }
 
-void QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) {
+bool QuicStreamSequencerBuffer::RetireBlockIfEmpty(size_t block_index) {
   DCHECK(ReadableBytes() == 0 || GetInBlockOffset(total_bytes_read_) == 0)
       << "RetireBlockIfEmpty() should only be called when advancing to next "
          "block"
          " or a gap has been reached.";
   // If the whole buffer becomes empty, the last piece of data has been read.
   if (Empty()) {
-    RetireBlock(block_index);
-    return;
+    return RetireBlock(block_index);
   }
 
   // Check where the logical end of this buffer is.
   // Not empty if the end of circular buffer has been wrapped to this block.
   if (GetBlockIndex(gaps_.back().begin_offset - 1) == block_index) {
-    return;
+    return true;
   }
 
   // Read index remains in this block, which means a gap has been reached.
@@ -473,10 +531,10 @@
     bool gap_ends_in_this_block =
         (GetBlockIndex(first_gap.end_offset) == block_index);
     if (gap_ends_in_this_block) {
-      return;
+      return true;
     }
   }
-  RetireBlock(block_index);
+  return RetireBlock(block_index);
 }
 
 bool QuicStreamSequencerBuffer::Empty() const {
@@ -534,8 +592,16 @@
     QuicStreamOffset current_frame_begin_offset = it.first;
     QuicStreamOffset current_frame_end_offset =
         it.second.length + current_frame_begin_offset;
-    current_frames_string +=
-        RangeDebugString(current_frame_begin_offset, current_frame_end_offset);
+    if (FLAGS_quic_stream_sequencer_buffer_debug) {
+      current_frames_string = string(StringPrintf(
+          "%s[%" PRIu64 ", %" PRIu64 ") receiving time %" PRId64 " ",
+          current_frames_string.c_str(), current_frame_begin_offset,
+          current_frame_end_offset, it.second.timestamp.ToDebuggingValue()));
+    } else {
+      current_frames_string = string(StringPrintf(
+          "%s[%" PRIu64 ", %" PRIu64 ") ", current_frames_string.c_str(),
+          current_frame_begin_offset, current_frame_end_offset));
+    }
   }
   return current_frames_string;
 }
diff --git a/net/quic/core/quic_stream_sequencer_buffer.h b/net/quic/core/quic_stream_sequencer_buffer.h
index 135e7d1..a79d8b4 100644
--- a/net/quic/core/quic_stream_sequencer_buffer.h
+++ b/net/quic/core/quic_stream_sequencer_buffer.h
@@ -125,7 +125,10 @@
 
   // Reads from this buffer into given iovec array, up to number of iov_len
   // iovec objects and returns the number of bytes read.
-  size_t Readv(const struct iovec* dest_iov, size_t dest_count);
+  QuicErrorCode Readv(const struct iovec* dest_iov,
+                      size_t dest_count,
+                      size_t* bytes_read,
+                      std::string* error_details);
 
   // Returns the readable region of valid data in iovec format. The readable
   // region is the buffer region where there is valid data not yet read by
@@ -174,13 +177,15 @@
   // Dispose the given buffer block.
   // After calling this method, blocks_[index] is set to nullptr
   // in order to indicate that no memory set is allocated for that block.
-  void RetireBlock(size_t index);
+  // Returns true on success, false otherwise.
+  bool RetireBlock(size_t index);
 
   // Should only be called after the indexed block is read till the end of the
   // block or a gap has been reached.
-  // If the block at |block_index| contains no buffered data, then the block is
-  // retired.
-  void RetireBlockIfEmpty(size_t block_index);
+  // If the block at |block_index| contains no buffered data, the block
+  // should be retired.
+  // Return false on success, or false otherwise.
+  bool RetireBlockIfEmpty(size_t block_index);
 
   // Called within OnStreamData() to update the gap OnStreamData() writes into
   // (remove, split or change begin/end offset).
diff --git a/net/quic/core/quic_stream_sequencer_buffer_test.cc b/net/quic/core/quic_stream_sequencer_buffer_test.cc
index f4ae84c..944b41a 100644
--- a/net/quic/core/quic_stream_sequencer_buffer_test.cc
+++ b/net/quic/core/quic_stream_sequencer_buffer_test.cc
@@ -66,7 +66,11 @@
   size_t Read(char* dest_buffer, size_t size) {
     iovec dest;
     dest.iov_base = dest_buffer, dest.iov_len = size;
-    return buffer_->Readv(&dest, 1);
+    size_t bytes_read;
+    string error_details;
+    EXPECT_EQ(QUIC_NO_ERROR,
+              buffer_->Readv(&dest, 1, &bytes_read, &error_details));
+    return bytes_read;
   }
 
   // If buffer is empty, the blocks_ array must be empty, which means all
@@ -186,6 +190,7 @@
   MockClock clock_;
   std::unique_ptr<QuicStreamSequencerBuffer> buffer_;
   std::unique_ptr<QuicStreamSequencerBufferPeer> helper_;
+  QuicFlagSaver flag_saver_;
   string error_details_;
 };
 
@@ -240,6 +245,22 @@
   EXPECT_TRUE(helper_->IsBufferAllocated());
 }
 
+TEST_F(QuicStreamSequencerBufferTest, OnStreamDataInvalidSource) {
+  FLAGS_quic_stream_sequencer_buffer_debug = true;
+  // Pass in an invalid source, expects to return error.
+  StringPiece source;
+  source.set(nullptr, 1024);
+  size_t written;
+  clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+  QuicTime t = clock_.ApproximateNow();
+  EXPECT_EQ(QUIC_STREAM_SEQUENCER_INVALID_STATE,
+            buffer_->OnStreamData(800, source, t, &written, &error_details_));
+  EXPECT_EQ(
+      0u, error_details_.find("QuicStreamSequencerBuffer error: OnStreamData()"
+                              " dest == nullptr: false"
+                              " source == nullptr: true"));
+}
+
 TEST_F(QuicStreamSequencerBufferTest, OnStreamDataWithOverlap) {
   string source(1024, 'a');
   // Write something into [800, 1824)
@@ -411,7 +432,9 @@
   // Read into a iovec array with total capacity of 120 bytes.
   char dest[120];
   iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}};
-  size_t read = buffer_->Readv(iovecs, 3);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 3, &read, &error_details_));
+  LOG(ERROR) << error_details_;
   EXPECT_EQ(100u, read);
   EXPECT_EQ(100u, buffer_->BytesConsumed());
   EXPECT_EQ(source, string(dest, read));
@@ -421,6 +444,27 @@
   EXPECT_TRUE(helper_->CheckBufferInvariants());
 }
 
+TEST_F(QuicStreamSequencerBufferTest, ReadvError) {
+  FLAGS_quic_stream_sequencer_buffer_debug = true;
+  string source = string(100, 'b');
+  clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
+  QuicTime t1 = clock_.ApproximateNow();
+  // Write something into [0, 100).
+  size_t written;
+  buffer_->OnStreamData(0, source, t1, &written, &error_details_);
+  EXPECT_TRUE(helper_->GetBlock(0) != nullptr);
+  EXPECT_TRUE(buffer_->HasBytesToRead());
+  // Read into a iovec array with total capacity of 120 bytes.
+  iovec iov{nullptr, 120};
+  size_t read;
+  EXPECT_EQ(QUIC_STREAM_SEQUENCER_INVALID_STATE,
+            buffer_->Readv(&iov, 1, &read, &error_details_));
+  EXPECT_EQ(0u,
+            error_details_.find(
+                "QuicStreamSequencerBuffer error: Readv() dest == nullptr: true"
+                " blocks_[0] == nullptr: false"));
+}
+
 TEST_F(QuicStreamSequencerBufferTest, ReadvAcrossBlocks) {
   string source(kBlockSizeBytes + 50, 'a');
   // Write 1st block to full and extand 50 bytes to next block.
@@ -433,7 +477,8 @@
   while (helper_->ReadableBytes()) {
     std::fill(dest, dest + 512, 0);
     iovec iovecs[2]{iovec{dest, 256}, iovec{dest + 256, 256}};
-    buffer_->Readv(iovecs, 2);
+    size_t read;
+    EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 2, &read, &error_details_));
   }
   // The last read only reads the rest 50 bytes in 2nd block.
   EXPECT_EQ(string(50, 'a'), string(dest, 50));
@@ -452,7 +497,8 @@
   // Read first 512 bytes from buffer to make space at the beginning.
   char dest[512]{0};
   const iovec iov{dest, 512};
-  buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
   // Clear() should make buffer empty while preserving BytesConsumed()
   buffer_->Clear();
   EXPECT_TRUE(buffer_->Empty());
@@ -469,7 +515,8 @@
   // Read first 512 bytes from buffer to make space at the beginning.
   char dest[512]{0};
   const iovec iov{dest, 512};
-  buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
   EXPECT_EQ(source.size(), written);
 
   // Write more than half block size of bytes in the last block with 'b', which
@@ -492,7 +539,8 @@
   // Read first 512 bytes from buffer to make space at the beginning.
   char dest[512]{0};
   const iovec iov{dest, 512};
-  buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
 
   // Try to write from [max_capacity_bytes_ - 0.5 * kBlockSizeBytes,
   // max_capacity_bytes_ +  512 + 1). But last bytes exceeds current capacity.
@@ -514,7 +562,8 @@
   buffer_->OnStreamData(0, source, t, &written, &error_details_);
   char dest[512]{0};
   const iovec iov{dest, 512};
-  buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
   source = string(256, 'b');
   clock_.AdvanceTime(QuicTime::Delta::FromSeconds(1));
   QuicTime t2 = clock_.ApproximateNow();
@@ -527,7 +576,8 @@
   std::unique_ptr<char[]> dest1{new char[max_capacity_bytes_]};
   dest1[0] = 0;
   const iovec iov1{dest1.get(), max_capacity_bytes_};
-  EXPECT_EQ(max_capacity_bytes_ - 512 + 256, buffer_->Readv(&iov1, 1));
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov1, 1, &read, &error_details_));
+  EXPECT_EQ(max_capacity_bytes_ - 512 + 256, read);
   EXPECT_EQ(max_capacity_bytes_ + 256, buffer_->BytesConsumed());
   EXPECT_TRUE(buffer_->Empty());
   EXPECT_TRUE(helper_->CheckBufferInvariants());
@@ -537,7 +587,8 @@
 TEST_F(QuicStreamSequencerBufferTest, ReadvEmpty) {
   char dest[512]{0};
   iovec iov{dest, 512};
-  size_t read = buffer_->Readv(&iov, 1);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(&iov, 1, &read, &error_details_));
   EXPECT_EQ(0u, read);
   EXPECT_TRUE(helper_->CheckBufferInvariants());
 }
@@ -566,7 +617,8 @@
   EXPECT_TRUE(buffer_->HasBytesToRead());
   char dest[120];
   iovec iovecs[3]{iovec{dest, 40}, iovec{dest + 40, 40}, iovec{dest + 80, 40}};
-  size_t read = buffer_->Readv(iovecs, 3);
+  size_t read;
+  EXPECT_EQ(QUIC_NO_ERROR, buffer_->Readv(iovecs, 3, &read, &error_details_));
   EXPECT_EQ(100u, read);
   EXPECT_EQ(100u, buffer_->BytesConsumed());
   EXPECT_TRUE(helper_->CheckBufferInvariants());
@@ -1013,7 +1065,10 @@
           dest_iov[i].iov_len = rng_.RandUint64() % kMaxReadSize;
           num_to_read += dest_iov[i].iov_len;
         }
-        size_t actually_read = buffer_->Readv(dest_iov, kNumReads);
+        size_t actually_read;
+        EXPECT_EQ(QUIC_NO_ERROR,
+                  buffer_->Readv(dest_iov, kNumReads, &actually_read,
+                                 &error_details_));
         ASSERT_LE(actually_read, num_to_read);
         DVLOG(1) << " read from offset: " << total_bytes_read_
                  << " size: " << num_to_read
diff --git a/net/quic/core/quic_stream_sequencer_test.cc b/net/quic/core/quic_stream_sequencer_test.cc
index 0960f03..b3b473f0 100644
--- a/net/quic/core/quic_stream_sequencer_test.cc
+++ b/net/quic/core/quic_stream_sequencer_test.cc
@@ -662,6 +662,30 @@
   EXPECT_EQ(0u, sequencer_->NumBytesBuffered());
 }
 
+TEST_F(QuicStreamSequencerTest, OnStreamFrameWithNullSource) {
+  FLAGS_quic_stream_sequencer_buffer_debug = true;
+  // Pass in a frame with data pointing to null address, expect to close
+  // connection with error.
+  StringPiece source(nullptr, 5u);
+  QuicStreamFrame frame(kClientDataStreamId1, false, 1, source);
+  EXPECT_CALL(stream_, CloseConnectionWithDetails(
+                           QUIC_STREAM_SEQUENCER_INVALID_STATE, _));
+  sequencer_->OnStreamFrame(frame);
+}
+
+TEST_F(QuicStreamSequencerTest, ReadvError) {
+  FLAGS_quic_stream_sequencer_buffer_debug = true;
+  EXPECT_CALL(stream_, OnDataAvailable());
+  string source(100, 'a');
+  OnFrame(0u, source.data());
+  EXPECT_EQ(source.length(), sequencer_->NumBytesBuffered());
+  // Pass in a null iovec, expect to tear down connection.
+  EXPECT_CALL(stream_, CloseConnectionWithDetails(
+                           QUIC_STREAM_SEQUENCER_INVALID_STATE, _));
+  iovec iov{nullptr, 512};
+  sequencer_->Readv(&iov, 1u);
+}
+
 }  // namespace
 }  // namespace test
 }  // namespace net
diff --git a/net/quic/core/quic_unacked_packet_map.cc b/net/quic/core/quic_unacked_packet_map.cc
index 0c70d14..adc4a653 100644
--- a/net/quic/core/quic_unacked_packet_map.cc
+++ b/net/quic/core/quic_unacked_packet_map.cc
@@ -18,6 +18,7 @@
 
 QuicUnackedPacketMap::QuicUnackedPacketMap()
     : largest_sent_packet_(0),
+      largest_sent_retransmittable_packet_(0),
       largest_observed_(0),
       least_unacked_(1),
       bytes_in_flight_(0),
@@ -59,6 +60,7 @@
   if (set_in_flight) {
     bytes_in_flight_ += bytes_sent;
     info.in_flight = true;
+    largest_sent_retransmittable_packet_ = packet_number;
   }
   unacked_packets_.push_back(info);
   // Swap the ack listeners and retransmittable frames to avoid allocations.
diff --git a/net/quic/core/quic_unacked_packet_map.h b/net/quic/core/quic_unacked_packet_map.h
index 73969fd6..2357779 100644
--- a/net/quic/core/quic_unacked_packet_map.h
+++ b/net/quic/core/quic_unacked_packet_map.h
@@ -80,6 +80,11 @@
   // Returns the largest packet number that has been sent.
   QuicPacketNumber largest_sent_packet() const { return largest_sent_packet_; }
 
+  // Returns the largest retransmittable packet number that has been sent.
+  QuicPacketNumber largest_sent_retransmittable_packet() const {
+    return largest_sent_retransmittable_packet_;
+  }
+
   // Returns the largest packet number that has been acked.
   QuicPacketNumber largest_observed() const { return largest_observed_; }
 
@@ -169,6 +174,8 @@
                        const TransmissionInfo& info) const;
 
   QuicPacketNumber largest_sent_packet_;
+  // The largest sent packet we expect to receive an ack for.
+  QuicPacketNumber largest_sent_retransmittable_packet_;
   QuicPacketNumber largest_observed_;
 
   // Newly serialized retransmittable packets are added to this map, which
diff --git a/net/quic/core/quic_utils.cc b/net/quic/core/quic_utils.cc
index 52c0def6..f944dd1 100644
--- a/net/quic/core/quic_utils.cc
+++ b/net/quic/core/quic_utils.cc
@@ -303,6 +303,7 @@
     RETURN_STRING_LITERAL(QUIC_MULTIPATH_PATH_DOES_NOT_EXIST);
     RETURN_STRING_LITERAL(QUIC_MULTIPATH_PATH_NOT_ACTIVE);
     RETURN_STRING_LITERAL(QUIC_TOO_MANY_FRAME_GAPS);
+    RETURN_STRING_LITERAL(QUIC_STREAM_SEQUENCER_INVALID_STATE);
     RETURN_STRING_LITERAL(QUIC_LAST_ERROR);
     // Intentionally have no default case, so we'll break the build
     // if we add errors and don't put them here.
diff --git a/net/tools/quic/quic_dispatcher_test.cc b/net/tools/quic/quic_dispatcher_test.cc
index a88a2ead..1d7343f5 100644
--- a/net/tools/quic/quic_dispatcher_test.cc
+++ b/net/tools/quic/quic_dispatcher_test.cc
@@ -427,8 +427,8 @@
   packet.nonce_proof = 132232;
   std::unique_ptr<QuicEncryptedPacket> encrypted(
       QuicFramer::BuildPublicResetPacket(packet));
-  std::unique_ptr<QuicReceivedPacket> received(
-      ConstructReceivedPacket(*encrypted, helper_.GetClock()->Now()));
+  std::unique_ptr<QuicReceivedPacket> received(ConstructReceivedPacket(
+      *encrypted, session1_->connection()->clock()->Now()));
   EXPECT_CALL(*session1_, OnConnectionClosed(QUIC_PUBLIC_RESET, _,
                                              ConnectionCloseSource::FROM_PEER))
       .Times(1)
diff --git a/testing/libfuzzer/fuzzers/BUILD.gn b/testing/libfuzzer/fuzzers/BUILD.gn
index 7457c326..f919ec3 100644
--- a/testing/libfuzzer/fuzzers/BUILD.gn
+++ b/testing/libfuzzer/fuzzers/BUILD.gn
@@ -419,3 +419,14 @@
   ]
   libfuzzer_options = [ "max_len=1000" ]
 }
+
+fuzzer_test("openssl_bio_string_fuzzer") {
+  sources = [
+    "openssl_bio_string_fuzzer.cc",
+  ]
+  deps = [
+    "//crypto",
+    "//third_party/boringssl",
+  ]
+  libfuzzer_options = [ "max_len=512" ]
+}
diff --git a/testing/libfuzzer/fuzzers/openssl_bio_string_fuzzer.cc b/testing/libfuzzer/fuzzers/openssl_bio_string_fuzzer.cc
new file mode 100644
index 0000000..4eec5d8c
--- /dev/null
+++ b/testing/libfuzzer/fuzzers/openssl_bio_string_fuzzer.cc
@@ -0,0 +1,32 @@
+// Copyright 2016 The Chromium 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 <stdint.h>
+
+#include "crypto/openssl_bio_string.h"
+#include "crypto/scoped_openssl_types.h"
+
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  if (size == 0) { return 0; }
+
+  std::string buffer;
+  std::string input(reinterpret_cast<const char*>(data), size);
+
+  std::size_t data_hash = std::hash<std::string>()(input);
+  uint8_t choice = data_hash % 3;
+
+  crypto::ScopedBIO bio(crypto::BIO_new_string(&buffer));
+  if (choice == 0) {
+    BIO_printf(bio.get(), "%s", input.c_str());
+  } else if (choice == 1) {
+    BIO_write(bio.get(), input.c_str(), size);
+  } else {
+    BIO_puts(bio.get(), input.c_str());
+  }
+  BIO_flush(bio.get());
+
+  return 0;
+}
+
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index 825e47f9..19a1348 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -264,36 +264,6 @@
 crbug.com/567837 virtual/scalefactor150/fast/hidpi/static/mousewheel-scroll-amount.html [ Skip ]
 crbug.com/567837 virtual/scalefactor150/fast/hidpi/static/gesture-scroll-amount.html [ Skip ]
 
-crbug.com/646176 paint/invalidation/4776765.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/caret-subpixel.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/caret-with-composited-scroll.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/compositing/iframe-inside-squashed-layer.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/delete-into-nested-block.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/inline-outline-repaint.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/invalidate-caret-in-composited-scrolling-container.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/invalidate-caret-in-non-composited-scrolling-container.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/line-flow-with-floats-2.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/line-flow-with-floats-8.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/line-flow-with-floats-9.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/overflow-scroll-body-appear.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/repaint-during-scroll-with-zoom.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/scrolled-iframe-scrollbar-change.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/selection-after-delete.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/shift-relative-positioned-container-with-image-addition.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/text-match-document-change.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/textarea-caret.html [ NeedsRebaseline ]
-crbug.com/646176 paint/invalidation/window-resize-vertical-writing-mode.html [ NeedsRebaseline ]
-
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-appearance-zoom125.html [ NeedsRebaseline ]
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-appearance-zoom200.html [ NeedsRebaseline ]
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-appearance.html [ NeedsRebaseline ]
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-one-row-appearance.html [ NeedsRebaseline ]
-crbug.com/640256 [ Linux Win ] fast/forms/color/color-suggestion-picker-two-row-appearance.html [ NeedsRebaseline ]
-
 # TODO(ojan): These tests aren't flaky. See crbug.com/517144.
 # Release trybots run asserts, but the main waterfall ones don't. So, even
 # though this is a non-flaky assert failure, we need to mark it [ Pass Crash ].
@@ -370,33 +340,6 @@
 crbug.com/525889 imported/wpt/html/webappapis/scripting/processing-model-2/runtime-error-in-setInterval.html [ Failure ]
 crbug.com/525889 imported/wpt/html/webappapis/scripting/processing-model-2/runtime-error-in-setTimeout.html [ Failure ]
 
-crbug.com/648963 compositing/contents-opaque/overflow-hidden-child-layers.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/culling/scrolled-within-boxshadow.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/culling/translated-boxshadow.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/culling/unscrolled-within-boxshadow.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/geometry/foreground-layer.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/layer-creation/rotate3d-overlap.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/masks/masked-ancestor.html [ NeedsRebaseline ]
-crbug.com/648963 paint/invalidation/box-shadow-add-repaint.html [ NeedsRebaseline ]
-crbug.com/648963 paint/invalidation/box-shadow-change-repaint.html [ NeedsRebaseline ]
-crbug.com/648963 paint/invalidation/transform-replaced-shadows.html [ NeedsRebaseline ]
-crbug.com/648963 svg/css/text-gradient-shadow.svg [ NeedsRebaseline ]
-crbug.com/648963 svg/css/text-shadow-multiple.xhtml [ NeedsRebaseline ]
-crbug.com/648963 svg/zoom/page/zoom-background-images.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/masks/multiple-masks.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/masks/simple-composited-mask.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/scrolling-iframe.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/connect-compositing-iframe3.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/overlapped-iframe.html [ NeedsRebaseline ]
-crbug.com/648963 fast/borders/border-radius-mask-video-shadow.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/enter-compositing-iframe.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/iframe-resize.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/composited-parent-iframe.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/invisible-nested-iframe-show.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/connect-compositing-iframe-delayed.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/connect-compositing-iframe2.html [ NeedsRebaseline ]
-crbug.com/648963 compositing/iframes/connect-compositing-iframe.html [ NeedsRebaseline ]
-
 crbug.com/636961 [ Linux Debug ] virtual/threaded/fast/scroll-behavior/smooth-scroll/ongoing-smooth-scroll-vertical-rl-anchors.html [ Pass Failure ]
 
 crbug.com/552532 [ Win10 ] fast/replaced/no-focus-ring-embed.html [ Pass Crash ]
@@ -701,11 +644,6 @@
 crbug.com/306222 fast/hidpi/image-srcset-relative-svg-canvas.html [ Skip ]
 crbug.com/306222 fast/hidpi/image-srcset-relative-svg-canvas-2x.html [ Skip ]
 
-crbug.com/647922 svg/zoom/page/zoom-img-preserveAspectRatio-support-1.html [ NeedsRebaseline ]
-crbug.com/647922 fast/borders/webkit-border-radius.html [ NeedsRebaseline ]
-crbug.com/647922 fast/borders/borderRadiusDotted04.html [ NeedsRebaseline ]
-crbug.com/647922 fast/borders/border-radius-different-width-001-double.html [ NeedsRebaseline ]
-
 # The failure in the next line is due to virtual/gpu bots using osmesa
 # Under osmesa, skia's filter quality doesn't work correctly. This test is expected to pass
 # when we swith to swiftshader.
@@ -1141,8 +1079,6 @@
 crbug.com/587779 [ Linux Mac10.9 Mac10.10 Mac10.11 Retina ] fast/dynamic/window-resize-scrollbars-test.html [ Timeout Failure Pass ]
 
 crbug.com/588103 fast/xmlhttprequest/xmlhttprequest-responsetype-arraybuffer.html [ Pass Failure ]
-crbug.com/649320 fast/forms/select/menulist-appearance-basic.html [ NeedsRebaseline ]
-crbug.com/649320 http/tests/webfont/popup-menu-load-webfont-after-open.html [ NeedsRebaseline ]
 crbug.com/594672 fast/events/iframe-object-onload.html [ Failure Pass ]
 crbug.com/594672 fast/events/scale-and-scroll-iframe-body.html [ Failure Pass ]
 crbug.com/594672 fast/events/updateLayoutForHitTest.html [ Failure Pass ]
@@ -1254,6 +1190,9 @@
 
 crbug.com/399507 [ Mac Linux Win10 ] virtual/threaded/inspector/tracing/timeline-paint/layer-tree.html [ Skip ]
 
+# Skip this test because it causes the next text to fail though the test itself passes.
+crbug.com/648785 paint/invalidation/fixed-right-bottom-in-page-scale.html [ Skip ]
+
 crbug.com/637245 [ Mac10.11 Retina ] fast/html/details-add-summary-5-and-click.html [ Pass Failure ]
 crbug.com/637245 [ Mac10.11 Retina ] fast/html/details-add-summary-8-and-click.html [ Pass Failure ]
 crbug.com/637245 [ Mac10.11 Retina ] fast/html/details-add-summary-1-and-click.html [ Pass Failure ]
@@ -1296,10 +1235,6 @@
 
 crbug.com/645640 inspector/extensions/extensions-eval.html [ NeedsManualRebaseline ]
 
-crbug.com/649631 [ Win7 Win10 ] fast/borders/border-styles-split.html [ NeedsRebaseline ]
-crbug.com/649631 [ Win7 Win10 ] fast/backgrounds/border-radius-split-background.html [ NeedsRebaseline ]
-crbug.com/649631 [ Win7 Win10 ] fast/backgrounds/border-radius-split-background-image.html [ NeedsRebaseline ]
-
 crbug.com/650655 virtual/enable_wasm/http/tests/wasm/wasm_serialization_tests.html [ NeedsManualRebaseline ]
 
 crbug.com/649046 fast/forms/calendar-picker/calendar-picker-appearance-zoom125.html [ NeedsRebaseline ]
diff --git a/third_party/WebKit/LayoutTests/accessibility/bounds-calc.html b/third_party/WebKit/LayoutTests/accessibility/bounds-calc.html
index 2af241f..3f2a7813 100644
--- a/third_party/WebKit/LayoutTests/accessibility/bounds-calc.html
+++ b/third_party/WebKit/LayoutTests/accessibility/bounds-calc.html
@@ -51,6 +51,7 @@
     <svg id="svg" width="60" height="60">
       <circle role="button" id="svg_circle" r="25" cx="30" cy="30" stroke="blue" stroke-width="1"/>
     </svg>
+    <p id="twolines">First line<br>Second line</p>
 </div>
 
 <script>
@@ -71,22 +72,23 @@
     assert_approx_equals(axObject.boundsHeight, bounds.height, epsilon, id + " height");
 }
 
-function assertStaticTextChildDOMRectSameAsAXRect(id) {
+function assertStaticTextChildDOMRectSameAsAXRect(id, index) {
     var element = document.getElementById(id);
     var axObject = accessibilityController.accessibleElementById(id);
     var text = element.firstChild;
-    var axText = axObject.childAtIndex(0);
-    assert_equals(text.nodeType, Node.TEXT_NODE, id + " firstChild nodeType");
-    assert_equals(axText.role, "AXRole: AXStaticText", id + " AX first child role");
+    for (var i = 0; i < index; i++)
+        text = text.nextSibling;
+    var axText = axObject.childAtIndex(index);
+    assert_equals(text.nodeType, Node.TEXT_NODE, id + " child " + index + " nodeType");
+    assert_equals(axText.role, "AXRole: AXStaticText", id + " AX child " + index + " role");
     var range = document.createRange();
     range.selectNode(text);
     var bounds = range.getBoundingClientRect();
-    var axObject = accessibilityController.accessibleElementById(id);
     var epsilon = 1;
-    assert_approx_equals(axText.boundsX, bounds.left, epsilon, id + " left");
-    assert_approx_equals(axText.boundsY, bounds.top, epsilon, id + " left");
-    assert_approx_equals(axText.boundsWidth, bounds.width, epsilon, id + " left");
-    assert_approx_equals(axText.boundsHeight, bounds.height, epsilon, id + " left");
+    assert_approx_equals(axText.boundsX, bounds.left, epsilon, id + " child " + index + " left");
+    assert_approx_equals(axText.boundsY, bounds.top, epsilon, id + " child " + index + " top");
+    assert_approx_equals(axText.boundsWidth, bounds.width, epsilon, id + " child " + index + " width");
+    assert_approx_equals(axText.boundsHeight, bounds.height, epsilon, id + " child " + index + " height");
 }
 
 function assertOffsetContainerIs(id, containerId, opt_expectedResult) {
@@ -111,26 +113,31 @@
     assertDOMRectSameAsAXRect("radio");
     assertDOMRectSameAsAXRect("button");
     assertDOMRectSameAsAXRect("heading");
-    assertStaticTextChildDOMRectSameAsAXRect("heading");
+    assertStaticTextChildDOMRectSameAsAXRect("heading", 0);
     assertDOMRectSameAsAXRect("para");
-    assertStaticTextChildDOMRectSameAsAXRect("para");
+    assertStaticTextChildDOMRectSameAsAXRect("para", 0);
     assertDOMRectSameAsAXRect("span");
-    assertStaticTextChildDOMRectSameAsAXRect("span");
+    assertStaticTextChildDOMRectSameAsAXRect("span", 0);
     assertDOMRectSameAsAXRect("ul");
     assertDOMRectSameAsAXRect("li1");
     assertDOMRectSameAsAXRect("li2");
     assertDOMRectSameAsAXRect("div");
-    assertStaticTextChildDOMRectSameAsAXRect("div");
+    assertStaticTextChildDOMRectSameAsAXRect("div", 0);
     assertDOMRectSameAsAXRect("border");
-    assertStaticTextChildDOMRectSameAsAXRect("border");
+    assertStaticTextChildDOMRectSameAsAXRect("border", 0);
     assertDOMRectSameAsAXRect("padding");
-    assertStaticTextChildDOMRectSameAsAXRect("padding");
+    assertStaticTextChildDOMRectSameAsAXRect("padding", 0);
     assertDOMRectSameAsAXRect("margin");
-    assertStaticTextChildDOMRectSameAsAXRect("margin");
-    assertDOMRectSameAsAXRect("border_padding_margin");
-    assertStaticTextChildDOMRectSameAsAXRect("border_padding_margin");
+    assertStaticTextChildDOMRectSameAsAXRect("margin", 0);
+    assertDOMRectSameAsAXRect("border_padding_margin", 0);
+    assertStaticTextChildDOMRectSameAsAXRect("border_padding_margin", 0);
     assertDOMRectSameAsAXRect("svg");
     assertDOMRectSameAsAXRect("svg_circle");
+
+    // Test both static text elements in <p>First line<br>Second line</p>.
+    // We don't care about the bounding box of the <br> element in-between.
+    assertStaticTextChildDOMRectSameAsAXRect("twolines", 0);
+    assertStaticTextChildDOMRectSameAsAXRect("twolines", 2);
 }, "Test computed AX rect for some common objects");
 </script>
 
diff --git a/third_party/WebKit/LayoutTests/accessibility/inline-text-bounds-for-range-br.html b/third_party/WebKit/LayoutTests/accessibility/inline-text-bounds-for-range-br.html
new file mode 100644
index 0000000..843b49e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/accessibility/inline-text-bounds-for-range-br.html
@@ -0,0 +1,39 @@
+<!DOCTYPE HTML>
+<script src="../resources/testharness.js"></script>
+<script src="../resources/testharnessreport.js"></script>
+
+<p id="paragraph">Line 1<br>Line 2</p>
+
+<script>
+test(function(t) {
+    // Due to rounding we won't get identical bounds as getBoundingClientRect(),
+    // so allow the test to pass if we're within 1 pixel.
+    var epsilon = 1;
+
+    var axParagraph = accessibilityController.accessibleElementById("paragraph");
+    var axStaticText1 = axParagraph.childAtIndex(0);
+    eval("var axTextBounds1 = " + axStaticText1.boundsForRange(0, 6));
+
+    var paragraph = document.getElementById("paragraph");
+    var range = new Range();
+    range.setStart(paragraph.firstChild, 0);
+    range.setEnd(paragraph.firstChild, 6);
+    var rangeBounds = range.getBoundingClientRect();
+
+    assert_approx_equals(axTextBounds1.x, rangeBounds.left, epsilon, "Line 1 left");
+    assert_approx_equals(axTextBounds1.y, rangeBounds.top, epsilon, "Line 1 top");
+    assert_approx_equals(axTextBounds1.width, rangeBounds.width, epsilon, "Line 1 width");
+    assert_approx_equals(axTextBounds1.height, rangeBounds.height, epsilon, "Line 1 height");
+
+    var axStaticText2 = axParagraph.childAtIndex(2);
+    eval("var axTextBounds2 = " + axStaticText2.boundsForRange(0, 6));
+    range.setStart(paragraph.lastChild, 0);
+    range.setEnd(paragraph.lastChild, 6);
+    rangeBounds = range.getBoundingClientRect();
+
+    assert_approx_equals(axTextBounds2.x, rangeBounds.left, epsilon, "Line 2 left");
+    assert_approx_equals(axTextBounds2.y, rangeBounds.top, epsilon, "Line 2 top");
+    assert_approx_equals(axTextBounds2.width, rangeBounds.width, epsilon, "Line 2 width");
+    assert_approx_equals(axTextBounds2.height, rangeBounds.height, epsilon, "Line 2 height");
+}, "Check bounds of inline text boxes after line breaks");
+</script>
diff --git a/third_party/WebKit/LayoutTests/compositing/contents-opaque/overflow-hidden-child-layers-expected.txt b/third_party/WebKit/LayoutTests/compositing/contents-opaque/overflow-hidden-child-layers-expected.txt
index c6a81d6..42fe6fb 100644
--- a/third_party/WebKit/LayoutTests/compositing/contents-opaque/overflow-hidden-child-layers-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/contents-opaque/overflow-hidden-child-layers-expected.txt
@@ -10,8 +10,8 @@
       "children": [
         {
           "name": "LayoutBlockFlow DIV class='box'",
-          "position": [38, 30],
-          "bounds": [140, 140],
+          "position": [39, 31],
+          "bounds": [138, 138],
           "drawsContent": true,
           "backgroundColor": "#0000FF"
         }
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
index 5d81bdc8..35d9b26 100644
--- a/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/culling/scrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
index e1fb5a2..0b7ed078 100644
--- a/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/culling/translated-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png b/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
index 5d81bdc8..35d9b26 100644
--- a/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
+++ b/third_party/WebKit/LayoutTests/compositing/culling/unscrolled-within-boxshadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
index ea7e791f..e5bf5d70 100644
--- a/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/geometry/foreground-layer-expected.txt
@@ -11,14 +11,14 @@
       "children": [
         {
           "name": "LayoutBlockFlow (relative positioned) DIV class='main box'",
-          "position": [18, 88],
-          "bounds": [320, 320],
+          "position": [19, 89],
+          "bounds": [318, 318],
           "drawsContent": true,
           "backgroundColor": "#FF0000",
           "children": [
             {
               "name": "LayoutBlockFlow (positioned) DIV class='negative child'",
-              "position": [60, 60],
+              "position": [59, 59],
               "bounds": [50, 50],
               "transform": [
                 [1, 0, 0, 0],
@@ -29,21 +29,21 @@
             },
             {
               "name": "LayoutBlockFlow (relative positioned) DIV class='main box' (foreground) Layer",
-              "bounds": [320, 320],
+              "bounds": [318, 318],
               "drawsContent": true
             }
           ]
         },
         {
           "name": "LayoutBlockFlow (relative positioned) DIV class='main box'",
-          "position": [362, 18],
-          "bounds": [320, 320],
+          "position": [363, 19],
+          "bounds": [318, 318],
           "drawsContent": true,
           "backgroundColor": "#FF0000",
           "children": [
             {
               "name": "Child Containment Layer",
-              "position": [60, 60],
+              "position": [59, 59],
               "bounds": [200, 200],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
index 0353e22a..98f85369 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/composited-parent-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME",
-          "position": [-12, -12],
-          "bounds": [370, 220],
+          "position": [-11, -11],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
index 255528bb..81be0a1 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-delayed-expected.txt
@@ -13,13 +13,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='iframe'",
-          "position": [8, 108],
-          "bounds": [370, 220],
+          "position": [9, 109],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
index 8d96c672..5eb9222 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
index 7543194..5651940 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe2-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='iframe' class='composited'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
index 5839791..13d3e635 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/connect-compositing-iframe3-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='iframe' class='composited'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
index 8d96c672..5eb9222 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/enter-compositing-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
index 3ae65e99..29b412e 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/iframe-resize-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe' class='bigger'",
-          "position": [8, 8],
-          "bounds": [470, 190],
+          "position": [9, 9],
+          "bounds": [468, 188],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [400, 120],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt
index 3fd5ca4b..71b75af 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME",
-          "position": [-12, -12],
-          "bounds": [370, 220],
+          "position": [-11, -11],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
index 509057ba..86bc611d 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/overlapped-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt b/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
index 225aa06d..301b11b 100644
--- a/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/iframes/scrolling-iframe-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME id='parent-iframe'",
-          "position": [8, 8],
-          "bounds": [370, 220],
+          "position": [9, 9],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt b/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
index 2adfdeb..4b65745 100644
--- a/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
+++ b/third_party/WebKit/LayoutTests/compositing/layer-creation/rotate3d-overlap-expected.txt
@@ -12,22 +12,34 @@
       "children": [
         {
           "name": "LayoutBlockFlow (relative positioned) DIV class='box translateZ'",
-          "position": [25, 25],
-          "bounds": [106, 106],
+          "position": [23, 23],
+          "bounds": [110, 110],
           "drawsContent": true,
           "backgroundColor": "#0000FF"
         },
         {
-          "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate15'",
-          "position": [169, 25],
-          "bounds": [106, 106],
-          "drawsContent": true,
-          "backgroundColor": "#0000FF",
-          "transform": [
-            [0.965925826289068, 0.258819045102521, 0, 0],
-            [-0.258819045102521, 0.965925826289068, 0, 0],
-            [0, 0, 1, 0],
-            [0, 0, 0, 1]
+          "name": "Squashing Containment Layer",
+          "shouldFlattenTransform": false,
+          "children": [
+            {
+              "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate15'",
+              "position": [167, 23],
+              "bounds": [110, 110],
+              "drawsContent": true,
+              "backgroundColor": "#0000FF",
+              "transform": [
+                [0.965925826289068, 0.258819045102521, 0, 0],
+                [-0.258819045102521, 0.965925826289068, 0, 0],
+                [0, 0, 1, 0],
+                [0, 0, 0, 1]
+              ]
+            },
+            {
+              "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
+              "position": [167, 143],
+              "bounds": [110, 110],
+              "drawsContent": true
+            }
           ]
         },
         {
@@ -36,8 +48,8 @@
           "children": [
             {
               "name": "LayoutBlockFlow (relative positioned) DIV class='composited box rotate45'",
-              "position": [313, 25],
-              "bounds": [106, 106],
+              "position": [311, 23],
+              "bounds": [110, 110],
               "drawsContent": true,
               "backgroundColor": "#0000FF",
               "transform": [
@@ -49,8 +61,8 @@
             },
             {
               "name": "Squashing Layer (first squashed layer: LayoutBlockFlow (relative positioned) DIV class='box')",
-              "position": [313, 145],
-              "bounds": [106, 106],
+              "position": [311, 143],
+              "bounds": [110, 110],
               "drawsContent": true
             }
           ]
diff --git a/third_party/WebKit/LayoutTests/fast/borders/border-radius-different-width-001-double-expected.png b/third_party/WebKit/LayoutTests/fast/borders/border-radius-different-width-001-double-expected.png
index 103d4e3..eec840d3 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/border-radius-different-width-001-double-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/border-radius-different-width-001-double-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png
index 36476cb..d335492 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/borderRadiusDotted04-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/fast/borders/webkit-border-radius-expected.png b/third_party/WebKit/LayoutTests/fast/borders/webkit-border-radius-expected.png
index 2c885e6..05e118e 100644
--- a/third_party/WebKit/LayoutTests/fast/borders/webkit-border-radius-expected.png
+++ b/third_party/WebKit/LayoutTests/fast/borders/webkit-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output-expected.txt
index 9cc9f97..b8be91b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output-expected.txt
@@ -1,6 +1,7 @@
-CONSOLE MESSAGE: line 12: If a Suborigin makes a request, a response without an Access-Control-Allow-Suborigin header should fail and should output a reasonable error message.
 CONSOLE ERROR: Fetch API cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http-so://foobar.127.0.0.1:8000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
-CONSOLE MESSAGE: line 18: PASS: Fetch correctly failed
 CONSOLE ERROR: Fetch API cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http-so://foobar.127.0.0.1:8000' is therefore not allowed access. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
-CONSOLE MESSAGE: line 18: PASS: Fetch correctly failed
+This is a testharness.js-based test.
+PASS Custom headers causes preflight failure 
+PASS Lack of Access-Control-Allow-Suborigin on response causes failure 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output.php
index ddee8738..32ed050 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-fetch-failure-output.php
@@ -5,32 +5,13 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>Fetches from suborigins require responses with valid Access-Control-Allow-Suborigin header</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
 <script>
-if (window.testRunner) {
-  testRunner.waitUntilDone();
-  testRunner.dumpAsText();
-}
-console.log(
-  'If a Suborigin makes a request, a response without an ' +
-  'Access-Control-Allow-Suborigin header should fail and should output a ' +
-  'reasonable error message.');
-
-function success() {
-  console.log("PASS: Fetch correctly failed");
-  next();
-}
-
-function failure() {
-  console.log("FAIL: Fetch incorrectly succeeded");
-  next();
-}
-
-// First one should fail with preflight failure. Second one should
-// fail with access control header failure.
-var tests = [
-  function() {
+async_test(t => {
     var headers = new Headers();
     headers.append("x-custom-header", "foobar");
     var options = {
@@ -39,26 +20,16 @@
     fetch(
         "http://127.0.0.1:8000/security/resources/cors-script.php?cors=false",
         options)
-      .then(failure)
-      .catch(success);
-  },
-  function() {
+      .then(t.unreached_func('Fetch succeeded'))
+      .catch(t.step_func_done());
+  }, 'Custom headers causes preflight failure');
+
+async_test(t => {
       fetch(
         "http://127.0.0.1:8000/security/resources/cors-script.php?cors=false")
-      .then(failure)
-      .catch(success);
-  }
-];
-
-function next() {
-  if (tests.length !== 0) {
-    tests.shift()();
-  } else if (window.testRunner) {
-    testRunner.notifyDone();
-  }
-}
-
-next();
+      .then(t.unreached_func('Fetch succeeded'))
+      .catch(t.step_func_done());
+  }, 'Lack of Access-Control-Allow-Suborigin on response causes failure');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt
index 6937603..ed840e3b 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output-expected.txt
@@ -1,6 +1,7 @@
-CONSOLE MESSAGE: line 12: If a Suborigin makes a request, a response without an Access-Control-Allow-Suborigin header should fail and should output a reasonable error message.
 CONSOLE ERROR: XMLHttpRequest cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http-so://foobar.127.0.0.1:8000' is therefore not allowed access.
-ALERT: PASS: XHR correctly failed
 CONSOLE ERROR: XMLHttpRequest cannot load http://127.0.0.1:8000/security/resources/cors-script.php?cors=false. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http-so://foobar.127.0.0.1:8000' is therefore not allowed access.
-ALERT: PASS: XHR correctly failed
+This is a testharness.js-based test.
+PASS Custom headers causes preflight failure 
+PASS Lack of Access-Control-Allow-Suborigin on response causes failure 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php
index bae8eb3..7a4f9ad 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-failure-output.php
@@ -5,59 +5,30 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>XHRs from suborigins require responses with valid Access-Control-Allow-Suborigin header</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
 <script>
-if (window.testRunner) {
-  testRunner.waitUntilDone();
-  testRunner.dumpAsText();
-}
-console.log(
-    'If a Suborigin makes a request, a response without an ' +
-    'Access-Control-Allow-Suborigin header should fail and should ' +
-    'output a reasonable error message.');
-
-function success() {
-  alert('PASS: XHR correctly failed');
-  next();
-}
-
-function failure() {
-  alert('FAIL: XHR incorrectly succeeded');
-  next();
-}
-
-// First one should fail with preflight failure. Second one should
-// fail with access control header failure.
-var tests = [
-  function() {
+async_test(t => {
     var xhr = new XMLHttpRequest();
-    xhr.onerror = success;
-    xhr.onload = failure;
+    xhr.onerror = t.step_func_done();
+    xhr.onload = t.unreached_func('XHR succeeded');
     xhr.open('GET', 'http://127.0.0.1:8000/security/resources/' +
                     'cors-script.php?cors=false');
     xhr.setRequestHeader('x-custom-header', 'foobar');
     xhr.send();
-  },
-  function() {
+  }, 'Custom headers causes preflight failure');
+
+async_test(t => {
     var xhr = new XMLHttpRequest();
-    xhr.onerror = success;
-    xhr.onload = failure;
+    xhr.onerror = t.step_func_done();
+    xhr.onload = t.unreached_func();
     xhr.open('GET', 'http://127.0.0.1:8000/security/resources/' +
                     'cors-script.php?cors=false');
     xhr.send();
-  }
-];
-
-function next() {
-  if (tests.length !== 0) {
-    tests.shift()();
-  } else if (window.testRunner) {
-    testRunner.notifyDone();
-  }
-}
-
-next();
+  }, 'Lack of Access-Control-Allow-Suborigin on response causes failure');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php
index c7958f6..76ec18c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cors-xhr-preflight.php
@@ -19,28 +19,28 @@
 }
 
 SuboriginXHRTest.prototype.execute = function() {
-    var settings = this;
-    async_test(test => {
-        var xhr = new XMLHttpRequest();
+  var settings = this;
+  async_test(test => {
+      var xhr = new XMLHttpRequest();
 
-        if (settings.crossorigin_value === 'use-credentials') {
-          xhr.withCredentials = true;
-        }
+      if (settings.crossorigin_value === 'use-credentials') {
+        xhr.withCredentials = true;
+      }
 
-        if (settings.pass) {
-          xhr.onload = test.step_func_done();
-          xhr.onerror = test.unreached_func('Good XHR fired error handler.');
-        } else {
-          xhr.onload = test.unreached_func('Bad XHR successful.');
-          xhr.onerror = test.step_func_done();
-        }
+      if (settings.pass) {
+        xhr.onload = test.step_func_done();
+        xhr.onerror = test.unreached_func('Good XHR fired error handler.');
+      } else {
+        xhr.onload = test.unreached_func('Bad XHR successful.');
+        xhr.onerror = test.step_func_done();
+      }
 
-        xhr.open('GET', settings.src);
-        // Set a custom header to force a preflight. Even though the
-        // scheme/host/port of the source and destination origins are the same, the
-        // Suborigin should cause the request to be treated as cross-origin.
-        xhr.setRequestHeader('x-custom-header', 'foobar');
-        xhr.send();
+      xhr.open('GET', settings.src);
+      // Set a custom header to force a preflight. Even though the
+      // scheme/host/port of the source and destination origins are the same, the
+      // Suborigin should cause the request to be treated as cross-origin.
+      xhr.setRequestHeader('x-custom-header', 'foobar');
+      xhr.send();
     }, settings.name);
 };
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors-expected.txt
index f95bb99..313696c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors-expected.txt
@@ -1,15 +1,5 @@
 CONSOLE ERROR: line 1: Uncaught SomeError
-The Test passes if 'window.onerror' gets unsanitized information about an exception thrown in a script loaded with a 'crossorigin' attribute, and delivered with valid CORS headers.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS /SomeError/.test(msg) is true
-PASS url is "http://127.0.0.1:8000/security/resources/cors-script.php?fail=true&cors=http-so://foobar.127.0.0.1:8000"
-PASS line is 1
-PASS column is 1
-PASS window.errorObject is not null
-PASS successfullyParsed is true
-
-TEST COMPLETE
+This is a testharness.js-based test.
+PASS Verify that thrown exception is unsanitized when crossorigin script loaded with crossorigin attribute 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors.php
index cbe183e..fde9583 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-cors.php
@@ -4,31 +4,24 @@
 <!DOCTYPE html>
 <head>
 <meta charset="utf-8">
+<title>Verify that thrown exception is unsanitized when crossorigin script loaded with crossorigin attribute</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<script src="/js-test-resources/js-test.js"></script>
 <script>
-window.jsTestIsAsync = true;
-description(
-  'The Test passes if \'window.onerror\' gets unsanitized information about ' +
-  'an exception thrown in a script loaded with a \'crossorigin\' attribute, ' +
-  'and delivered with valid CORS headers.');
+setup({ allow_uncaught_exception: true });
 
 window.onerror = function(msg, url, line, column, error) {
-  window.msg = msg;
-  window.url = url;
-  window.line = line;
-  window.column = column;
-  window.errorObject = error;
-  shouldBeTrue('/SomeError/.test(msg)');
-  shouldBeEqualToString(
-    'url',
+  assert_true(/SomeError/.test(msg));
+  assert_equals(
+    url,
     'http://127.0.0.1:8000/security/resources/cors-script.php?' +
-    'fail=true&cors=http-so://foobar.127.0.0.1:8000');
-  shouldBe('line', '1');
-  shouldBe('column', '1');
-  shouldNotBe('window.errorObject', 'null');
-  finishJSTest();
+    'fail=true&cors=http-so://foobar.127.0.0.1:8000')
+  assert_equals(line, 1)
+  assert_equals(column, 1);
+  assert_not_equals(error, null);
+  done();
 }
 </script>
 <script crossorigin src="/security/resources/cors-script.php?fail=true&cors=http-so://foobar.127.0.0.1:8000"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors-expected.txt
index 2886f0e..3bd5f8ae 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors-expected.txt
@@ -1,15 +1,5 @@
 CONSOLE ERROR: line 1: Uncaught SomeError
-The test passes if 'window.onerror' gets sanitized information about an exception thrown in a script loaded from a suborigin.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS /SomeError/.test(msg) is false
-PASS url is ""
-PASS line is 0
-PASS column is 0
-PASS window.errorObject is null
-PASS successfullyParsed is true
-
-TEST COMPLETE
+This is a testharness.js-based test.
+PASS Verify that thrown exception is sanitized when crossorigin script loaded without crossorigin attribute 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors.php
index 7fac8ca1..901f8e42 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-script-window-onerror-no-cors.php
@@ -4,27 +4,21 @@
 <!DOCTYPE html>
 <head>
 <meta charset="utf-8">
+<title>Verify that thrown exception is sanitized when crossorigin script loaded without crossorigin attribute</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<script src="/js-test-resources/js-test.js"></script>
 <script>
-window.jsTestIsAsync = true;
-description(
-  'The test passes if \'window.onerror\' gets sanitized information about ' +
-  'an exception thrown in a script loaded from a suborigin.');
+setup({ allow_uncaught_exception: true });
 
 window.onerror = function(msg, url, line, column, error) {
-  window.msg = msg;
-  window.url = url;
-  window.line = line;
-  window.column = column;
-  window.errorObject = error;
-  shouldBeFalse('/SomeError/.test(msg)');
-  shouldBeEqualToString('url', '');
-  shouldBe('line', '0');
-  shouldBe('column', '0');
-  shouldBe('window.errorObject', 'null');
-  finishJSTest();
+  assert_false(/SomeError/.test(msg));
+  assert_equals(url, '');
+  assert_equals(line, 0);
+  assert_equals(column, 0);
+  assert_equals(error, null);
+  done();
 }
 </script>
 <script src="/security/resources/cors-script.php?fail=true&cors=false"></script>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception-expected.txt
deleted file mode 100644
index 8edc5066..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Cross-origin access to 'window.event' should throw a SecurityError.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS frame.contentWindow.event threw exception SecurityError: Blocked a frame with origin "http-so://foobar.127.0.0.1:8000" from accessing a cross-origin frame..
-PASS frame.contentWindow.event = 1; threw exception SecurityError: Blocked a frame with origin "http-so://foobar.127.0.0.1:8000" from accessing a cross-origin frame..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception.php
index 4406e3d4..59f462f 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-event-exception.php
@@ -5,29 +5,24 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>Crossorigin access to window.event should throw a SecurityError</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<iframe src="http://127.0.0.1:8000/"></iframe>
-<script src="/js-test-resources/js-test.js"></script>
 <script>
-window.jsTestIsAsync = true;
-description(
-  'Cross-origin access to \'window.event\' should throw a SecurityError.');
-
-var frame = document.querySelector('iframe');
-window.onload = function () {
-  shouldThrow(
-    'frame.contentWindow.event',
-    '"SecurityError: Blocked a frame with origin ' +
-    '\\"http-so://foobar.127.0.0.1:8000\\" from accessing a ' +
-    'cross-origin frame."');
-  shouldThrow(
-    'frame.contentWindow.event = 1;',
-    '"SecurityError: Blocked a frame with origin ' +
-    '\\"http-so://foobar.127.0.0.1:8000\\" from accessing a ' +
-    'cross-origin frame."');
-  finishJSTest();
+var iframe = document.createElement('iframe');
+iframe.src = 'http://127.0.0.1:8000/';
+iframe.onload = function() {
+  assert_throws('SecurityError', function() {
+      var e = iframe.contentWindow.event;
+    });
+  assert_throws('SecurityError', function() {
+      iframe.contentWindow.event = 1;
+    });
+  done();
 };
+document.body.appendChild(iframe);
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception-expected.txt
deleted file mode 100644
index f116532..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception-expected.txt
+++ /dev/null
@@ -1,11 +0,0 @@
-Cross-origin access to 'window.open' and 'window.opener' should throw a SecurityError.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS frame.contentWindow.open() threw exception SecurityError: Blocked a frame with origin "http-so://foobar.127.0.0.1:8000" from accessing a cross-origin frame..
-PASS frame.contentWindow.opener = 1; threw exception SecurityError: Failed to set the 'opener' property on 'Window': Blocked a frame with origin "http-so://foobar.127.0.0.1:8000" from accessing a cross-origin frame..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception.php
index c711b62..2e66a68 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-window-open-exception.php
@@ -5,30 +5,24 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>Crossorigin access to window.open and window.opener should throw a SecurityError</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
-<iframe src="/"></iframe>
-<script src="/js-test-resources/js-test.js"></script>
 <script>
-window.jsTestIsAsync = true; 
-description(
-  'Cross-origin access to \'window.open\' and \'window.opener\' should ' +
-  'throw a SecurityError.');
-var frame = document.querySelector('iframe');
-window.onload = function () {
-  shouldThrow(
-    'frame.contentWindow.open()',
-    '"SecurityError: Blocked a frame with origin ' +
-    '\\"http-so://foobar.127.0.0.1:8000\\" from accessing a ' +
-    'cross-origin frame."');
-  shouldThrow(
-    'frame.contentWindow.opener = 1;',
-    '"SecurityError: Failed to set the \'opener\' property on ' +
-    '\'Window\': Blocked a frame with origin ' +
-    '\\"http-so://foobar.127.0.0.1:8000\\" from accessing a ' +
-    'cross-origin frame."');
-  finishJSTest();
+var iframe = document.createElement('iframe');
+iframe.src = '/';
+iframe.onload = function() {
+  assert_throws('SecurityError', function() {
+      iframe.contentWindow.open();
+    });
+  assert_throws('SecurityError', function() {
+      iframe.contentWindow.opener = 1;
+    });
+  done();
 };
+document.body.appendChild(iframe);
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors-expected.txt
deleted file mode 100644
index 2c71315..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors-expected.txt
+++ /dev/null
@@ -1,10 +0,0 @@
-Ensure that scripts imported into a Worker from cross-origin hosts trigger sanitized onerror messages.
-
-On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
-
-
-PASS worker = new Worker("/workers/resources/worker-importscripts-onerror-sameorigin.js") threw exception SecurityError: Failed to construct 'Worker': Script at 'http://127.0.0.1:8000/workers/resources/worker-importscripts-onerror-sameorigin.js' cannot be accessed from origin 'http-so://foobar.127.0.0.1:8000'..
-PASS successfullyParsed is true
-
-TEST COMPLETE
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors.php
index 43d0704..98eea6c 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/crossorigin/suborigin-cross-origin-worker-onerror-no-cors.php
@@ -5,25 +5,19 @@
 <html>
 <head>
 <meta charset="utf-8">
-<script>
-window.jsTestIsAsync = true;
-window.isOnErrorTest = true;
-</script>
-<script src="/js-test-resources/js-test.js"></script>
+<title>Scripts imported into a worker from crossorigin hosts throw SecurityError</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
 <script>
-description('Ensure that scripts imported into a Worker from cross-origin hosts trigger sanitized onerror messages.');
-
 var worker;
 var worker_path =
-  '/workers/resources/worker-importscripts-onerror-sameorigin.js';
-shouldThrow(
-  'worker = new Worker("' + worker_path + '")',
-  '"SecurityError: Failed to construct \'Worker\': Script at ' +
-  '\'http://127.0.0.1:8000' + worker_path +
-  '\' cannot be accessed from origin \'http-so://foobar.127.0.0.1:8000\'."');
-finishJSTest();
+    '/workers/resources/worker-importscripts-onerror-sameorigin.js';
+assert_throws('SecurityError', function() {
+    worker = new Worker(worker_path);
+  });
+done();
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-allow-same-suborigin-access.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-allow-same-suborigin-access.html
index 4ad57b3f..7cbaebb 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-allow-same-suborigin-access.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-allow-same-suborigin-access.html
@@ -15,33 +15,29 @@
     test();
 }
 
-var tests = [
-  function() {
-    async_test(function(t) {
-        window.onmessage = t.step_func(function(event) {
-            assert_equals(event.data, 'I am a secret');
-            t.done();
-            next_test();
-          });
-        var iframe = document.createElement('iframe');
-        iframe.src = 'resources/iframe-reaches-into-parent.php?' +
-                     'suborigin=foobar&childsuborigin=foobar';
-        document.body.appendChild(iframe);
-      }, 'iframe reaches into parent')
-  },
-  function() {
-    async_test(function(t) {
-        window.onmessage = t.step_func(function(event) {
-            assert_equals(event.data, 'I am a secret');
-            t.done();
-            next_test();
-          });
-        var iframe = document.createElement('iframe');
-        iframe.src = 'resources/reach-into-iframe.php?' +
-                     'suborigin=foobar&childsuborigin=foobar';
-        document.body.appendChild(iframe);
-      }, 'Parent reaches into iframe')
+function make_iframe_test(test_name, resource) {
+  return function() {
+  async_test(t => {
+      window.onmessage = t.step_func(function(event) {
+          assert_equals(event.data, 'I am a secret');
+          // next_test() must be called before t.done() so that the next test,
+          // if one exists, is setup and the overall test doesn't end.
+          next_test();
+          t.done();
+        });
+      var iframe = document.createElement('iframe');
+      iframe.src = 'resources/' + resource + '?' +
+                   'suborigin=foobar&childsuborigin=foobar';
+      document.body.appendChild(iframe);
+    }, test_name);
   }
+}
+
+var tests = [
+  make_iframe_test(
+    'iframe reaches into parent', 'iframe-reaches-into-parent.php'),
+  make_iframe_test(
+    'parent reaches into iframe', 'reach-into-iframe.php')
 ];
 
 next_test();
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning-expected.txt
deleted file mode 100644
index 86f98e4..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning-expected.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-CONSOLE ERROR: line 9: Error with Suborigin header: Suborigin header with value 'foobar' was delivered via a <meta> element and not an HTTP header, which is disallowed. The Suborigin has been ignored.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning.html
deleted file mode 100644
index f910829..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-console-warning.html
+++ /dev/null
@@ -1,11 +0,0 @@
-<!DOCTYPE html>
-<html>
-<head>
-<meta charset="utf-8">
-<script>
-if (window.testRunner)
-  testRunner.dumpAsText();
-</script>
-<meta http-equiv="Suborigin" content="foobar">
-</head>
-</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-expected.txt
new file mode 100644
index 0000000..910c60e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-in-meta-disallowed-expected.txt
@@ -0,0 +1,5 @@
+CONSOLE ERROR: line 5: Error with Suborigin header: Suborigin header with value 'foobar' was delivered via a <meta> element and not an HTTP header, which is disallowed. The Suborigin has been ignored.
+This is a testharness.js-based test.
+PASS The <meta> tag does not allow a page to enter a suborigin. 
+Harness: the test ran to completion.
+
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
index 8bc72a6..d390006 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names-expected.txt
@@ -1,18 +1,12 @@
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character ''' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character '@' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character 'b' in suborigin policy. Suborigin policy options must start and end with a single quote.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character 'F' in suborigin.
-ALERT: I am a secret
 CONSOLE ERROR: Error with Suborigin header: Invalid character 'F' in suborigin.
-ALERT: I am a secret
+This is a testharness.js-based test.
+PASS Invalid suborigin names 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
index 70c5a27..397484d0 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-invalid-names.html
@@ -3,19 +3,12 @@
 <head>
 <meta charset="utf-8">
 <title>Invalid suborigin names</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 
+<body>
 <script>
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-
-function finish() {
-  if (window.testRunner)
-    testRunner.notifyDone();
-}
-
 var test_suborigin_names = [
   '',
   '\'foobar\'',
@@ -28,24 +21,31 @@
   'FOOBAR',
 ];
 
-var iframe;
-var i = 0;
-function next() {
-  if (i >= test_suborigin_names.length)
-    finish();
-  document.getElementById('iframe').src = 'resources/reach-into-iframe.php?' +
-                                          'childsuborigin=' +
-                                          test_suborigin_names[i];
-  i++;
-}
+async_test(t => {
+    var i = 0;
 
-window.onmessage = function(event) {
-  alert(event.data);
-  next();
-};
+    window.onmessage = t.step_func(function(event) {
+        assert_equals(event.data, 'I am a secret');
+        next();
+      });
 
-window.onload = function() {
-  next();
-};
+    function next() {
+      if (i >= test_suborigin_names.length) {
+        t.done();
+        return;
+      }
+
+      var iframe = document.createElement('iframe');
+      iframe.src =
+        'resources/reach-into-iframe.php?childsuborigin=' +
+        test_suborigin_names[i];
+      document.body.appendChild(iframe);
+
+      i++;
+    }
+
+    next();
+  }, 'Invalid suborigin names');
 </script>
-<iframe id="iframe"></iframe>
+</body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed-expected.txt
index b6f792d..f0f5ffd 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed-expected.txt
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed-expected.txt
@@ -1,2 +1,7 @@
 CONSOLE ERROR: Error with Suborigin header: Multiple Suborigin headers found. Ignoring all but the first.
+This is a testharness.js-based test.
+PASS 'foo' is the assigned suborigin 
+PASS 'bar' is not a valid suborigin 
+PASS Cannot access frame without suborigin 
+Harness: the test ran to completion.
 
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed.php b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed.php
index 1f61f72..166bc43 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed.php
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-multiple-suborigins-disallowed.php
@@ -5,11 +5,58 @@
 <html>
 <head>
 <meta charset="utf-8">
+<title>Only first of multiple suborigins assigned</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
 <body>
 <script>
-if (window.testRunner)
-  testRunner.dumpAsText();
+async_test(t => {
+    window.secret = 'unchanged';
+    var iframe = document.createElement('iframe');
+    iframe.src = 'resources/post-to-parent.php?suborigin=foo';
+    iframe.onload = t.step_func(function() {
+        try {
+          var secret = iframe.contentWindow.secret;
+          t.done();
+        } catch (e) {
+          assert_unreached(
+            'Unable to read secret from iframe in same suborigin');
+        }
+      });
+    document.body.appendChild(iframe);
+  }, '\'foo\' is the assigned suborigin');
+
+async_test(t => {
+    window.secret = 'unchanged';
+    var iframe = document.createElement('iframe');
+    iframe.src = 'resources/post-to-parent.php?suborigin=bar';
+    iframe.onload = t.step_func(function() {
+        try {
+          var secret = iframe.contentWindow.secret;
+          assert_unreached(
+            'Successfully read secret from iframe in a suborigin');
+        } catch (e) {
+          t.done();
+        }
+      });
+    document.body.appendChild(iframe);
+  }, '\'bar\' is not a valid suborigin');
+
+async_test(t => {
+    window.secret = 'unchanged';
+    var iframe = document.createElement('iframe');
+    iframe.src = 'resources/post-to-parent.php';
+    iframe.onload = t.step_func(function() {
+        try {
+          var secret = iframe.contentWindow.secret;
+          assert_unreached('Able to read secret from iframe without suborigin');
+        } catch (e) {
+          t.done();
+        }
+      });
+    document.body.appendChild(iframe);
+  }, 'Cannot access frame without suborigin');
 </script>
 </body>
 </html>
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt
deleted file mode 100644
index 7f0c9b9..0000000
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names-expected.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-ALERT: SecurityError: Blocked a frame with origin "http://127.0.0.1:8000" from accessing a cross-origin frame.
-
diff --git a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
index 6572af7..fb264ab 100644
--- a/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
+++ b/third_party/WebKit/LayoutTests/http/tests/security/suborigins/suborigin-valid-names.html
@@ -3,19 +3,11 @@
 <head>
 <meta charset="utf-8">
 <title>Valid suborigin names</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
 </head>
-
+<body>
 <script>
-if (window.testRunner) {
-  testRunner.dumpAsText();
-  testRunner.waitUntilDone();
-}
-
-function finish() {
-  if (window.testRunner)
-    testRunner.notifyDone();
-}
-
 var test_suborigin_names = [
   'foobar',
   'foob4r',
@@ -25,23 +17,33 @@
   'foobar-'
 ];
 
-var iframe;
-var i = 0;
-function next() {
-  if (i >= test_suborigin_names.length)
-    finish();
-  document.getElementById('iframe').src =
-    'resources/reach-into-iframe.php?childsuborigin=' + test_suborigin_names[i];
-  i++;
-}
+async_test(t => {
+    var i = 0;
 
-window.onmessage = function(event) {
-  alert(event.data);
-  next();
-};
+    window.onmessage = t.step_func(function(event) {
+        assert_equals(
+          event.data,
+          'SecurityError: Blocked a frame with origin ' +
+          '"http://127.0.0.1:8000" from accessing a cross-origin frame.');
+        next();
+      });
 
-window.onload = function() {
-  next();
-};
+    function next() {
+      if (i >= test_suborigin_names.length) {
+        t.done();
+        return;
+      }
+
+      var iframe = document.createElement('iframe');
+      iframe.src =
+        'resources/reach-into-iframe.php?childsuborigin=' +
+        test_suborigin_names[i];
+      document.body.appendChild(iframe);
+
+      i++;
+    }
+
+    next();
+  }, 'Valid suborigin names');
 </script>
-<iframe id="iframe"></iframe>
+</body>
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-add-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-add-repaint-expected.txt
index 9c13d858..8ec7014f 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-add-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-add-repaint-expected.txt
@@ -10,7 +10,7 @@
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow DIV id='test'",
-          "rect": [8, 8, 110, 110],
+          "rect": [7, 7, 112, 112],
           "reason": "style change"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-change-repaint-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-change-repaint-expected.txt
index 999c7fc..39056a8 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-change-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/box-shadow-change-repaint-expected.txt
@@ -10,7 +10,7 @@
       "paintInvalidations": [
         {
           "object": "LayoutBlockFlow DIV id='test'",
-          "rect": [8, 8, 120, 120],
+          "rect": [7, 7, 122, 122],
           "reason": "style change"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
index c09e9b57..ae41289 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
@@ -6,6 +6,10 @@
     },
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -23,10 +27,6 @@
     {
       "object": "LayoutBlockFlow (positioned) DIV id='overlay'",
       "reason": "layoutObject insertion"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
index e460773d..8f194db3 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -86,6 +86,10 @@
     },
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
@@ -95,10 +99,6 @@
     {
       "object": "LayoutBlockFlow BODY",
       "reason": "location change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
index 6eea390..3c1302f4 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -21,6 +21,14 @@
       "reason": "scroll"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "location change"
     },
@@ -42,14 +50,6 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
index 6eea390..3c1302f4 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/deep-nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -21,6 +21,14 @@
       "reason": "scroll"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "location change"
     },
@@ -42,14 +50,6 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
index 02dab6c..ffbf191 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-1-expected.txt
@@ -108,6 +108,14 @@
       "reason": "scroll"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "location change"
     },
@@ -129,14 +137,6 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
index 02dab6c..ffbf191 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/svg/nested-embedded-svg-size-changes-no-layout-triggers-2-expected.txt
@@ -108,6 +108,14 @@
       "reason": "scroll"
     },
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "location change"
     },
@@ -129,14 +137,6 @@
     },
     {
       "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/transform-replaced-shadows-expected.txt b/third_party/WebKit/LayoutTests/paint/invalidation/transform-replaced-shadows-expected.txt
index 6edfb4b..b0dece1 100644
--- a/third_party/WebKit/LayoutTests/paint/invalidation/transform-replaced-shadows-expected.txt
+++ b/third_party/WebKit/LayoutTests/paint/invalidation/transform-replaced-shadows-expected.txt
@@ -10,7 +10,7 @@
       "paintInvalidations": [
         {
           "object": "LayoutImage IMG id='box' class='smaller'",
-          "rect": [-12, 28, 280, 280],
+          "rect": [-10, 28, 276, 278],
           "reason": "subtree"
         }
       ]
diff --git a/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png
new file mode 100644
index 0000000..ce2c0e82
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-different-width-001-double-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-different-width-001-double-expected.png
new file mode 100644
index 0000000..103d4e3
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/border-radius-different-width-001-double-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/android/fast/borders/webkit-border-radius-expected.png b/third_party/WebKit/LayoutTests/platform/android/fast/borders/webkit-border-radius-expected.png
new file mode 100644
index 0000000..2c885e6
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/fast/borders/webkit-border-radius-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/android/paint/invalidation/caret-subpixel-expected.txt
similarity index 100%
rename from third_party/WebKit/LayoutTests/paint/invalidation/caret-subpixel-expected.txt
rename to third_party/WebKit/LayoutTests/platform/android/paint/invalidation/caret-subpixel-expected.txt
diff --git a/third_party/WebKit/LayoutTests/platform/android/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt b/third_party/WebKit/LayoutTests/platform/android/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
new file mode 100644
index 0000000..c09e9b57
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/paint/invalidation/scrolled-iframe-scrollbar-change-expected.txt
@@ -0,0 +1,33 @@
+{
+  "objectPaintInvalidations": [
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow HTML",
+      "reason": "forced by layout"
+    },
+    {
+      "object": "LayoutBlockFlow BODY class='noScroll'",
+      "reason": "style change"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='container'",
+      "reason": "incremental"
+    },
+    {
+      "object": "LayoutBlockFlow (positioned) DIV id='overlay'",
+      "reason": "layoutObject insertion"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/css/text-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-gradient-shadow-expected.txt
new file mode 100644
index 0000000..a861e517
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-gradient-shadow-expected.txt
@@ -0,0 +1,11 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x600
+  LayoutSVGRoot {svg} at (200,20) size 439x265
+    LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
+      LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
+        LayoutSVGGradientStop {stop} [offset=0.00] [color=#FF0000]
+        LayoutSVGGradientStop {stop} [offset=1.00] [color=#0000FF]
+    LayoutSVGText {text} at (200,20) size 399x225 contains 1 chunk(s)
+      LayoutSVGInlineText {#text} at (0,0) size 399x225
+        chunk 1 text run 1 at (200.00,200.00) startOffset 0 endOffset 3 width 399.00: "SVG"
diff --git a/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.txt b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.txt
new file mode 100644
index 0000000..30527e7
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/android/svg/css/text-shadow-multiple-expected.txt
@@ -0,0 +1,87 @@
+layer at (0,0) size 800x600
+  LayoutView at (0,0) size 800x600
+layer at (0,0) size 800x414
+  LayoutBlockFlow {html} at (0,0) size 800x414
+    LayoutBlockFlow {body} at (0,16) size 800x398
+      LayoutBlockFlow {p} at (0,0) size 800x20
+        LayoutText {#text} at (0,0) size 425x19
+          text run at (0,0) width 425: "The first two texts should look identical, as there is no shadow applied."
+      LayoutBlockFlow (anonymous) at (0,36) size 800x155
+        LayoutSVGRoot {svg} at (20,122) size 720x58
+          LayoutSVGText {text} at (20,20) size 720x58 contains 1 chunk(s)
+            LayoutSVGTSpan {tspan} at (0,0) size 96x57
+              LayoutSVGInlineText {#text} at (0,0) size 96x57
+                chunk 1 text run 1 at (20.00,66.80) startOffset 0 endOffset 4 width 96.00: "This"
+            LayoutSVGInlineText {#text} at (96,0) size 14x57
+              chunk 1 text run 1 at (116.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+            LayoutSVGTSpan {tspan} at (0,0) size 80x57
+              LayoutSVGInlineText {#text} at (110,0) size 80x57
+                chunk 1 text run 1 at (130.00,66.80) startOffset 0 endOffset 4 width 80.00: "text"
+            LayoutSVGInlineText {#text} at (190,0) size 14x57
+              chunk 1 text run 1 at (210.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+            LayoutSVGTSpan {tspan} at (0,0) size 305x57
+              LayoutSVGInlineText {#text} at (204,0) size 305x57
+                chunk 1 text run 1 at (224.00,66.80) startOffset 0 endOffset 14 width 305.00: "casts multiple"
+            LayoutSVGInlineText {#text} at (509,0) size 211x57
+              chunk 1 text run 1 at (529.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+              chunk 1 text run 1 at (543.00,66.80) startOffset 0 endOffset 7 width 197.00: "shadows"
+        LayoutText {#text} at (0,0) size 0x0
+      LayoutBlockFlow {p} at (0,207) size 800x20
+        LayoutText {#text} at (0,0) size 530x19
+          text run at (0,0) width 530: "The next two texts have subtle differences, as the stroke/fill is painted seperated in SVG."
+      LayoutBlockFlow (anonymous) at (0,243) size 800x155
+        LayoutSVGRoot {svg} at (0,312) size 747x91
+          LayoutSVGText {text} at (20,20) size 720x58 contains 1 chunk(s)
+            LayoutSVGTSpan {tspan} at (0,0) size 96x57
+              LayoutSVGInlineText {#text} at (0,0) size 96x57
+                chunk 1 text run 1 at (20.00,66.80) startOffset 0 endOffset 4 width 96.00: "This"
+            LayoutSVGInlineText {#text} at (96,0) size 14x57
+              chunk 1 text run 1 at (116.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+            LayoutSVGTSpan {tspan} at (0,0) size 80x57
+              LayoutSVGInlineText {#text} at (110,0) size 80x57
+                chunk 1 text run 1 at (130.00,66.80) startOffset 0 endOffset 4 width 80.00: "text"
+            LayoutSVGInlineText {#text} at (190,0) size 14x57
+              chunk 1 text run 1 at (210.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+            LayoutSVGTSpan {tspan} at (0,0) size 305x57
+              LayoutSVGInlineText {#text} at (204,0) size 305x57
+                chunk 1 text run 1 at (224.00,66.80) startOffset 0 endOffset 14 width 305.00: "casts multiple"
+            LayoutSVGInlineText {#text} at (509,0) size 211x57
+              chunk 1 text run 1 at (529.00,66.80) startOffset 0 endOffset 1 width 14.00: " "
+              chunk 1 text run 1 at (543.00,66.80) startOffset 0 endOffset 7 width 197.00: "shadows"
+        LayoutText {#text} at (0,0) size 0x0
+layer at (20,52) size 720x59
+  LayoutBlockFlow (positioned) {div} at (20,52) size 720x59
+    LayoutInline {span} at (0,0) size 96x57 [textStrokeWidth=1.00]
+      LayoutText {#text} at (0,1) size 96x57
+        text run at (0,1) width 96: "This"
+    LayoutText {#text} at (96,1) size 14x57
+      text run at (96,1) width 14: " "
+    LayoutInline {span} at (0,0) size 80x57 [textFillColor=#FFFFFF] [textStrokeWidth=1.00]
+      LayoutText {#text} at (110,1) size 80x57
+        text run at (110,1) width 80: "text"
+    LayoutText {#text} at (190,1) size 14x57
+      text run at (190,1) width 14: " "
+    LayoutInline {span} at (0,0) size 305x57
+      LayoutText {#text} at (204,1) size 305x57
+        text run at (204,1) width 305: "casts multiple"
+    LayoutText {#text} at (509,1) size 211x57
+      text run at (509,1) width 14: " "
+      text run at (523,1) width 197: "shadows"
+layer at (20,259) size 720x59
+  LayoutBlockFlow (positioned) {div} at (20,259) size 720x59
+    LayoutInline {span} at (0,0) size 96x57 [textStrokeWidth=1.00]
+      LayoutText {#text} at (0,1) size 96x57
+        text run at (0,1) width 96: "This"
+    LayoutText {#text} at (96,1) size 14x57
+      text run at (96,1) width 14: " "
+    LayoutInline {span} at (0,0) size 80x57 [textFillColor=#FFFFFF] [textStrokeWidth=1.00]
+      LayoutText {#text} at (110,1) size 80x57
+        text run at (110,1) width 80: "text"
+    LayoutText {#text} at (190,1) size 14x57
+      text run at (190,1) width 14: " "
+    LayoutInline {span} at (0,0) size 305x57
+      LayoutText {#text} at (204,1) size 305x57
+        text run at (204,1) width 305: "casts multiple"
+    LayoutText {#text} at (509,1) size 211x57
+      text run at (509,1) width 14: " "
+      text run at (523,1) width 197: "shadows"
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt
index 21fa972..6c009c83 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/iframes/invisible-nested-iframe-show-expected.txt
@@ -11,13 +11,13 @@
       "children": [
         {
           "name": "LayoutIFrame IFRAME",
-          "position": [-12, -12],
-          "bounds": [370, 220],
+          "position": [-11, -11],
+          "bounds": [368, 218],
           "drawsContent": true,
           "children": [
             {
               "name": "Frame Overflow Controls Host Layer",
-              "position": [35, 35],
+              "position": [34, 34],
               "bounds": [300, 150],
               "children": [
                 {
diff --git a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
index ce2c0e82..809c0e4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
index 757dc64..fe36d178 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 8b5411c..4f76bae 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 9714eab..aae43f1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 853a1c3f..b15258f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index adbd3b5..7037fe4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index 75c079b..09e0a08 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
index fe30a20..78158860 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.txt
index 1f99f133..708312da 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/fast/forms/select/menulist-appearance-basic-expected.txt
@@ -87,7 +87,13 @@
             text run at (4,1) width 33: "foo"
       LayoutText {#text} at (187,186) size 4x19
         text run at (187,186) width 4: " "
-      LayoutBR {BR} at (191,186) size 0x19
+      LayoutMenuList {SELECT} at (195,186) size 126x20 [bgcolor=#DDDDDD] [border: (1px solid #A9A9A9)]
+        LayoutBlockFlow (anonymous) at (1,1) size 124x18
+          LayoutText (anonymous) at (4,1) size 102x16
+            text run at (4,1) width 102: "September 2016"
+      LayoutText {#text} at (325,186) size 4x19
+        text run at (325,186) width 4: " "
+      LayoutBR {BR} at (329,186) size 0x19
       LayoutMenuList {SELECT} at (6,230) size 63x27 [bgcolor=#DDDDDD] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 61x26
           LayoutText (anonymous) at (6,1) size 28x23
diff --git a/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index ce087b8..9a997a4 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt
index eba788b..be5fc6e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/4776765-expected.txt
@@ -25,6 +25,16 @@
         },
         {
           "object": "LayoutBR BR",
+          "rect": [7, 83, 3, 21],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [7, 83, 3, 21],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
           "rect": [7, 63, 3, 21],
           "reason": "invalidate paint rectangle"
         }
@@ -33,6 +43,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt
index 0b45783..d8d9c51 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -39,6 +39,16 @@
                       "object": "LayoutBlockFlow DIV id='inner-editor'",
                       "rect": [2, 1002, 3, 18],
                       "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 18],
+                      "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 18],
+                      "reason": "invalidate paint rectangle"
                     }
                   ]
                 }
@@ -69,6 +79,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='text'",
       "reason": "subtree"
     },
@@ -79,6 +93,10 @@
     {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index 40f794a..1cc6316 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -71,6 +71,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -92,14 +100,6 @@
     {
       "object": "InlineTextBox 'test1'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt
index 81a9c37..1524af3 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/delete-into-nested-block-expected.txt
@@ -57,6 +57,16 @@
           "object": "LayoutText #text",
           "rect": [7, 126, 3, 22],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 126, 3, 22],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 126, 3, 22],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -103,6 +113,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
@@ -119,6 +133,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "layoutObject insertion"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt
index f00316f..9930e77 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/inline-outline-repaint-expected.txt
@@ -27,6 +27,16 @@
           "object": "LayoutText #text",
           "rect": [43, 174, 3, 22],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [43, 174, 3, 22],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [43, 174, 3, 22],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -37,6 +47,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "forced by layout"
     },
@@ -49,6 +63,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutInline SPAN id='test'",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index c513249..926b8ea 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
index cf039665..9d07cff7 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -39,6 +39,16 @@
               "object": "LayoutText #text",
               "rect": [60, 4, 3, 16],
               "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [60, 4, 3, 16],
+              "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [60, 4, 3, 16],
+              "reason": "invalidate paint rectangle"
             }
           ]
         }
@@ -47,6 +57,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='root'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt
index 509cf12a..367df1f 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-2-expected.txt
@@ -133,6 +133,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -387,10 +391,6 @@
     {
       "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
index 09598361..d0c8fc8 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/line-flow-with-floats-8-expected.txt
@@ -117,6 +117,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -355,10 +359,6 @@
     {
       "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-body-appear-expected.txt
index 0d733d16..7b67112 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/overflow-scroll-body-appear-expected.txt
@@ -69,6 +69,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -122,14 +130,6 @@
     {
       "object": "InlineTextBox '.'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
index caf3769..bd7c8bb0 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -73,6 +73,14 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "HorizontalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutView #document",
       "reason": "subtree"
     },
@@ -95,14 +103,6 @@
     {
       "object": "InlineTextBox 'scroll me'",
       "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt
index f96b17e7..705bdb43 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/selection-after-delete-expected.txt
@@ -22,6 +22,16 @@
           "object": "LayoutBR BR",
           "rect": [38, 78, 3, 21],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 78, 3, 21],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 78, 3, 21],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -32,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV id='test'",
       "reason": "forced by layout"
     },
@@ -44,6 +58,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBR BR",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
index 9b6e9c6..3ca55d73 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/shift-relative-positioned-container-with-image-addition-expected.txt
@@ -86,6 +86,10 @@
     },
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "location change"
     },
     {
@@ -95,10 +99,6 @@
     {
       "object": "LayoutBlockFlow BODY",
       "reason": "location change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt
index e6eb689..70f4942e 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/text-match-document-change-expected.txt
@@ -42,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -60,10 +64,6 @@
     {
       "object": "InlineTextBox 'After change'",
       "reason": "layoutObject insertion"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index da7216ee..327dde1 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -65,6 +65,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -134,10 +138,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -203,6 +203,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -268,10 +272,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "bounds change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -341,6 +341,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -378,10 +382,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.txt
index a861e517..a77f2e55 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-gradient-shadow-expected.txt
@@ -1,7 +1,7 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
-  LayoutSVGRoot {svg} at (200,20) size 439x265
+  LayoutSVGRoot {svg} at (200,20) size 438x264
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
       LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
         LayoutSVGGradientStop {stop} [offset=0.00] [color=#FF0000]
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.txt b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.txt
index 30527e7..f261d344 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/css/text-shadow-multiple-expected.txt
@@ -30,7 +30,7 @@
         LayoutText {#text} at (0,0) size 530x19
           text run at (0,0) width 530: "The next two texts have subtle differences, as the stroke/fill is painted seperated in SVG."
       LayoutBlockFlow (anonymous) at (0,243) size 800x155
-        LayoutSVGRoot {svg} at (0,312) size 747x91
+        LayoutSVGRoot {svg} at (0,311) size 747x94
           LayoutSVGText {text} at (20,20) size 720x58 contains 1 chunk(s)
             LayoutSVGTSpan {tspan} at (0,0) size 96x57
               LayoutSVGInlineText {#text} at (0,0) size 96x57
diff --git a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index 2d9e85a..365566b 100644
--- a/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/linux/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.png
index 0f690f79..b98822b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.txt
index 330b364..abf5fdf 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/fast/forms/select/menulist-appearance-basic-expected.txt
@@ -87,7 +87,13 @@
             text run at (8,1) width 36: "foo"
       LayoutText {#text} at (205,163) size 4x18
         text run at (205,163) width 4: " "
-      LayoutBR {BR} at (209,163) size 0x18
+      LayoutMenuList {SELECT} at (213,164) size 110x18 [bgcolor=#F8F8F8] [border: (1px solid #A6A6A6)]
+        LayoutBlockFlow (anonymous) at (1,1) size 108x16
+          LayoutText (anonymous) at (8,1) size 87x13
+            text run at (8,1) width 87: "September 2016"
+      LayoutText {#text} at (327,163) size 4x18
+        text run at (327,163) width 4: " "
+      LayoutBR {BR} at (331,163) size 0x18
       LayoutMenuList {SELECT} at (6,204) size 59x25 [bgcolor=#F8F8F8] [border: (1px solid #A6A6A6)]
         LayoutBlockFlow (anonymous) at (1,1) size 57x23
           LayoutText (anonymous) at (12,1) size 25x19
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index f8c9704..38a1039 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index 0fa2451..ec8a0c3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.10/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.png
index 67ae39d..9757171 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.txt
index 1125f17..68a3095 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/fast/forms/select/menulist-appearance-basic-expected.txt
@@ -87,7 +87,13 @@
             text run at (8,1) width 39: "foo"
       LayoutText {#text} at (212,163) size 4x18
         text run at (212,163) width 4: " "
-      LayoutBR {BR} at (216,163) size 0x18
+      LayoutMenuList {SELECT} at (220,164) size 116x18 [bgcolor=#F8F8F8] [border: (1px solid #A6A6A6)]
+        LayoutBlockFlow (anonymous) at (1,1) size 114x16
+          LayoutText (anonymous) at (8,1) size 93x13
+            text run at (8,1) width 93: "September 2016"
+      LayoutText {#text} at (340,163) size 4x18
+        text run at (340,163) width 4: " "
+      LayoutBR {BR} at (344,163) size 0x18
       LayoutMenuList {SELECT} at (6,204) size 61x25 [bgcolor=#F8F8F8] [border: (1px solid #A6A6A6)]
         LayoutBlockFlow (anonymous) at (1,1) size 59x23
           LayoutText (anonymous) at (12,1) size 27x19
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index c2540d5a..308f881 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index c9535f2a..90b7233 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
index 967c98b..29b3fc345 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -39,6 +39,16 @@
               "object": "LayoutText #text",
               "rect": [45, 6, 3, 13],
               "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [45, 6, 3, 13],
+              "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [45, 6, 3, 13],
+              "reason": "invalidate paint rectangle"
             }
           ]
         }
@@ -47,6 +57,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='root'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt
index 5805d97e..964bd06 100644
--- a/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac-mac10.9/paint/invalidation/textarea-caret-expected.txt
@@ -42,12 +42,26 @@
           "object": "LayoutText #text",
           "rect": [151, 10, 2, 14],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [151, 10, 2, 14],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [151, 10, 2, 14],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl TEXTAREA id='editor'",
       "reason": "subtree"
     },
@@ -80,6 +94,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
index 916eeb8d..af8a80b 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/multiple-masks-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/multiple-masks-expected.png
index 996a5560..65651aa6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/multiple-masks-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/multiple-masks-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/simple-composited-mask-expected.png b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/simple-composited-mask-expected.png
index dca2a9ff..2f63d68 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/simple-composited-mask-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/compositing/masks/simple-composited-mask-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
index 57ad0929..93286fa88 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
index d841027..969d6fd9 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/mac/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index c7c5b25f..2418bca6 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt
index 8988cbc..ec9bd476 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/4776765-expected.txt
@@ -25,6 +25,16 @@
         },
         {
           "object": "LayoutBR BR",
+          "rect": [7, 77, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [7, 77, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
           "rect": [7, 59, 3, 20],
           "reason": "invalidate paint rectangle"
         }
@@ -33,6 +43,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt
index 60299d6..cb356a3 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-subpixel-expected.txt
@@ -22,12 +22,26 @@
           "object": "LayoutBlockFlow DIV id='inner-editor'",
           "rect": [209, 10, 4, 15],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [209, 10, 4, 15],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [209, 10, 4, 15],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='target'",
       "reason": "subtree"
     },
@@ -38,6 +52,10 @@
     {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
index 58a372b..5a9289a 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -39,6 +39,16 @@
                       "object": "LayoutBlockFlow DIV id='inner-editor'",
                       "rect": [2, 1002, 3, 15],
                       "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 15],
+                      "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 15],
+                      "reason": "invalidate paint rectangle"
                     }
                   ]
                 }
@@ -69,6 +79,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='text'",
       "reason": "subtree"
     },
@@ -79,6 +93,10 @@
     {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index 01653d5..d4d2b19 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -71,6 +71,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -92,14 +100,6 @@
     {
       "object": "InlineTextBox 'test1'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
index 87390c9e..4e0bf06 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/delete-into-nested-block-expected.txt
@@ -57,6 +57,16 @@
           "object": "LayoutText #text",
           "rect": [7, 118, 3, 21],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 118, 3, 21],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 118, 3, 21],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -103,6 +113,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
@@ -119,6 +133,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "layoutObject insertion"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt
index 969e6d6..05d34eae 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/inline-outline-repaint-expected.txt
@@ -27,6 +27,16 @@
           "object": "LayoutText #text",
           "rect": [45, 183, 3, 20],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [45, 183, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [45, 183, 3, 20],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -37,6 +47,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "forced by layout"
     },
@@ -49,6 +63,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutInline SPAN id='test'",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index 842ac69..fe8daf5 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
index bb30929..72b8b765 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -39,6 +39,16 @@
               "object": "LayoutText #text",
               "rect": [38, 6, 3, 13],
               "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [38, 6, 3, 13],
+              "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [38, 6, 3, 13],
+              "reason": "invalidate paint rectangle"
             }
           ]
         }
@@ -47,6 +57,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='root'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt
index 1fcd677..134678d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -113,6 +113,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -311,14 +319,6 @@
     {
       "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-body-appear-expected.txt
index 37b2e39..4b7a749 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/overflow-scroll-body-appear-expected.txt
@@ -69,6 +69,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -122,14 +130,6 @@
     {
       "object": "InlineTextBox '.'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
index b73c00d..7fc5d22 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -73,6 +73,14 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "HorizontalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutView #document",
       "reason": "subtree"
     },
@@ -95,14 +103,6 @@
     {
       "object": "InlineTextBox 'scroll me'",
       "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt
index 7da2a029..7b6f62d 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/selection-after-delete-expected.txt
@@ -22,6 +22,16 @@
           "object": "LayoutBR BR",
           "rect": [38, 74, 3, 20],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 74, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 74, 3, 20],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -32,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV id='test'",
       "reason": "forced by layout"
     },
@@ -44,6 +58,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBR BR",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt
index d0241ece..985885f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/text-match-document-change-expected.txt
@@ -42,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -60,10 +64,6 @@
     {
       "object": "InlineTextBox 'After change'",
       "reason": "layoutObject insertion"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt
index 53aebf9..a763b5e 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/textarea-caret-expected.txt
@@ -42,12 +42,26 @@
           "object": "LayoutText #text",
           "rect": [131, 10, 2, 14],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [131, 10, 2, 14],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [131, 10, 2, 14],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl TEXTAREA id='editor'",
       "reason": "subtree"
     },
@@ -80,6 +94,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index cb25b9a..76072b91 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -65,6 +65,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -134,10 +138,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -203,6 +203,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -268,10 +272,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "bounds change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -341,6 +341,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -378,10 +382,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.txt
index 445aeed..1a35683 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-gradient-shadow-expected.txt
@@ -1,7 +1,7 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
-  LayoutSVGRoot {svg} at (200,20) size 441x270
+  LayoutSVGRoot {svg} at (200,20) size 440x269
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
       LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
         LayoutSVGGradientStop {stop} [offset=0.00] [color=#FF0000]
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.txt b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.txt
index 0d86443..2cc45e1 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/css/text-shadow-multiple-expected.txt
@@ -30,7 +30,7 @@
         LayoutText {#text} at (0,0) size 567x18
           text run at (0,0) width 567: "The next two texts have subtle differences, as the stroke/fill is painted seperated in SVG."
       LayoutBlockFlow (anonymous) at (0,238) size 800x154
-        LayoutSVGRoot {svg} at (0,308) size 744x89
+        LayoutSVGRoot {svg} at (0,307) size 744x92
           LayoutSVGText {text} at (20,21) size 717x56 contains 1 chunk(s)
             LayoutSVGTSpan {tspan} at (0,0) size 95x56
               LayoutSVGInlineText {#text} at (0,0) size 95x56
diff --git a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
index 1056d1e..62eb78f 100644
--- a/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/mac/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
index 3c1b7dd6..e3e3cec9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/compositing/masks/masked-ancestor-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-expected.png
index 5ac01f3..826e9b8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-image-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-image-expected.png
index e64ac73..b0bc567 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-image-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/backgrounds/border-radius-split-background-image-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
index d01b6ab..8defd39 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-radius-mask-video-shadow-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-styles-split-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-styles-split-expected.png
index 34a8820f..2393034d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-styles-split-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/borders/border-styles-split-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
index 6bc47b3..5501a0a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
index 132f3499..83921f9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom125-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
index 076cda4e..74e46ab 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-appearance-zoom200-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
index 99a8f81..2f7a58c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-one-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
index 99680dc..a78036d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/color/color-suggestion-picker-two-row-appearance-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
index f3177b8f..d5802e9c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.txt b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.txt
index 807a15e..8208717 100644
--- a/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/fast/forms/select/menulist-appearance-basic-expected.txt
@@ -87,7 +87,13 @@
             text run at (4,1) width 34: "foo"
       LayoutText {#text} at (189,188) size 4x17
         text run at (189,188) width 4: " "
-      LayoutBR {BR} at (193,188) size 0x17
+      LayoutMenuList {SELECT} at (197,187) size 126x20 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
+        LayoutBlockFlow (anonymous) at (1,1) size 124x18
+          LayoutText (anonymous) at (4,1) size 102x16
+            text run at (4,1) width 102: "September 2016"
+      LayoutText {#text} at (327,188) size 4x17
+        text run at (327,188) width 4: " "
+      LayoutBR {BR} at (331,188) size 0x17
       LayoutMenuList {SELECT} at (6,229) size 63x26 [bgcolor=#FFFFFF] [border: (1px solid #A9A9A9)]
         LayoutBlockFlow (anonymous) at (1,1) size 61x25
           LayoutText (anonymous) at (6,1) size 28x22
diff --git a/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png b/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
index 399e0c4..2eb35bf 100644
--- a/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/http/tests/webfont/popup-menu-load-webfont-after-open-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt
index f28a8d1..2404e86 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/4776765-expected.txt
@@ -25,6 +25,16 @@
         },
         {
           "object": "LayoutBR BR",
+          "rect": [7, 77, 3, 19],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [7, 77, 3, 19],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
           "rect": [7, 59, 3, 19],
           "reason": "invalidate paint rectangle"
         }
@@ -33,6 +43,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt
new file mode 100644
index 0000000..c009fdc
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-subpixel-expected.txt
@@ -0,0 +1,62 @@
+{
+  "name": "Content Root Layer",
+  "bounds": [800, 600],
+  "children": [
+    {
+      "name": "LayoutView #document",
+      "bounds": [800, 600],
+      "contentsOpaque": true,
+      "drawsContent": true,
+      "paintInvalidations": [
+        {
+          "object": "LayoutTextControl INPUT id='target'",
+          "rect": [8, 8, 224, 22],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [10, 11, 201, 16],
+          "reason": "subtree"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [208, 10, 4, 18],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [208, 10, 4, 18],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBlockFlow DIV id='inner-editor'",
+          "rect": [208, 10, 4, 18],
+          "reason": "invalidate paint rectangle"
+        }
+      ]
+    }
+  ],
+  "objectPaintInvalidations": [
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='target'",
+      "reason": "subtree"
+    },
+    {
+      "object": "LayoutBlockFlow DIV id='inner-editor'",
+      "reason": "subtree"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    }
+  ]
+}
+
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
index dff41bb..7f8cd0d4 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/caret-with-composited-scroll-expected.txt
@@ -39,6 +39,16 @@
                       "object": "LayoutBlockFlow DIV id='inner-editor'",
                       "rect": [2, 1002, 3, 18],
                       "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 18],
+                      "reason": "invalidate paint rectangle"
+                    },
+                    {
+                      "object": "LayoutBlockFlow DIV id='inner-editor'",
+                      "rect": [2, 1002, 3, 18],
+                      "reason": "invalidate paint rectangle"
                     }
                   ]
                 }
@@ -69,6 +79,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='text'",
       "reason": "subtree"
     },
@@ -79,6 +93,10 @@
     {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
index a34ee3f..eec44b5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/compositing/iframe-inside-squashed-layer-expected.txt
@@ -71,6 +71,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -92,14 +100,6 @@
     {
       "object": "InlineTextBox 'test1'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt
index 68571ea..6b996e2 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/delete-into-nested-block-expected.txt
@@ -57,6 +57,16 @@
           "object": "LayoutText #text",
           "rect": [7, 118, 3, 20],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 118, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [7, 118, 3, 20],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -103,6 +113,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "outline"
     },
@@ -119,6 +133,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "layoutObject insertion"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt
index 3f3ed422..fa91e45 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/inline-outline-repaint-expected.txt
@@ -27,6 +27,16 @@
           "object": "LayoutText #text",
           "rect": [45, 182, 3, 20],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [45, 182, 3, 20],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [45, 182, 3, 20],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -37,6 +47,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV",
       "reason": "forced by layout"
     },
@@ -49,6 +63,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutInline SPAN id='test'",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
index 5c5cb52..e41c0d6a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-composited-scrolling-container-expected.txt
@@ -80,12 +80,12 @@
   ],
   "objectPaintInvalidations": [
     {
-      "object": "LayoutTextControl INPUT id='root'",
-      "reason": "subtree"
-    },
-    {
       "object": "Caret",
       "reason": "invalidate paint rectangle"
+    },
+    {
+      "object": "LayoutTextControl INPUT id='root'",
+      "reason": "subtree"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
index 2c09ac4..7be285e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/invalidate-caret-in-non-composited-scrolling-container-expected.txt
@@ -39,6 +39,16 @@
               "object": "LayoutText #text",
               "rect": [64, 4, 3, 16],
               "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [64, 4, 3, 16],
+              "reason": "invalidate paint rectangle"
+            },
+            {
+              "object": "LayoutText #text",
+              "rect": [64, 4, 3, 16],
+              "reason": "invalidate paint rectangle"
             }
           ]
         }
@@ -47,6 +57,10 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl INPUT id='root'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt
index 49cb14a..f8dfd64 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/line-flow-with-floats-9-expected.txt
@@ -113,6 +113,14 @@
   ],
   "objectPaintInvalidations": [
     {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -311,14 +319,6 @@
     {
       "object": "InlineTextBox 'wonder is, that there\u2018s any one left alive!\u2019'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-body-appear-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-body-appear-expected.txt
index 0047151..3bc8375 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-body-appear-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/overflow-scroll-body-appear-expected.txt
@@ -69,6 +69,14 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "style change"
     },
     {
@@ -122,14 +130,6 @@
     {
       "object": "InlineTextBox '.'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
index 8742ad9..e3747d8 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/repaint-during-scroll-with-zoom-expected.txt
@@ -73,6 +73,14 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "HorizontalScrollbar",
+      "reason": "scroll"
+    },
+    {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutView #document",
       "reason": "subtree"
     },
@@ -95,14 +103,6 @@
     {
       "object": "InlineTextBox 'scroll me'",
       "reason": "subtree"
-    },
-    {
-      "object": "HorizontalScrollbar",
-      "reason": "scroll"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt
index f8c6c013..fbafe7f 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/selection-after-delete-expected.txt
@@ -22,6 +22,16 @@
           "object": "LayoutBR BR",
           "rect": [38, 74, 3, 19],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 74, 3, 19],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutBR BR",
+          "rect": [38, 74, 3, 19],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
@@ -32,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBlockFlow DIV id='test'",
       "reason": "forced by layout"
     },
@@ -44,6 +58,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutBR BR",
       "reason": "forced by layout"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt
index 0545b834..373cb1a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/text-match-document-change-expected.txt
@@ -42,6 +42,10 @@
       "reason": "layoutObject removal"
     },
     {
+      "object": "VerticalScrollbar",
+      "reason": "scroll"
+    },
+    {
       "object": "LayoutBlockFlow HTML",
       "reason": "forced by layout"
     },
@@ -60,10 +64,6 @@
     {
       "object": "InlineTextBox 'After change'",
       "reason": "layoutObject insertion"
-    },
-    {
-      "object": "VerticalScrollbar",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt
index 65ad43a..abf1f3e 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/textarea-caret-expected.txt
@@ -37,12 +37,26 @@
           "object": "LayoutText #text",
           "rect": [186, 10, 2, 18],
           "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [186, 10, 2, 18],
+          "reason": "invalidate paint rectangle"
+        },
+        {
+          "object": "LayoutText #text",
+          "rect": [186, 10, 2, 18],
+          "reason": "invalidate paint rectangle"
         }
       ]
     }
   ],
   "objectPaintInvalidations": [
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutTextControl TEXTAREA id='editor'",
       "reason": "subtree"
     },
@@ -67,6 +81,10 @@
       "reason": "invalidate paint rectangle"
     },
     {
+      "object": "Caret",
+      "reason": "invalidate paint rectangle"
+    },
+    {
       "object": "LayoutText #text",
       "reason": "subtree"
     },
diff --git a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
index 1d5da92..2b513fb9a 100644
--- a/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/paint/invalidation/window-resize-vertical-writing-mode-expected.txt
@@ -65,6 +65,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -134,10 +138,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -203,6 +203,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -268,10 +272,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "bounds change"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
@@ -341,6 +341,10 @@
   "objectPaintInvalidations": [
     {
       "object": "LayoutView #document",
+      "reason": "scroll"
+    },
+    {
+      "object": "LayoutView #document",
       "reason": "bounds change"
     },
     {
@@ -378,10 +382,6 @@
     {
       "object": "InlineTextBox 'NNNN'",
       "reason": "forced by layout"
-    },
-    {
-      "object": "LayoutView #document",
-      "reason": "scroll"
     }
   ]
 }
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-gradient-shadow-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-gradient-shadow-expected.txt
index 5a3f6bb..4dbbbd5 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-gradient-shadow-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-gradient-shadow-expected.txt
@@ -1,7 +1,7 @@
 layer at (0,0) size 800x600
   LayoutView at (0,0) size 800x600
 layer at (0,0) size 800x600
-  LayoutSVGRoot {svg} at (200,22) size 441x261
+  LayoutSVGRoot {svg} at (200,22) size 440x260
     LayoutSVGHiddenContainer {defs} at (0,0) size 0x0
       LayoutSVGResourceLinearGradient {linearGradient} [id="gradient"] [gradientUnits=objectBoundingBox] [start=(0,0)] [end=(1,0)]
         LayoutSVGGradientStop {stop} [offset=0.00] [color=#FF0000]
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.txt b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.txt
index 3f0e8e4..ee2764c 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.txt
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/css/text-shadow-multiple-expected.txt
@@ -30,7 +30,7 @@
         LayoutText {#text} at (0,0) size 568x17
           text run at (0,0) width 568: "The next two texts have subtle differences, as the stroke/fill is painted seperated in SVG."
       LayoutBlockFlow (anonymous) at (0,238) size 800x154
-        LayoutSVGRoot {svg} at (0,308) size 744x89
+        LayoutSVGRoot {svg} at (0,307) size 744x92
           LayoutSVGText {text} at (20,21) size 717x56 contains 1 chunk(s)
             LayoutSVGTSpan {tspan} at (0,0) size 95x56
               LayoutSVGInlineText {#text} at (0,0) size 95x56
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
index 11caa10..b52fae9 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-background-images-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
index 084f6ba..7277c25d 100644
--- a/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
+++ b/third_party/WebKit/LayoutTests/platform/win/svg/zoom/page/zoom-img-preserveAspectRatio-support-1-expected.png
Binary files differ
diff --git a/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash-expected.txt b/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash-expected.txt
new file mode 100644
index 0000000..b7ff4a9b
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash-expected.txt
@@ -0,0 +1 @@
+If it doesn't crash, this test has passed.
diff --git a/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash.html b/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash.html
new file mode 100644
index 0000000..b2c36f0
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/storage/websql/transaction-removed-context-crash.html
@@ -0,0 +1,30 @@
+<!DOCTYPE html>
+<title>Transaction from removed execution context</title>
+<script>
+if (window.testRunner) {
+    testRunner.dumpAsText();
+    testRunner.waitUntilDone();
+}
+
+var script = `
+var db = openDatabase('db' + Math.random() + Date.now(), '1.0', 'test database', 2*1024);
+db.transaction(tx => {
+    tx.executeSql('DROP TABLE IF EXISTS TestTable');
+    tx.executeSql('CREATE TABLE IF NOT EXISTS TestTable (id unique,text)');
+    tx.executeSql('DELETE FROM TestTable WHERE id=?', [1]);
+    frameElement.parentNode.removeChild(frameElement);
+});
+`;
+
+window.addEventListener('DOMContentLoaded', e => {
+    var blob = new Blob(['<script>' + script +  '<\/script>'], {'type': 'text/html'});
+    var iframe = document.createElement('iframe');
+    document.body.appendChild(iframe);
+    iframe.src = URL.createObjectURL(blob);
+    if (window.testRunner)
+        window.setTimeout(() => { testRunner.notifyDone() }, 250);
+});
+</script>
+<body>
+If it doesn't crash, this test has passed.
+</body>
diff --git a/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html
new file mode 100644
index 0000000..0f7666e
--- /dev/null
+++ b/third_party/WebKit/LayoutTests/webaudio/realtimeanalyser-fftsize-reset.html
@@ -0,0 +1,132 @@
+<!doctype html>
+<html>
+  <head>
+    <title>Test fftSize Changes Resetting AnalyserNode State </title>
+    <script src="../resources/testharness.js"></script>
+    <script src="../resources/testharnessreport.js"></script>
+    <script src="resources/audio-testing.js"></script>
+  </head>
+
+  <body>
+    <script>
+      // Fairly arbitrary sample rate.
+      var sampleRate = 24000;
+
+      var audit = Audit.createTaskRunner();
+
+      // Verify that setting the fftSize resets the memory for the FFT smoothing
+      // operation.  Only a few of the possible variations are tested.
+
+      audit.defineTask("128->1024", function (taskDone) {
+        testFFTSize({
+          initialFFTSize: 128,
+          finalFFTSize: 1024,
+          errorThreshold: {
+            relativeThreshold: 1.9095e-6
+          }
+        }).then(taskDone);
+      });
+
+      audit.defineTask("512->256", function (taskDone) {
+        testFFTSize({
+          initialFFTSize: 512,
+          finalFFTSize: 256,
+          errorThreshold: {
+            relativeThreshold: 1.8166e-6
+          }
+        }).then(taskDone);
+      });
+
+      function testFFTSize(options) {
+        var {
+          initialFFTSize, finalFFTSize, errorThreshold
+        } = options;
+
+        // The duration is fairly arbitrary as long as it's long enough for the
+        // FFT test.
+        var context = new OfflineAudioContext(1, sampleRate, sampleRate);
+
+        // Actual source doesn't matter but a sawtooth is a nice waveform with
+        // lots of harmonic content.
+        var osc = context.createOscillator();
+        osc.type = "sawtooth";
+
+        // The analyser under test.
+        var testAnalyser = context.createAnalyser();
+        testAnalyser.fftSize = initialFFTSize;
+
+        // The reference analyser.  The fftSize is fixed to the desired value,
+        // and we turn off smoothing so that we get the FFT of the current time
+        // data.
+        var refAnalyser = context.createAnalyser();
+        refAnalyser.fftSize = finalFFTSize;
+        refAnalyser.smoothingTimeConstant = 0;
+
+        // Setup the graph and start the oscillator.
+        osc.connect(testAnalyser)
+          .connect(context.destination);
+        osc.connect(refAnalyser)
+          .connect(context.destination);
+
+        osc.start();
+
+        // Let the analyser smooth a few FFTs (rather arbitrary, but should be
+        // more than one), then switch the size.
+
+        var suspendFrame = 4 * initialFFTSize;
+        context.suspend(suspendFrame / context.sampleRate)
+          .then(function () {
+            testAnalyser.fftSize = finalFFTSize;
+          })
+          .then(context.resume.bind(context));
+
+        // Wait some frames and grab the FFT data.  This is fairly arbitrary
+        // too, and can be independent of the FFT sizes.
+        suspendFrame += 1024;
+        context.suspend(suspendFrame / context.sampleRate)
+          .then(function () {
+            var testFFT = new Float32Array(testAnalyser.frequencyBinCount);
+            var refFFT = new Float32Array(refAnalyser.frequencyBinCount)
+            var testSignal = new Float32Array(testAnalyser.fftSize);
+            var refSignal = new Float32Array(refAnalyser.fftSize);
+
+            testAnalyser.getFloatTimeDomainData(testSignal);
+            refAnalyser.getFloatTimeDomainData(refSignal);
+
+            testAnalyser.getFloatFrequencyData(testFFT);
+            refAnalyser.getFloatFrequencyData(refFFT);
+
+            // Convert the FFT data from dB to linear
+            testFFT = testFFT.map(x => Math.pow(10, x / 20));
+            refFFT = refFFT.map(x => Math.pow(10, x / 20));
+
+            // The test data has smoothing applied, but the reference doesn't.
+            // Apply the smoothing factor to the reference data.
+            var smoothing = 1 - testAnalyser.smoothingTimeConstant;
+            refFFT = refFFT.map(x => x * smoothing);
+
+            var success = true;
+
+            // First a basic sanity check that the time domain signals are
+            // exactly the same for both analysers.
+            success = Should("Time data", testSignal)
+              .beCloseToArray(refSignal, 0) && success;
+
+            success = Should("Linear FFT data after setting fftSize = " + testAnalyser.fftSize,
+                testFFT)
+              .beCloseToArray(refFFT, errorThreshold) && success;
+
+            Should("*** Changing fftSize from " + initialFFTSize + " to " + finalFFTSize, success)
+              .summarize(
+                 "correctly reset the smoothing state",
+                "did not correctly reset the smoothing state");
+          })
+          .then(context.resume.bind(context));
+
+        return context.startRendering();
+      }
+
+      audit.runTasks();
+    </script>
+  </body>
+</html>
diff --git a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
index acb1388..1da00243 100644
--- a/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
+++ b/third_party/WebKit/LayoutTests/webexposed/global-interface-listing-expected.txt
@@ -4075,7 +4075,6 @@
     getter permissions
     getter platform
     getter plugins
-    getter pointerEnabled
     getter presentation
     getter product
     getter productSub
diff --git a/third_party/WebKit/Source/core/events/EventTarget.cpp b/third_party/WebKit/Source/core/events/EventTarget.cpp
index f273e0e..4d2932f4 100644
--- a/third_party/WebKit/Source/core/events/EventTarget.cpp
+++ b/third_party/WebKit/Source/core/events/EventTarget.cpp
@@ -597,21 +597,10 @@
             if (event->isPointerEvent() && static_cast<PointerEvent*>(event)->pointerType() == "touch")
                 UseCounter::count(executingWindow->document(), UseCounter::PointerDownFiredForTouch);
         }
-    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerenter, UseCounter::PointerEnterLeaveFired)
-        || checkTypeThenUseCount(event, EventTypeNames::pointerleave, UseCounter::PointerEnterLeaveFired)
-        || checkTypeThenUseCount(event, EventTypeNames::pointerover, UseCounter::PointerOverOutFired)
-        || checkTypeThenUseCount(event, EventTypeNames::pointerout, UseCounter::PointerOverOutFired)) {
-        LocalDOMWindow* executingWindow = this->executingWindow();
-        Node* node = toNode();
-        if (executingWindow && node && node->getNodeType() == Node::kElementNode && event->isPointerEvent()) {
-            const Element* element = static_cast<Element*>(node);
-            const PointerEvent* pointerEvent = static_cast<PointerEvent*>(event);
-            const UseCounter::Feature feature = (event->type() == EventTypeNames::pointerenter || event->type() == EventTypeNames::pointerleave)
-                ? UseCounter::PointerEnterLeaveFiredWhileCaptured
-                : UseCounter::PointerOverOutFiredWhileCaptured;
-            if (element->hasPointerCapture(pointerEvent->pointerId()) && element->hasProcessedPointerCapture(pointerEvent->pointerId()))
-                UseCounter::count(executingWindow->document(), feature);
-        }
+    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerenter, UseCounter::PointerEnterLeaveFired)) {
+    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerleave, UseCounter::PointerEnterLeaveFired)) {
+    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerover, UseCounter::PointerOverOutFired)) {
+    } else if (checkTypeThenUseCount(event, EventTypeNames::pointerout, UseCounter::PointerOverOutFired)) {
     }
 
     ExecutionContext* context = getExecutionContext();
diff --git a/third_party/WebKit/Source/core/events/NavigatorEvents.cpp b/third_party/WebKit/Source/core/events/NavigatorEvents.cpp
index e2a419c..eba1769 100644
--- a/third_party/WebKit/Source/core/events/NavigatorEvents.cpp
+++ b/third_party/WebKit/Source/core/events/NavigatorEvents.cpp
@@ -46,9 +46,4 @@
     return 0;
 }
 
-bool NavigatorEvents::pointerEnabled(Navigator& navigator)
-{
-    return false;
-}
-
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/events/NavigatorEvents.h b/third_party/WebKit/Source/core/events/NavigatorEvents.h
index bc47673..787d16b 100644
--- a/third_party/WebKit/Source/core/events/NavigatorEvents.h
+++ b/third_party/WebKit/Source/core/events/NavigatorEvents.h
@@ -41,7 +41,6 @@
     STATIC_ONLY(NavigatorEvents);
 public:
     static long maxTouchPoints(Navigator&);
-    static bool pointerEnabled(Navigator&);
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/core/events/NavigatorEvents.idl b/third_party/WebKit/Source/core/events/NavigatorEvents.idl
index da729c9..433a944 100644
--- a/third_party/WebKit/Source/core/events/NavigatorEvents.idl
+++ b/third_party/WebKit/Source/core/events/NavigatorEvents.idl
@@ -32,10 +32,4 @@
 
 partial interface Navigator {
     readonly attribute long maxTouchPoints;
-
-    // TODO(mustaq): This is a non-standard attribute, added behind the
-    // PointerEvent flag only to estimate potential risks. This returns |false|
-    // even though PointerEvent support is there. The attribute will be removed
-    // once we have the UseCounter data. See crbug.com/631897.
-    [RuntimeEnabled=PointerEvent,DeprecateAs=NavigatorPointerEnabled,NotEnumerable] readonly attribute boolean pointerEnabled;
 };
diff --git a/third_party/WebKit/Source/core/frame/Deprecation.cpp b/third_party/WebKit/Source/core/frame/Deprecation.cpp
index fefdbf5a..4470ec0a 100644
--- a/third_party/WebKit/Source/core/frame/Deprecation.cpp
+++ b/third_party/WebKit/Source/core/frame/Deprecation.cpp
@@ -380,9 +380,6 @@
     case UseCounter::V8SVGViewElement_ViewTarget_AttributeGetter:
         return willBeRemoved("SVGViewElement.viewTarget", M56, "5665473114931200");
 
-    case UseCounter::NavigatorPointerEnabled:
-        return "Navigator.pointerEnabled is a non-standard API added for experiments only. It will be removed in near future.";
-
     case UseCounter::WebAudioAutoplayCrossOriginIframe:
         return willBeRemoved("Web Audio autoplay (without user gesture) from cross-origin iframes", M55, "6406908126691328");
 
diff --git a/third_party/WebKit/Source/core/frame/UseCounter.h b/third_party/WebKit/Source/core/frame/UseCounter.h
index b0e493c..2ef5f13 100644
--- a/third_party/WebKit/Source/core/frame/UseCounter.h
+++ b/third_party/WebKit/Source/core/frame/UseCounter.h
@@ -1254,7 +1254,6 @@
         RadioNameMatchingStrict = 1513,
         RadioNameMatchingASCIICaseless = 1514,
         RadioNameMatchingCaseFolding = 1515,
-        NavigatorPointerEnabled = 1516,
         InputSelectionGettersThrow = 1517,
         UsbGetDevices = 1519,
         UsbRequestDevice = 1520,
@@ -1276,8 +1275,6 @@
 
         PointerEnterLeaveFired = 1535,
         PointerOverOutFired = 1536,
-        PointerEnterLeaveFiredWhileCaptured = 1537,
-        PointerOverOutFiredWhileCaptured = 1538,
         DraggableAttribute = 1539,
         CleanScriptElementWithNonce = 1540,
         PotentiallyInjectedScriptElementWithNonce = 1541,
diff --git a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
index 2673420..c240a25f 100644
--- a/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintPropertyTreeBuilder.cpp
@@ -438,19 +438,19 @@
 
 void PaintPropertyTreeBuilder::updateScrollAndScrollTranslation(const LayoutObject& object, PaintPropertyTreeBuilderContext& context)
 {
-    if (object.isBoxModelObject() && object.hasOverflowClip()) {
-        PaintLayer* layer = toLayoutBoxModelObject(object).layer();
-        DCHECK(layer);
-        DoubleSize scrollOffset = layer->getScrollableArea()->scrollOffset();
-        if (!scrollOffset.isZero() || layer->scrollsOverflow()) {
+    if (object.hasOverflowClip()) {
+        const LayoutBox& box = toLayoutBox(object);
+        const PaintLayerScrollableArea* scrollableArea = box.getScrollableArea();
+        DoubleSize scrollOffset = box.scrolledContentOffset();
+        if (!scrollOffset.isZero() || scrollableArea->scrollsOverflow()) {
             TransformationMatrix matrix = TransformationMatrix().translate(-scrollOffset.width(), -scrollOffset.height());
             context.current.transform = object.getMutableForPainting().ensureObjectPaintProperties().createOrUpdateScrollTranslation(
                 context.current.transform, matrix, FloatPoint3D(), context.current.shouldFlattenInheritedTransform, context.current.renderingContextID);
 
-            IntSize scrollClip = layer->getScrollableArea()->visibleContentRect().size();
-            IntSize scrollBounds = layer->getScrollableArea()->contentsSize();
-            bool userScrollableHorizontal = layer->getScrollableArea()->userInputScrollable(HorizontalScrollbar);
-            bool userScrollableVertical = layer->getScrollableArea()->userInputScrollable(VerticalScrollbar);
+            IntSize scrollClip = scrollableArea->visibleContentRect().size();
+            IntSize scrollBounds = scrollableArea->contentsSize();
+            bool userScrollableHorizontal = scrollableArea->userInputScrollable(HorizontalScrollbar);
+            bool userScrollableVertical = scrollableArea->userInputScrollable(VerticalScrollbar);
             context.current.scroll = object.getMutableForPainting().ensureObjectPaintProperties().createOrUpdateScroll(
                 context.current.scroll, context.current.transform, scrollClip, scrollBounds, userScrollableHorizontal, userScrollableVertical);
 
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImageChromeClient.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImageChromeClient.cpp
index 8173387..83b8ab63 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImageChromeClient.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImageChromeClient.cpp
@@ -34,7 +34,7 @@
 
 namespace blink {
 
-static const double animationFrameDelay = 0.025;
+static const double animationFrameDelay = 1.0 / 60;
 
 SVGImageChromeClient::SVGImageChromeClient(SVGImage* image)
     : m_image(image)
diff --git a/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp b/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
index 9252393..a2cf0fc7 100644
--- a/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
+++ b/third_party/WebKit/Source/modules/accessibility/AXInlineTextBox.cpp
@@ -66,11 +66,17 @@
     outBoundsInContainer = FloatRect();
     outContainerTransform.setIdentity();
 
-    if (!m_inlineTextBox)
+    if (!m_inlineTextBox || !parentObject() || !parentObject()->getLayoutObject())
         return;
 
     *outContainer = parentObject();
     outBoundsInContainer = FloatRect(m_inlineTextBox->localBounds());
+
+    // Subtract the local bounding box of the parent because they're
+    // both in the same coordinate system.
+    LayoutObject* parentLayoutObject = parentObject()->getLayoutObject();
+    FloatRect parentBoundingBox = parentLayoutObject->localBoundingBoxRectForAccessibility();
+    outBoundsInContainer.moveBy(-parentBoundingBox.location());
 }
 
 bool AXInlineTextBox::computeAccessibilityIsIgnored(IgnoredReasons* ignoredReasons) const
diff --git a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
index 1d968f9..1f8d4d1 100644
--- a/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
+++ b/third_party/WebKit/Source/modules/offscreencanvas2d/OffscreenCanvasRenderingContext2D.cpp
@@ -94,18 +94,13 @@
     return !!m_imageBuffer;
 }
 
-static bool shouldAccelerate(IntSize surfaceSize)
-{
-    return RuntimeEnabledFeatures::accelerated2dCanvasEnabled();
-}
-
 ImageBuffer* OffscreenCanvasRenderingContext2D::imageBuffer() const
 {
     if (!m_imageBuffer) {
         IntSize surfaceSize(width(), height());
         OpacityMode opacityMode = hasAlpha() ? NonOpaque : Opaque;
         std::unique_ptr<ImageBufferSurface> surface;
-        if (shouldAccelerate(surfaceSize)) {
+        if (RuntimeEnabledFeatures::accelerated2dCanvasEnabled()) {
             surface.reset(new AcceleratedImageBufferSurface(surfaceSize, opacityMode));
         }
 
diff --git a/third_party/WebKit/Source/modules/webdatabase/Database.cpp b/third_party/WebKit/Source/modules/webdatabase/Database.cpp
index 3f3b630..7176166 100644
--- a/third_party/WebKit/Source/modules/webdatabase/Database.cpp
+++ b/third_party/WebKit/Source/modules/webdatabase/Database.cpp
@@ -897,11 +897,13 @@
 
 SecurityOrigin* Database::getSecurityOrigin() const
 {
+    if (!getExecutionContext())
+        return nullptr;
     if (getExecutionContext()->isContextThread())
         return m_contextThreadSecurityOrigin.get();
     if (getDatabaseContext()->databaseThread()->isDatabaseThread())
         return m_databaseThreadSecurityOrigin.get();
-    return 0;
+    return nullptr;
 }
 
 bool Database::opened()
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
index 2f76b3b0..ad28611 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.cpp
@@ -380,6 +380,11 @@
     }
 }
 
+static void hibernateWrapperForTesting(WeakPtr<Canvas2DLayerBridge> bridge)
+{
+    hibernateWrapper(bridge, 0);
+}
+
 void Canvas2DLayerBridge::hibernate()
 {
     DCHECK(!isHibernating());
@@ -606,7 +611,11 @@
             m_layer->clearTexture();
         m_logger->reportHibernationEvent(HibernationScheduled);
         m_hibernationScheduled = true;
-        Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_HERE, WTF::bind(&hibernateWrapper, m_weakPtrFactory.createWeakPtr()));
+        if (m_dontUseIdleSchedulingForTesting) {
+            Platform::current()->currentThread()->getWebTaskRunner()->postTask(BLINK_FROM_HERE, WTF::bind(&hibernateWrapperForTesting, m_weakPtrFactory.createWeakPtr()));
+        } else {
+            Platform::current()->currentThread()->scheduler()->postIdleTask(BLINK_FROM_HERE, WTF::bind(&hibernateWrapper, m_weakPtrFactory.createWeakPtr()));
+        }
     }
     if (!isHidden() && m_softwareRenderingWhileHidden) {
         flushRecordingOnly();
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
index fc94bdc..6e095af3 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridge.h
@@ -120,6 +120,7 @@
     void prepareSurfaceForPaintingIfNeeded();
     bool isHidden() { return m_isHidden; }
     OpacityMode opacityMode() { return m_opacityMode; }
+    void dontUseIdleSchedulingForTesting() { m_dontUseIdleSchedulingForTesting = true; }
 
     void beginDestruction();
     void hibernate();
@@ -259,6 +260,7 @@
     bool m_softwareRenderingWhileHidden;
     bool m_surfaceCreationFailedAtLeastOnce = false;
     bool m_hibernationScheduled = false;
+    bool m_dontUseIdleSchedulingForTesting = false;
 
     friend class Canvas2DLayerBridgeTest;
     friend class CanvasRenderingContext2DTest;
diff --git a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
index f4673ee4..a4c7095 100644
--- a/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Canvas2DLayerBridgeTest.cpp
@@ -101,7 +101,9 @@
 public:
     PassRefPtr<Canvas2DLayerBridge> makeBridge(std::unique_ptr<FakeWebGraphicsContext3DProvider> provider, const IntSize& size, Canvas2DLayerBridge::AccelerationMode accelerationMode)
     {
-        return adoptRef(new Canvas2DLayerBridge(std::move(provider), size, 0, NonOpaque, accelerationMode, nullptr));
+        RefPtr<Canvas2DLayerBridge> bridge = adoptRef(new Canvas2DLayerBridge(std::move(provider), size, 0, NonOpaque, accelerationMode, nullptr));
+        bridge->dontUseIdleSchedulingForTesting();
+        return bridge.release();
     }
 
 protected:
@@ -462,7 +464,7 @@
     EXPECT_CALL(*mockLoggerPtr, didStartHibernating())
         .WillOnce(testing::Invoke(hibernationStartedEvent.get(), &WaitableEvent::signal));
     postSetIsHiddenTask(BLINK_FROM_HERE, testThread.get(), bridge.get(), true);
-    // Toggle visibility before the idle tasks that enters hibernation gets a
+    // Toggle visibility before the task that enters hibernation gets a
     // chance to run.
     postSetIsHiddenTask(BLINK_FROM_HERE, testThread.get(), bridge.get(), false);
     postSetIsHiddenTask(BLINK_FROM_HERE, testThread.get(), bridge.get(), true);
@@ -816,23 +818,6 @@
     postAndWaitDestroyBridgeTask(BLINK_FROM_HERE, testThread.get(), &bridge);
 }
 
-class IdleFenceTask : public WebThread::IdleTask {
-public:
-    IdleFenceTask(WaitableEvent* doneEvent)
-        : m_doneEvent(doneEvent)
-    { }
-
-    virtual ~IdleFenceTask() { }
-
-    void run(double /*deadline*/) override
-    {
-        m_doneEvent->signal();
-    }
-
-private:
-    WaitableEvent* m_doneEvent;
-};
-
 #if CANVAS2D_HIBERNATION_ENABLED
 TEST_F(Canvas2DLayerBridgeTest, TeardownWhileHibernationIsPending)
 #else
@@ -863,13 +848,13 @@
     // a bridge to hold the mockLogger.
     hibernationScheduledEvent->wait();
     // Once we know the hibernation task is scheduled, we can schedule a fence.
-    // Assuming Idle tasks are guaranteed to run in the order they were
+    // Assuming tasks are guaranteed to run in the order they were
     // submitted, this fence will guarantee the attempt to hibernate runs to
     // completion before the thread is destroyed.
     // This test passes by not crashing, which proves that the WeakPtr logic
     // is sound.
     std::unique_ptr<WaitableEvent> fenceEvent = wrapUnique(new WaitableEvent());
-    testThread->scheduler()->postIdleTask(BLINK_FROM_HERE, new IdleFenceTask(fenceEvent.get()));
+    testThread->getWebTaskRunner()->postTask(BLINK_FROM_HERE, WTF::bind(&WaitableEvent::signal, unretained(fenceEvent.get())));
     fenceEvent->wait();
 }
 
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
index d502f616..d89fb00 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/layout_tests/port/android.py
@@ -156,7 +156,7 @@
         return self.device_directory() + 'fonts/'
 
     def device_forwarder_path(self):
-        return self.device_directory() + 'forwarder'
+        return self.device_directory() + 'device_forwarder'
 
     def device_fifo_directory(self):
         return '/data/data/' + self.package_name() + '/files/'
@@ -461,7 +461,10 @@
 
     # Local public methods.
     def path_to_forwarder(self):
-        return self._build_path('forwarder')
+        return self._build_path('device_forwarder')
+
+    def path_to_forwarder_host(self):
+        return self._build_path('host_forwarder')
 
     def path_to_md5sum(self):
         return self._build_path(MD5SUM_DEVICE_FILE_NAME)
@@ -506,6 +509,7 @@
         result = self._check_file_exists(self.path_to_md5sum(), 'md5sum utility')
         result = self._check_file_exists(self.path_to_md5sum_host(), 'md5sum host utility') and result
         result = self._check_file_exists(self.path_to_forwarder(), 'forwarder utility') and result
+        result = self._check_file_exists(self.path_to_forwarder_host(), 'forwarder host utility') and result
 
         if not result:
             # There is a race condition in adb at least <= 4.3 on Linux that causes it to go offline periodically
@@ -815,7 +819,6 @@
         self._err_fifo_path = driver_details.device_fifo_directory() + 'stderr.fifo'
         self._read_stdout_process = None
         self._read_stderr_process = None
-        self._forwarder_process = None
         self._original_governors = {}
         self._original_kptr_restrict = None
 
@@ -965,7 +968,10 @@
             self._android_commands.push(host_file, device_file)
 
     def _push_executable(self, log_callback):
-        self._push_file_if_needed(self._port.path_to_forwarder(), self._driver_details.device_forwarder_path(), log_callback)
+        self._push_file_if_needed(
+            self._port.path_to_forwarder(),
+            self._driver_details.device_forwarder_path(),
+            log_callback)
         for resource in self._driver_details.additional_resources():
             self._push_file_if_needed(self._port._build_path(
                 resource), self._driver_details.device_directory() + resource, log_callback)
@@ -1145,14 +1151,13 @@
         super(ChromiumAndroidDriver, self)._start(pixel_tests, per_test_args, wait_for_ready=False)
 
         self._log_debug('Starting forwarder')
-        self._forwarder_process = self._port._server_process_constructor(
-            self._port, 'Forwarder', self._android_commands.adb_command() +
-            ['shell', '%s -no-spawn-daemon %s' % (self._driver_details.device_forwarder_path(), FORWARD_PORTS)])
-        self._forwarder_process.start()
-
-        deadline = time.time() + DRIVER_START_STOP_TIMEOUT_SECS
-        if not self._wait_for_server_process_output(self._forwarder_process, deadline, 'Forwarding device port'):
-            return False
+        self._android_commands.run(['shell', self._driver_details.device_forwarder_path()])
+        for forward_port in FORWARD_PORTS.split():
+            self._port.host.executive.run_command([
+                self._port.path_to_forwarder_host(),
+                '--adb=%s' % AndroidCommands.adb_command_path(self._port.host.executive, self._debug_logging),
+                '--serial-id=%s' % self._android_commands.get_serial(),
+                '--map', forward_port, forward_port])
 
         self._android_commands.run(['logcat', '-c'])
 
@@ -1261,11 +1266,16 @@
             self._read_stderr_process.kill()
             self._read_stderr_process = None
 
-        super(ChromiumAndroidDriver, self).stop()
+        self._android_commands.run([
+            'shell',
+            self._driver_details.device_forwarder_path(),
+            '--kill-server'])
 
-        if self._forwarder_process:
-            self._forwarder_process.kill()
-            self._forwarder_process = None
+        self._port.host.executive.run_command([
+            self._port.path_to_forwarder_host(),
+            '--kill-server'])
+
+        super(ChromiumAndroidDriver, self).stop()
 
         if self._android_devices.is_device_prepared(self._android_commands.get_serial()):
             if not ChromiumAndroidDriver._loop_with_timeout(self._remove_all_pipes, DRIVER_START_STOP_TIMEOUT_SECS):
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/optimize_baselines_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/optimize_baselines_unittest.py
index f8a3538a..715e6a6 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/optimize_baselines_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/optimize_baselines_unittest.py
@@ -75,8 +75,8 @@
         self.assertEquals(
             out,
             '{"add": [], "remove-lines": [], '
-            '"delete": ["/test.checkout/LayoutTests/platform/test-mac-mac10.10/another/test-expected.png", '
-            '"/test.checkout/LayoutTests/platform/test-mac-mac10.10/another/test-expected.txt"]}\n')
+            '"delete": ["/test.checkout/LayoutTests/platform/test-mac-mac10.10/another/test-expected.txt", '
+            '"/test.checkout/LayoutTests/platform/test-mac-mac10.10/another/test-expected.png"]}\n')
         self.assertFalse(
             self.tool.filesystem.exists(self.tool.filesystem.join(
                 test_port.layout_tests_dir(), 'platform/mac/another/test-expected.txt')))
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
index deebf32b..78d3011 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
@@ -87,42 +87,29 @@
     TODO(qyearsley): Refactor this so that lines to remove are only tracked in one format.
     """
     def __init__(self, files_to_add=None, files_to_delete=None, lines_to_remove=None):
-        self._files_to_add = set(files_to_add or [])
-        self._files_to_delete = set(files_to_delete or [])
-        lines_to_remove = lines_to_remove or {}
-        self._lines_to_remove = {t: set(builders) for t, builders in lines_to_remove.iteritems()}
+        self.files_to_add = files_to_add or []
+        self.files_to_delete = files_to_delete or []
+        self.lines_to_remove = lines_to_remove or {}
 
     def add_file(self, path):
-        self._files_to_add.add(path)
+        self.files_to_add.append(path)
 
     def delete_file(self, path):
-        self._files_to_delete.add(path)
+        self.files_to_delete.append(path)
 
     def remove_line(self, test, builder):
-        if test not in self._lines_to_remove:
-            self._lines_to_remove[test] = set()
-        self._lines_to_remove[test].add(builder)
-
-    @property
-    def files_to_add(self):
-        return sorted(self._files_to_add - self._files_to_delete)
-
-    @property
-    def files_to_delete(self):
-        return sorted(self._files_to_delete - self._files_to_add)
-
-    @property
-    def lines_to_remove(self):
-        return {t: sorted(set(builders)) for t, builders in sorted(self._lines_to_remove.iteritems())}
+        if test not in self.lines_to_remove:
+            self.lines_to_remove[test] = []
+        self.lines_to_remove[test].append(builder)
 
     def to_dict(self):
         remove_lines = []
-        for test in sorted(self.lines_to_remove):
-            for builder in sorted(set(self.lines_to_remove[test])):
+        for test in self.lines_to_remove:
+            for builder in self.lines_to_remove[test]:
                 remove_lines.append({'test': test, 'builder': builder})
         return {
-            'add': self.files_to_add,
-            'delete': self.files_to_delete,
+            'add': list(self.files_to_add),
+            'delete': list(self.files_to_delete),
             'remove-lines': remove_lines,
         }
 
@@ -143,18 +130,19 @@
                     lines_to_remove[test] = []
                 lines_to_remove[test].append(builder)
         return ChangeSet(
-            files_to_add=files_to_add,
-            files_to_delete=files_to_delete,
+            files_to_add=list(files_to_add),
+            files_to_delete=list(files_to_delete),
             lines_to_remove=lines_to_remove)
 
     def update(self, other):
         assert isinstance(other, ChangeSet)
-        self._files_to_add.update(other.files_to_add)
-        self._files_to_delete.update(other.files_to_delete)
+        assert type(other.lines_to_remove) is dict
+        self.files_to_add.extend(other.files_to_add)
+        self.files_to_delete.extend(other.files_to_delete)
         for test in other.lines_to_remove:
-            if test not in self._lines_to_remove:
-                self._lines_to_remove[test] = set()
-            self._lines_to_remove[test].update(other.lines_to_remove[test])
+            if test not in self.lines_to_remove:
+                self.lines_to_remove[test] = []
+            self.lines_to_remove[test].extend(other.lines_to_remove[test])
 
 
 class BaseInternalRebaselineCommand(AbstractRebaseliningCommand):
@@ -499,18 +487,28 @@
         return (SKIP in full_expectations.get_expectations(test) and
                 SKIP not in generic_expectations.get_expectations(test))
 
-    def _run_in_parallel(self, commands):
+    def _run_in_parallel(self, commands, update_scm=True):
         if not commands:
-            return ChangeSet()
+            return {}
 
         command_results = self._tool.executive.run_in_parallel(commands)
         for _, _, stderr in command_results:
             if stderr:
                 _log.error(stderr)
 
-        return self._extract_scm_changes(command_results)
+        change_set = self._extract_scm_changes(command_results)
 
-    def _rebaseline(self, options, test_prefix_list):
+        # TODO(qyearsley): Instead of updating the SCM state here, aggregate changes
+        # and update once in _rebaseline. See http://crbug.com/639410.
+        if update_scm:
+            if change_set.files_to_delete:
+                self._tool.scm().delete_list(change_set.files_to_delete)
+            if change_set.files_to_add:
+                self._tool.scm().add_list(change_set.files_to_add)
+
+        return change_set.lines_to_remove
+
+    def _rebaseline(self, options, test_prefix_list, update_scm=True):
         """Downloads new baselines in parallel, then updates expectations files
         and optimizes baselines.
 
@@ -528,6 +526,7 @@
                 "some/other.html" but only from builder-1.
                 TODO(qyearsley): Replace test_prefix_list everywhere with some
                 sort of class that contains the same data.
+            update_scm: If True, commands like `git add` and `git rm` will be run.
         """
         for test, builds_to_check in sorted(test_prefix_list.items()):
             _log.info("Rebaselining %s", test)
@@ -536,25 +535,25 @@
 
         copy_baseline_commands, rebaseline_commands, extra_lines_to_remove = self._rebaseline_commands(
             test_prefix_list, options)
+        lines_to_remove = {}
 
-        change_set = ChangeSet(lines_to_remove=extra_lines_to_remove)
+        self._run_in_parallel(copy_baseline_commands, update_scm=update_scm)
+        lines_to_remove = self._run_in_parallel(rebaseline_commands, update_scm=update_scm)
 
-        change_set.update(self._run_in_parallel(copy_baseline_commands))
-        change_set.update(self._run_in_parallel(rebaseline_commands))
+        for test in extra_lines_to_remove:
+            if test in lines_to_remove:
+                lines_to_remove[test] = lines_to_remove[test] + extra_lines_to_remove[test]
+            else:
+                lines_to_remove[test] = extra_lines_to_remove[test]
 
-        if change_set.lines_to_remove:
-            self._update_expectations_files(change_set.lines_to_remove)
+        if lines_to_remove:
+            self._update_expectations_files(lines_to_remove)
 
         if options.optimize:
             # TODO(wkorman): Consider changing temporary branch to base off of HEAD rather than
             # origin/master to ensure we run baseline optimization processes with the same code as
             # auto-rebaseline itself.
-            change_set.update(self._run_in_parallel(self._optimize_baselines(test_prefix_list, options.verbose)))
-
-        if change_set.files_to_delete:
-            self._tool.scm().delete_list(change_set.files_to_delete)
-        if change_set.files_to_add:
-            self._tool.scm().add_list(change_set.files_to_add)
+            self._run_in_parallel(self._optimize_baselines(test_prefix_list, options.verbose), update_scm=update_scm)
 
     def _suffixes_for_actual_failures(self, test, build, existing_suffixes):
         """Gets the baseline suffixes for actual mismatch failures in some results.
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
index 0914a0d..c62fd98 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_cl.py
@@ -83,7 +83,7 @@
 
         if options.dry_run:
             return
-        self._rebaseline(options, test_prefix_list)
+        self._rebaseline(options, test_prefix_list, update_scm=False)
 
     def _filter_existing(self, test_prefix_list):
         """Filters out entries in |test_prefix_list| for tests that don't exist."""
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
index 20c1de4..abe3f60 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
@@ -934,93 +934,3 @@
         self.calls = self.calls[:num_previous_calls]
         self.calls.append(new_calls)
         return command_outputs
-
-
-class ChangeSetTest(unittest.TestCase):
-
-    def test_constructor_and_getters(self):
-        change_set = ChangeSet(
-            files_to_add=['add/a.html', 'add/b.html'],
-            files_to_delete=['del/x.html'],
-            lines_to_remove={'my/test.html': ['my-builder']})
-        self.assertEqual(change_set.files_to_add, ['add/a.html', 'add/b.html'])
-        self.assertEqual(change_set.files_to_delete, ['del/x.html'])
-        self.assertEqual(change_set.lines_to_remove, {'my/test.html': ['my-builder']})
-
-    def test_files_to_add_and_files_to_delete_are_sorted_no_dupes(self):
-        change_set = ChangeSet(files_to_add=['b', 'a', 'a'], files_to_delete=['x', 'y', 'x'])
-        self.assertEqual(change_set.files_to_add, ['a', 'b'])
-        self.assertEqual(change_set.files_to_delete, ['x', 'y'])
-
-    def test_files_both_added_and_deleted_are_ignored(self):
-        change_set = ChangeSet(files_to_add=['a', 'b', 'c'], files_to_delete=['c', 'd', 'e'])
-        self.assertEqual(change_set.files_to_add, ['a', 'b'])
-        self.assertEqual(change_set.files_to_delete, ['d', 'e'])
-        change_set.add_file('d')
-        self.assertEqual(change_set.files_to_add, ['a', 'b'])
-        self.assertEqual(change_set.files_to_delete, ['e'])
-        change_set.delete_file('b')
-        self.assertEqual(change_set.files_to_add, ['a'])
-        self.assertEqual(change_set.files_to_delete, ['e'])
-
-    def test_add_file(self):
-        change_set = ChangeSet()
-        change_set.add_file('a')
-        change_set.add_file('b')
-        change_set.add_file('b')
-        self.assertEqual(change_set.files_to_add, ['a', 'b'])
-
-    def test_delete_file(self):
-        change_set = ChangeSet()
-        change_set.delete_file('a')
-        change_set.delete_file('b')
-        change_set.delete_file('b')
-        self.assertEqual(change_set.files_to_delete, ['a', 'b'])
-
-    def test_remove_line(self):
-        change_set = ChangeSet()
-        change_set.remove_line('test', 'builder-b')
-        change_set.remove_line('test', 'builder-a')
-        change_set.remove_line('test', 'builder-a')
-        self.assertEqual(
-            change_set.lines_to_remove,
-            {'test': ['builder-a', 'builder-b']})
-
-    def test_from_dict(self):
-        change_set = ChangeSet.from_dict({
-            'add': ['to/add.html'],
-            'remove-lines': [{'test': 'some/test.html', 'builder': 'builder-name'}]
-        })
-        self.assertEqual(change_set.files_to_add, ['to/add.html'])
-        self.assertEqual(change_set.lines_to_remove, {'some/test.html': ['builder-name']})
-
-    def test_to_dict(self):
-        change_set = ChangeSet(
-            files_to_add=['add/b.html', 'add/a.html'],
-            files_to_delete=['del/x.html'],
-            lines_to_remove={
-                'x/test.html': ['builder-b', 'builder-b', 'builder-a'],
-                'y/test.html': [],
-                'z/test.html': ['builder-c']})
-        self.assertEqual(change_set.to_dict(), {
-            'add': ['add/a.html', 'add/b.html'],
-            'delete': ['del/x.html'],
-            'remove-lines': [
-                {'test': 'x/test.html', 'builder': 'builder-a'},
-                {'test': 'x/test.html', 'builder': 'builder-b'},
-                {'test': 'z/test.html', 'builder': 'builder-c'},
-            ],
-        })
-
-    def test_update(self):
-        change_set = ChangeSet(
-            files_to_add=['add/a.html', 'add/b.html'],
-            files_to_delete=['del/x.html'],
-            lines_to_remove={'my/test.html': ['my-builder']})
-        change_set.update(ChangeSet(
-            files_to_add=['add/a.html', 'add/c.html', 'del/x.html'],
-            files_to_delete=['add/b.html', 'del/y.html'],
-            lines_to_remove={'my/test.html': ['my-builder', 'other-builder']}))
-        self.assertEqual(change_set.files_to_add, ['add/a.html', 'add/c.html'])
-        self.assertEqual(change_set.files_to_delete, ['del/y.html'])
-        self.assertEqual(change_set.lines_to_remove, {'my/test.html': ['my-builder', 'other-builder']})
diff --git a/third_party/sqlite/amalgamation/sqlite3.c b/third_party/sqlite/amalgamation/sqlite3.c
index 58981ca9..97d1ab99 100644
--- a/third_party/sqlite/amalgamation/sqlite3.c
+++ b/third_party/sqlite/amalgamation/sqlite3.c
@@ -26285,36 +26285,21 @@
     return sqlite3AddInt64(pA, -iB);
   }
 }
-#define TWOPOWER32 (((i64)1)<<32)
-#define TWOPOWER31 (((i64)1)<<31)
 SQLITE_PRIVATE int sqlite3MulInt64(i64 *pA, i64 iB){
   i64 iA = *pA;
-  i64 iA1, iA0, iB1, iB0, r;
-
-  iA1 = iA/TWOPOWER32;
-  iA0 = iA % TWOPOWER32;
-  iB1 = iB/TWOPOWER32;
-  iB0 = iB % TWOPOWER32;
-  if( iA1==0 ){
-    if( iB1==0 ){
-      *pA *= iB;
-      return 0;
+  if( iB>0 ){
+    if( iA>LARGEST_INT64/iB ) return 1;
+    if( iA<SMALLEST_INT64/iB ) return 1;
+  }else if( iB<0 ){
+    if( iA>0 ){
+      if( iB<SMALLEST_INT64/iA ) return 1;
+    }else if( iA<0 ){
+      if( iB==SMALLEST_INT64 ) return 1;
+      if( iA==SMALLEST_INT64 ) return 1;
+      if( -iA>LARGEST_INT64/-iB ) return 1;
     }
-    r = iA0*iB1;
-  }else if( iB1==0 ){
-    r = iA1*iB0;
-  }else{
-    /* If both iA1 and iB1 are non-zero, overflow will result */
-    return 1;
   }
-  testcase( r==(-TWOPOWER31)-1 );
-  testcase( r==(-TWOPOWER31) );
-  testcase( r==TWOPOWER31 );
-  testcase( r==TWOPOWER31-1 );
-  if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
-  r *= TWOPOWER32;
-  if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
-  *pA = r;
+  *pA = iA*iB;
   return 0;
 }
 
diff --git a/third_party/sqlite/patches/0014-backport-Address-integer-overflow-in-sqlite3MulInt64.patch b/third_party/sqlite/patches/0014-backport-Address-integer-overflow-in-sqlite3MulInt64.patch
new file mode 100644
index 0000000..19a5210
--- /dev/null
+++ b/third_party/sqlite/patches/0014-backport-Address-integer-overflow-in-sqlite3MulInt64.patch
@@ -0,0 +1,112 @@
+From 7bcd4f0f17fb5bb6ae11be6ef0b70197195f2d61 Mon Sep 17 00:00:00 2001
+From: Scott Hess <shess@chromium.org>
+Date: Fri, 23 Sep 2016 09:54:14 -0700
+Subject: [PATCH 14/14] [backport] Address integer overflow in sqlite3MulInt64.
+
+SQLite check-in http://www.sqlite.org/src/info/db3ebd7c52cfc5fc
+
+"Improved implementation of 64-bit signed integer multiply that
+correctly detects overflow (and promotes to floating-point) in some
+corner cases. Fix for ticket [1ec41379c9c1e400]"
+
+http://www.sqlite.org/src/info/1ec41379c9c1e400"
+
+BUG=601727
+---
+ third_party/sqlite/src/src/util.c     | 37 +++++++++++------------------------
+ third_party/sqlite/src/test/expr.test | 27 +++++++++++++++++++++++++
+ 2 files changed, 38 insertions(+), 26 deletions(-)
+
+diff --git a/third_party/sqlite/src/src/util.c b/third_party/sqlite/src/src/util.c
+index b4c5e62..7640f1d 100644
+--- a/third_party/sqlite/src/src/util.c
++++ b/third_party/sqlite/src/src/util.c
+@@ -1244,36 +1244,21 @@ int sqlite3SubInt64(i64 *pA, i64 iB){
+     return sqlite3AddInt64(pA, -iB);
+   }
+ }
+-#define TWOPOWER32 (((i64)1)<<32)
+-#define TWOPOWER31 (((i64)1)<<31)
+ int sqlite3MulInt64(i64 *pA, i64 iB){
+   i64 iA = *pA;
+-  i64 iA1, iA0, iB1, iB0, r;
+-
+-  iA1 = iA/TWOPOWER32;
+-  iA0 = iA % TWOPOWER32;
+-  iB1 = iB/TWOPOWER32;
+-  iB0 = iB % TWOPOWER32;
+-  if( iA1==0 ){
+-    if( iB1==0 ){
+-      *pA *= iB;
+-      return 0;
++  if( iB>0 ){
++    if( iA>LARGEST_INT64/iB ) return 1;
++    if( iA<SMALLEST_INT64/iB ) return 1;
++  }else if( iB<0 ){
++    if( iA>0 ){
++      if( iB<SMALLEST_INT64/iA ) return 1;
++    }else if( iA<0 ){
++      if( iB==SMALLEST_INT64 ) return 1;
++      if( iA==SMALLEST_INT64 ) return 1;
++      if( -iA>LARGEST_INT64/-iB ) return 1;
+     }
+-    r = iA0*iB1;
+-  }else if( iB1==0 ){
+-    r = iA1*iB0;
+-  }else{
+-    /* If both iA1 and iB1 are non-zero, overflow will result */
+-    return 1;
+   }
+-  testcase( r==(-TWOPOWER31)-1 );
+-  testcase( r==(-TWOPOWER31) );
+-  testcase( r==TWOPOWER31 );
+-  testcase( r==TWOPOWER31-1 );
+-  if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
+-  r *= TWOPOWER32;
+-  if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
+-  *pA = r;
++  *pA = iA*iB;
+   return 0;
+ }
+ 
+diff --git a/third_party/sqlite/src/test/expr.test b/third_party/sqlite/src/test/expr.test
+index 7d7b8ce..7a6d477 100644
+--- a/third_party/sqlite/src/test/expr.test
++++ b/third_party/sqlite/src/test/expr.test
+@@ -308,6 +308,33 @@ ifcapable floatingpoint {if {[working_64bit_int]} {
+   test_realnum_expr expr-1.257\
+       {i1=-4294967296, i2=-2147483647} {i1*i2}    9223372032559808512
+ 
++  test_realnum_expr expr-1.260\
++      {i1=3037000500, i2=3037000500} {i1*i2}      9.22337203700025e+18
++  test_realnum_expr expr-1.261\
++      {i1=3037000500, i2=-3037000500} {i1*i2}     -9.22337203700025e+18
++  test_realnum_expr expr-1.262\
++      {i1=-3037000500, i2=3037000500} {i1*i2}     -9.22337203700025e+18
++  test_realnum_expr expr-1.263\
++      {i1=-3037000500, i2=-3037000500} {i1*i2}    9.22337203700025e+18
++
++  test_realnum_expr expr-1.264\
++      {i1=3037000500, i2=3037000499} {i1*i2}      9223372033963249500
++  test_realnum_expr expr-1.265\
++      {i1=3037000500, i2=-3037000499} {i1*i2}     -9223372033963249500
++  test_realnum_expr expr-1.266\
++      {i1=-3037000500, i2=3037000499} {i1*i2}     -9223372033963249500
++  test_realnum_expr expr-1.267\
++      {i1=-3037000500, i2=-3037000499} {i1*i2}    9223372033963249500
++
++  test_realnum_expr expr-1.268\
++      {i1=3037000499, i2=3037000500} {i1*i2}      9223372033963249500
++  test_realnum_expr expr-1.269\
++      {i1=3037000499, i2=-3037000500} {i1*i2}     -9223372033963249500
++  test_realnum_expr expr-1.270\
++      {i1=-3037000499, i2=3037000500} {i1*i2}     -9223372033963249500
++  test_realnum_expr expr-1.271\
++      {i1=-3037000499, i2=-3037000500} {i1*i2}    9223372033963249500
++
+ }}
+ 
+ ifcapable floatingpoint {
+-- 
+2.5.0
+
diff --git a/third_party/sqlite/src/src/util.c b/third_party/sqlite/src/src/util.c
index b4c5e62..7640f1d 100644
--- a/third_party/sqlite/src/src/util.c
+++ b/third_party/sqlite/src/src/util.c
@@ -1244,36 +1244,21 @@
     return sqlite3AddInt64(pA, -iB);
   }
 }
-#define TWOPOWER32 (((i64)1)<<32)
-#define TWOPOWER31 (((i64)1)<<31)
 int sqlite3MulInt64(i64 *pA, i64 iB){
   i64 iA = *pA;
-  i64 iA1, iA0, iB1, iB0, r;
-
-  iA1 = iA/TWOPOWER32;
-  iA0 = iA % TWOPOWER32;
-  iB1 = iB/TWOPOWER32;
-  iB0 = iB % TWOPOWER32;
-  if( iA1==0 ){
-    if( iB1==0 ){
-      *pA *= iB;
-      return 0;
+  if( iB>0 ){
+    if( iA>LARGEST_INT64/iB ) return 1;
+    if( iA<SMALLEST_INT64/iB ) return 1;
+  }else if( iB<0 ){
+    if( iA>0 ){
+      if( iB<SMALLEST_INT64/iA ) return 1;
+    }else if( iA<0 ){
+      if( iB==SMALLEST_INT64 ) return 1;
+      if( iA==SMALLEST_INT64 ) return 1;
+      if( -iA>LARGEST_INT64/-iB ) return 1;
     }
-    r = iA0*iB1;
-  }else if( iB1==0 ){
-    r = iA1*iB0;
-  }else{
-    /* If both iA1 and iB1 are non-zero, overflow will result */
-    return 1;
   }
-  testcase( r==(-TWOPOWER31)-1 );
-  testcase( r==(-TWOPOWER31) );
-  testcase( r==TWOPOWER31 );
-  testcase( r==TWOPOWER31-1 );
-  if( r<(-TWOPOWER31) || r>=TWOPOWER31 ) return 1;
-  r *= TWOPOWER32;
-  if( sqlite3AddInt64(&r, iA0*iB0) ) return 1;
-  *pA = r;
+  *pA = iA*iB;
   return 0;
 }
 
diff --git a/third_party/sqlite/src/test/expr.test b/third_party/sqlite/src/test/expr.test
index 7d7b8ce..7a6d477 100644
--- a/third_party/sqlite/src/test/expr.test
+++ b/third_party/sqlite/src/test/expr.test
@@ -308,6 +308,33 @@
   test_realnum_expr expr-1.257\
       {i1=-4294967296, i2=-2147483647} {i1*i2}    9223372032559808512
 
+  test_realnum_expr expr-1.260\
+      {i1=3037000500, i2=3037000500} {i1*i2}      9.22337203700025e+18
+  test_realnum_expr expr-1.261\
+      {i1=3037000500, i2=-3037000500} {i1*i2}     -9.22337203700025e+18
+  test_realnum_expr expr-1.262\
+      {i1=-3037000500, i2=3037000500} {i1*i2}     -9.22337203700025e+18
+  test_realnum_expr expr-1.263\
+      {i1=-3037000500, i2=-3037000500} {i1*i2}    9.22337203700025e+18
+
+  test_realnum_expr expr-1.264\
+      {i1=3037000500, i2=3037000499} {i1*i2}      9223372033963249500
+  test_realnum_expr expr-1.265\
+      {i1=3037000500, i2=-3037000499} {i1*i2}     -9223372033963249500
+  test_realnum_expr expr-1.266\
+      {i1=-3037000500, i2=3037000499} {i1*i2}     -9223372033963249500
+  test_realnum_expr expr-1.267\
+      {i1=-3037000500, i2=-3037000499} {i1*i2}    9223372033963249500
+
+  test_realnum_expr expr-1.268\
+      {i1=3037000499, i2=3037000500} {i1*i2}      9223372033963249500
+  test_realnum_expr expr-1.269\
+      {i1=3037000499, i2=-3037000500} {i1*i2}     -9223372033963249500
+  test_realnum_expr expr-1.270\
+      {i1=-3037000499, i2=3037000500} {i1*i2}     -9223372033963249500
+  test_realnum_expr expr-1.271\
+      {i1=-3037000499, i2=-3037000500} {i1*i2}    9223372033963249500
+
 }}
 
 ifcapable floatingpoint {
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml
index cefb886..adc7294 100644
--- a/tools/metrics/histograms/histograms.xml
+++ b/tools/metrics/histograms/histograms.xml
@@ -17761,6 +17761,16 @@
   </summary>
 </histogram>
 
+<histogram name="GCM.DataMessageReceivedHasRegisteredApp"
+    enum="BooleanRegistered">
+  <owner>peter@chromium.org</owner>
+  <summary>
+    Records whether a corresponding registration was found for each received
+    DATA_MESSAGE or DELETED_MESSAGES message from Google Cloud Messaging.
+    Recorded while processing the received message.
+  </summary>
+</histogram>
+
 <histogram name="GCM.FirstReceivedDataMessageLatencyAfterConnection" units="ms">
   <owner>juyik@chromium.org</owner>
   <summary>
@@ -61054,6 +61064,17 @@
   </summary>
 </histogram>
 
+<histogram name="Sync.LostNavigationCount" units="navigations">
+  <owner>pnoland@chromium.org</owner>
+  <summary>
+    Counts instances of navigations that are recorded locally but not synced.
+    Recorded once per active tab for every inferred sync cycle. Sync cycles are
+    inferred by examining the is_synced and is_syncing flags of sync directories
+    when recording local changes to tabs or windows. Sync cycles that occur
+    without changes to tabs or windows won't cause this metric to be logged.
+  </summary>
+</histogram>
+
 <histogram name="Sync.MemoryPressureWarningBeforeCleanShutdown" units="count">
   <owner>gangwu@chromium.org</owner>
   <summary>
diff --git a/tools/valgrind/gtest_exclude/chrome_elf_unittests.gtest-drmemory_win32.txt b/tools/valgrind/gtest_exclude/chrome_elf_unittests.gtest-drmemory_win32.txt
new file mode 100644
index 0000000..8f8d9f9
--- /dev/null
+++ b/tools/valgrind/gtest_exclude/chrome_elf_unittests.gtest-drmemory_win32.txt
@@ -0,0 +1,2 @@
+# https://crbug.com/628462
+BlacklistTest.LoadBlacklistedLibrary
diff --git a/ui/gfx/image/canvas_image_source.cc b/ui/gfx/image/canvas_image_source.cc
index b336b31..e53257f 100644
--- a/ui/gfx/image/canvas_image_source.cc
+++ b/ui/gfx/image/canvas_image_source.cc
@@ -6,6 +6,7 @@
 
 #include "base/logging.h"
 #include "ui/gfx/canvas.h"
+#include "ui/gfx/image/image_skia.h"
 
 namespace gfx {
 
diff --git a/ui/gfx/image/canvas_image_source.h b/ui/gfx/image/canvas_image_source.h
index f41c281..1108f0d 100644
--- a/ui/gfx/image/canvas_image_source.h
+++ b/ui/gfx/image/canvas_image_source.h
@@ -7,8 +7,10 @@
 
 #include "base/compiler_specific.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "ui/gfx/geometry/size.h"
 #include "ui/gfx/gfx_export.h"
+#include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_source.h"
 
 namespace gfx {
@@ -21,7 +23,18 @@
 // completed.
 class GFX_EXPORT CanvasImageSource : public gfx::ImageSkiaSource {
  public:
+  // Factory function to create an ImageSkia from a CanvasImageSource. Example:
+  //   gfx::ImageSkia my_image =
+  //       CanvasImageSource::MakeImageSkia<MySource>(param1, param2);
+  template <typename T, typename... Args>
+  static ImageSkia MakeImageSkia(Args&&... args) {
+    auto source = base::MakeUnique<T>(std::forward<Args>(args)...);
+    gfx::Size size = source->size();
+    return gfx::ImageSkia(source.release(), size);
+  }
+
   CanvasImageSource(const gfx::Size& size, bool is_opaque);
+  ~CanvasImageSource() override {}
 
   // Called when a new image needs to be drawn for a scale factor.
   virtual void Draw(gfx::Canvas* canvas) = 0;
@@ -33,8 +46,6 @@
   gfx::ImageSkiaRep GetImageForScale(float scale) override;
 
  protected:
-  ~CanvasImageSource() override {}
-
   const gfx::Size size_;
   const bool is_opaque_;
   DISALLOW_COPY_AND_ASSIGN(CanvasImageSource);
diff --git a/ui/gfx/ipc/gfx_param_traits_macros.h b/ui/gfx/ipc/gfx_param_traits_macros.h
index 2a8c6e5..cdee2f6 100644
--- a/ui/gfx/ipc/gfx_param_traits_macros.h
+++ b/ui/gfx/ipc/gfx_param_traits_macros.h
@@ -54,6 +54,7 @@
 IPC_STRUCT_TRAITS_BEGIN(gfx::NativePixmapPlane)
   IPC_STRUCT_TRAITS_MEMBER(stride)
   IPC_STRUCT_TRAITS_MEMBER(offset)
+  IPC_STRUCT_TRAITS_MEMBER(size)
   IPC_STRUCT_TRAITS_MEMBER(modifier)
 IPC_STRUCT_TRAITS_END()
 
diff --git a/ui/gfx/mojo/buffer_types.mojom b/ui/gfx/mojo/buffer_types.mojom
index 0f0be7e9..49c1ee1 100644
--- a/ui/gfx/mojo/buffer_types.mojom
+++ b/ui/gfx/mojo/buffer_types.mojom
@@ -53,6 +53,7 @@
 struct NativePixmapPlane {
   uint32 stride;
   int32 offset;
+  uint64 size;
   uint64 modifier;
 };
 
diff --git a/ui/gfx/mojo/buffer_types_traits.h b/ui/gfx/mojo/buffer_types_traits.h
index 175a493..311f98e 100644
--- a/ui/gfx/mojo/buffer_types_traits.h
+++ b/ui/gfx/mojo/buffer_types_traits.h
@@ -199,6 +199,9 @@
   static int32_t offset(const gfx::NativePixmapPlane& plane) {
     return plane.offset;
   }
+  static uint64_t size(const gfx::NativePixmapPlane& plane) {
+    return plane.size;
+  }
   static uint64_t modifier(const gfx::NativePixmapPlane& plane) {
     return plane.modifier;
   }
@@ -206,6 +209,7 @@
                    gfx::NativePixmapPlane* out) {
     out->stride = data.stride();
     out->offset = data.offset();
+    out->size = data.size();
     out->modifier = data.modifier();
     return true;
   }
diff --git a/ui/gfx/mojo/struct_traits_unittest.cc b/ui/gfx/mojo/struct_traits_unittest.cc
index 556954b0..d837cd8 100644
--- a/ui/gfx/mojo/struct_traits_unittest.cc
+++ b/ui/gfx/mojo/struct_traits_unittest.cc
@@ -144,6 +144,10 @@
   const gfx::GpuMemoryBufferId kId(99);
   const uint32_t kOffset = 126;
   const int32_t kStride = 256;
+#if defined(USE_OZONE)
+  const uint64_t kSize = kOffset + kStride;
+  const uint64_t kModifier = 2;
+#endif
   base::SharedMemory shared_memory;
   ASSERT_TRUE(shared_memory.CreateAnonymous(1024));
   ASSERT_TRUE(shared_memory.Map(1024));
@@ -155,6 +159,11 @@
   handle.offset = kOffset;
   handle.stride = kStride;
 
+#if defined(USE_OZONE)
+  handle.native_pixmap_handle.planes.emplace_back(kOffset, kStride, kSize,
+                                                  kModifier);
+#endif
+
   mojom::TraitsTestServicePtr proxy = GetTraitsTestProxy();
   gfx::GpuMemoryBufferHandle output;
   proxy->EchoGpuMemoryBufferHandle(handle, &output);
@@ -162,6 +171,13 @@
   EXPECT_EQ(kId, output.id);
   EXPECT_EQ(kOffset, output.offset);
   EXPECT_EQ(kStride, output.stride);
+
+#if defined(USE_OZONE)
+  ASSERT_EQ(1u, output.native_pixmap_handle.planes.size());
+  EXPECT_EQ(kSize, output.native_pixmap_handle.planes.back().size);
+  EXPECT_EQ(kModifier, output.native_pixmap_handle.planes.back().modifier);
+#endif
+
 #if !defined(OS_MACOSX) && !defined(OS_IOS)
   // TODO: Add support for mach_port on mac.
   base::SharedMemory output_memory(output.handle, true);
diff --git a/ui/gfx/native_pixmap_handle.cc b/ui/gfx/native_pixmap_handle.cc
index a3092b265..f0144a8 100644
--- a/ui/gfx/native_pixmap_handle.cc
+++ b/ui/gfx/native_pixmap_handle.cc
@@ -2,14 +2,20 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <stdint.h>
+
 #include "ui/gfx/native_pixmap_handle.h"
 
 namespace gfx {
 
-NativePixmapPlane::NativePixmapPlane() : stride(0), offset(0), modifier(0) {}
+NativePixmapPlane::NativePixmapPlane()
+    : stride(0), offset(0), size(0), modifier(0) {}
 
-NativePixmapPlane::NativePixmapPlane(int stride, int offset, uint64_t modifier)
-    : stride(stride), offset(offset), modifier(modifier) {}
+NativePixmapPlane::NativePixmapPlane(int stride,
+                                     int offset,
+                                     uint64_t size,
+                                     uint64_t modifier)
+    : stride(stride), offset(offset), size(size), modifier(modifier) {}
 
 NativePixmapPlane::NativePixmapPlane(const NativePixmapPlane& other) = default;
 
diff --git a/ui/gfx/native_pixmap_handle.h b/ui/gfx/native_pixmap_handle.h
index 767951b..eca2bd1d 100644
--- a/ui/gfx/native_pixmap_handle.h
+++ b/ui/gfx/native_pixmap_handle.h
@@ -5,7 +5,7 @@
 #ifndef UI_GFX_NATIVE_PIXMAP_HANDLE_H_
 #define UI_GFX_NATIVE_PIXMAP_HANDLE_H_
 
-#include <stdint.h>
+#include <stddef.h>
 #include <vector>
 
 #include "ui/gfx/gfx_export.h"
@@ -20,7 +20,7 @@
 // buffer. More fields can be added if they are plane specific.
 struct GFX_EXPORT NativePixmapPlane {
   NativePixmapPlane();
-  NativePixmapPlane(int stride, int offset, uint64_t modifier);
+  NativePixmapPlane(int stride, int offset, uint64_t size, uint64_t modifier);
   NativePixmapPlane(const NativePixmapPlane& other);
   ~NativePixmapPlane();
 
@@ -28,6 +28,9 @@
   // a memory mapping. One per plane per entry.
   int stride;
   int offset;
+  // Size in bytes of the plane.
+  // This is necessary to map the buffers.
+  uint64_t size;
   // The modifier is retrieved from GBM library and passed to EGL driver.
   // Generally it's platform specific, and we don't need to modify it in
   // Chromium code. Also one per plane per entry.
diff --git a/ui/gfx/paint_vector_icon.cc b/ui/gfx/paint_vector_icon.cc
index 70daac2..1ac78e27 100644
--- a/ui/gfx/paint_vector_icon.cc
+++ b/ui/gfx/paint_vector_icon.cc
@@ -10,6 +10,7 @@
 #include "base/i18n/rtl.h"
 #include "base/lazy_instance.h"
 #include "base/macros.h"
+#include "base/memory/ptr_util.h"
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "third_party/skia/include/core/SkPaint.h"
@@ -596,8 +597,8 @@
 ImageSkia CreateVectorIconFromSource(const std::string& source,
                                      int dip_size,
                                      SkColor color) {
-  return ImageSkia(new VectorIconSourceLegacy(source, dip_size, color),
-                   gfx::Size(dip_size, dip_size));
+  return CanvasImageSource::MakeImageSkia<VectorIconSourceLegacy>(
+      source, dip_size, color);
 }
 
 }  // namespace gfx
diff --git a/ui/ozone/gl/gl_image_ozone_native_pixmap_drm_unittest.cc b/ui/ozone/gl/gl_image_ozone_native_pixmap_drm_unittest.cc
index cc2f152..8ab537f 100644
--- a/ui/ozone/gl/gl_image_ozone_native_pixmap_drm_unittest.cc
+++ b/ui/ozone/gl/gl_image_ozone_native_pixmap_drm_unittest.cc
@@ -50,6 +50,10 @@
       0, pitches[0] * size.height() + pitches[1] * size.height() / 2,
       pitches[0] * size.height(),
   };
+  std::vector<size_t> sizes{pitches[0] * size.height(),
+                            pitches[1] * size.height() / 2,
+                            pitches[2] * size.height() / 2};
+
   size_t byte_number = pitches[0] * size.height() +
                        pitches[1] * size.height() / 2 +
                        pitches[2] * size.height() / 2;
@@ -89,7 +93,7 @@
   gfx::NativePixmapHandle pixmap_handle;
   pixmap_handle.fds.emplace_back(fd, false);
   for (int i = 0; i < 3; i++) {
-    pixmap_handle.planes.emplace_back(pitches[i], offsets[i], 0);
+    pixmap_handle.planes.emplace_back(pitches[i], offsets[i], sizes[i], 0);
   }
   ui::SurfaceFactoryOzone* surface_factory =
       ui::OzonePlatform::GetInstance()->GetSurfaceFactoryOzone();
diff --git a/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc b/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
index 98bf556..78514ef 100644
--- a/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
+++ b/ui/ozone/gl/gl_image_ozone_native_pixmap_unittest.cc
@@ -38,11 +38,16 @@
     if (usage == gfx::BufferUsage::GPU_READ_CPU_READ_WRITE) {
       auto client_pixmap = client_pixmap_factory_->ImportFromHandle(
           pixmap->ExportHandle(), size, usage);
-      void* data = client_pixmap->Map();
-      EXPECT_TRUE(data);
-      GLImageTestSupport::SetBufferDataToColor(
-          size.width(), size.height(), pixmap->GetDmaBufPitch(0), 0,
-          pixmap->GetBufferFormat(), color, static_cast<uint8_t*>(data));
+      bool mapped = client_pixmap->Map();
+      EXPECT_TRUE(mapped);
+
+      for (size_t plane = 0; plane < NumberOfPlanesForBufferFormat(format);
+           ++plane) {
+        void* data = client_pixmap->GetMemoryAddress(plane);
+        GLImageTestSupport::SetBufferDataToColor(
+            size.width(), size.height(), pixmap->GetDmaBufPitch(plane), plane,
+            pixmap->GetBufferFormat(), color, static_cast<uint8_t*>(data));
+      }
       client_pixmap->Unmap();
     }
 
diff --git a/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc b/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
index 9c1cf29..01f0b0f 100644
--- a/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
+++ b/ui/ozone/platform/cast/client_native_pixmap_factory_cast.cc
@@ -19,12 +19,19 @@
 class ClientNativePixmapCast : public ClientNativePixmap {
  public:
   // ClientNativePixmap implementation:
-  void* Map() override {
+  bool Map() override {
+    NOTREACHED();
+    return false;
+  }
+  void* GetMemoryAddress(size_t plane) const override {
     NOTREACHED();
     return nullptr;
-  }
+  };
   void Unmap() override { NOTREACHED(); }
-  void GetStride(int* stride) const override { NOTREACHED(); }
+  int GetStride(size_t plane) const override {
+    NOTREACHED();
+    return 0;
+  }
 };
 
 class ClientNativePixmapFactoryCast : public ClientNativePixmapFactory {
diff --git a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc b/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
index 19b3e104..06aada4 100644
--- a/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
+++ b/ui/ozone/platform/drm/client_native_pixmap_factory_gbm.cc
@@ -21,12 +21,19 @@
   ClientNativePixmapGbm() {}
   ~ClientNativePixmapGbm() override {}
 
-  void* Map() override {
+  bool Map() override {
+    NOTREACHED();
+    return false;
+  }
+  void Unmap() override { NOTREACHED(); }
+  void* GetMemoryAddress(size_t plane) const override {
     NOTREACHED();
     return nullptr;
   }
-  void Unmap() override { NOTREACHED(); }
-  void GetStride(int* stride) const override { NOTREACHED(); }
+  int GetStride(size_t plane) const override {
+    NOTREACHED();
+    return 0;
+  }
 };
 
 }  // namespace
@@ -73,21 +80,20 @@
       const gfx::Size& size,
       gfx::BufferUsage usage) override {
     DCHECK(!handle.fds.empty());
-    base::ScopedFD scoped_fd(handle.fds[0].fd);
     switch (usage) {
       case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE:
       case gfx::BufferUsage::GPU_READ_CPU_READ_WRITE_PERSISTENT:
 #if defined(OS_CHROMEOS)
-        // TODO(dcastagna): Add support for pixmaps with multiple FDs for non
-        // scanout buffers.
-        return ClientNativePixmapDmaBuf::ImportFromDmabuf(
-            scoped_fd.release(), size, handle.planes[0].stride);
+        return ClientNativePixmapDmaBuf::ImportFromDmabuf(handle, size);
 #else
         NOTREACHED();
         return nullptr;
 #endif
       case gfx::BufferUsage::GPU_READ:
       case gfx::BufferUsage::SCANOUT:
+        // Close all the fds.
+        for (const auto& fd : handle.fds)
+          base::ScopedFD scoped_fd(fd.fd);
         return base::WrapUnique(new ClientNativePixmapGbm);
     }
     NOTREACHED();
diff --git a/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.cc b/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.cc
index a04bc5c4..8c547f8 100644
--- a/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.cc
+++ b/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.cc
@@ -58,42 +58,46 @@
 
 // static
 std::unique_ptr<ClientNativePixmap> ClientNativePixmapDmaBuf::ImportFromDmabuf(
-    int dmabuf_fd,
-    const gfx::Size& size,
-    int stride) {
-  DCHECK_GE(dmabuf_fd, 0);
-  base::CheckedNumeric<size_t> map_size = stride;
-  map_size *= size.height();
-  if (!map_size.IsValid())
-    return nullptr;
-  return base::WrapUnique(new ClientNativePixmapDmaBuf(dmabuf_fd, size, stride,
-                                                       map_size.ValueOrDie()));
+    const gfx::NativePixmapHandle& handle,
+    const gfx::Size& size) {
+  return base::WrapUnique(new ClientNativePixmapDmaBuf(handle, size));
 }
 
-ClientNativePixmapDmaBuf::ClientNativePixmapDmaBuf(int dmabuf_fd,
-                                                   const gfx::Size& size,
-                                                   int stride,
-                                                   size_t map_size)
-    : dmabuf_fd_(dmabuf_fd), map_size_(map_size), size_(size), stride_(stride) {
+ClientNativePixmapDmaBuf::ClientNativePixmapDmaBuf(
+    const gfx::NativePixmapHandle& handle,
+    const gfx::Size& size)
+    : pixmap_handle_(handle), size_(size), data_{0} {
   TRACE_EVENT0("drm", "ClientNativePixmapDmaBuf");
-  data_ = mmap(nullptr, map_size_, (PROT_READ | PROT_WRITE), MAP_SHARED,
-               dmabuf_fd, 0);
+  // TODO(dcastagna): support multiple fds.
+  DCHECK_EQ(1u, handle.fds.size());
+  DCHECK_GE(handle.fds.front().fd, 0);
+  dmabuf_fd_.reset(handle.fds.front().fd);
+
+  DCHECK_GE(handle.planes.back().size, 0u);
+  size_t map_size = handle.planes.back().offset + handle.planes.back().size;
+  data_ = mmap(nullptr, map_size, (PROT_READ | PROT_WRITE), MAP_SHARED,
+               dmabuf_fd_.get(), 0);
   if (data_ == MAP_FAILED) {
     PLOG(ERROR) << "Failed mmap().";
-    base::TerminateBecauseOutOfMemory(map_size_);
+    base::TerminateBecauseOutOfMemory(map_size);
   }
 }
 
 ClientNativePixmapDmaBuf::~ClientNativePixmapDmaBuf() {
   TRACE_EVENT0("drm", "~ClientNativePixmapDmaBuf");
-  int ret = munmap(data_, map_size_);
+  size_t map_size =
+      pixmap_handle_.planes.back().offset + pixmap_handle_.planes.back().size;
+  int ret = munmap(data_, map_size);
   DCHECK(!ret);
 }
 
-void* ClientNativePixmapDmaBuf::Map() {
+bool ClientNativePixmapDmaBuf::Map() {
   TRACE_EVENT0("drm", "DmaBuf:Map");
-  PrimeSyncStart(dmabuf_fd_.get());
-  return data_;
+  if (data_ != nullptr) {
+    PrimeSyncStart(dmabuf_fd_.get());
+    return true;
+  }
+  return false;
 }
 
 void ClientNativePixmapDmaBuf::Unmap() {
@@ -101,8 +105,15 @@
   PrimeSyncEnd(dmabuf_fd_.get());
 }
 
-void ClientNativePixmapDmaBuf::GetStride(int* stride) const {
-  *stride = stride_;
+void* ClientNativePixmapDmaBuf::GetMemoryAddress(size_t plane) const {
+  DCHECK_LT(plane, pixmap_handle_.planes.size());
+  uint8_t* address = reinterpret_cast<uint8_t*>(data_);
+  return address + pixmap_handle_.planes[plane].offset;
+}
+
+int ClientNativePixmapDmaBuf::GetStride(size_t plane) const {
+  DCHECK_LT(plane, pixmap_handle_.planes.size());
+  return pixmap_handle_.planes[plane].stride;
 }
 
 }  // namespace ui
diff --git a/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h b/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h
index 4fef392..9817235 100644
--- a/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h
+++ b/ui/ozone/platform/drm/common/client_native_pixmap_dmabuf.h
@@ -12,32 +12,33 @@
 #include "base/files/scoped_file.h"
 #include "base/macros.h"
 #include "ui/gfx/geometry/size.h"
+#include "ui/gfx/native_pixmap_handle.h"
 #include "ui/ozone/public/client_native_pixmap.h"
 
 namespace ui {
 
 class ClientNativePixmapDmaBuf : public ClientNativePixmap {
  public:
-  static std::unique_ptr<ClientNativePixmap>
-  ImportFromDmabuf(int dmabuf_fd, const gfx::Size& size, int stride);
+  static std::unique_ptr<ClientNativePixmap> ImportFromDmabuf(
+      const gfx::NativePixmapHandle& handle,
+      const gfx::Size& size);
 
   ~ClientNativePixmapDmaBuf() override;
 
   // Overridden from ClientNativePixmap.
-  void* Map() override;
+  bool Map() override;
   void Unmap() override;
-  void GetStride(int* stride) const override;
+
+  void* GetMemoryAddress(size_t plane) const override;
+  int GetStride(size_t plane) const override;
 
  private:
-  ClientNativePixmapDmaBuf(int dmabuf_fd,
-                           const gfx::Size& size,
-                           int stride,
-                           size_t map_size);
+  ClientNativePixmapDmaBuf(const gfx::NativePixmapHandle& handle,
+                           const gfx::Size& size);
 
-  base::ScopedFD dmabuf_fd_;
-  const size_t map_size_;
+  const gfx::NativePixmapHandle pixmap_handle_;
   const gfx::Size size_;
-  const int stride_;
+  base::ScopedFD dmabuf_fd_;
   void* data_;
 
   DISALLOW_COPY_AND_ASSIGN(ClientNativePixmapDmaBuf);
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.cc b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
index 8b9a893..0f38ed8 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.cc
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.cc
@@ -75,6 +75,11 @@
   return planes_[index].offset;
 }
 
+size_t GbmBuffer::GetSize(size_t index) const {
+  DCHECK_LT(index, planes_.size());
+  return planes_[index].size;
+}
+
 uint64_t GbmBuffer::GetFormatModifier(size_t index) const {
   DCHECK_LT(index, planes_.size());
   return planes_[index].modifier;
@@ -123,16 +128,20 @@
     // kept open for the lifetime of the buffer.
     base::ScopedFD fd(gbm_bo_get_plane_fd(bo, i));
 
-    if (!fd.is_valid()) {
-      PLOG(ERROR) << "Failed to export buffer to dma_buf";
-      gbm_bo_destroy(bo);
-      return nullptr;
+    // TODO(dcastagna): support multiple fds.
+    // crbug.com/642410
+    if (!i) {
+      if (!fd.is_valid()) {
+        PLOG(ERROR) << "Failed to export buffer to dma_buf";
+        gbm_bo_destroy(bo);
+        return nullptr;
+      }
+      fds.emplace_back(std::move(fd));
     }
-    fds.emplace_back(std::move(fd));
 
-    planes.emplace_back(gbm_bo_get_plane_stride(bo, i),
-                        gbm_bo_get_plane_offset(bo, i),
-                        gbm_bo_get_plane_format_modifier(bo, i));
+    planes.emplace_back(
+        gbm_bo_get_plane_stride(bo, i), gbm_bo_get_plane_offset(bo, i),
+        gbm_bo_get_plane_size(bo, i), gbm_bo_get_plane_format_modifier(bo, i));
   }
   scoped_refptr<GbmBuffer> buffer(new GbmBuffer(
       gbm, bo, format, usage, std::move(fds), size, std::move(planes)));
@@ -216,6 +225,7 @@
           base::FileDescriptor(scoped_fd.release(), true /* auto_close */));
     }
     handle.planes.emplace_back(buffer_->GetStride(i), buffer_->GetOffset(i),
+                               buffer_->GetSize(i),
                                buffer_->GetFormatModifier(i));
   }
   return handle;
diff --git a/ui/ozone/platform/drm/gpu/gbm_buffer.h b/ui/ozone/platform/drm/gpu/gbm_buffer.h
index b8397448..f4ff68a2 100644
--- a/ui/ozone/platform/drm/gpu/gbm_buffer.h
+++ b/ui/ozone/platform/drm/gpu/gbm_buffer.h
@@ -41,6 +41,7 @@
   int GetFd(size_t plane) const;
   int GetStride(size_t plane) const;
   int GetOffset(size_t plane) const;
+  size_t GetSize(size_t plane) const;
   uint64_t GetFormatModifier(size_t plane) const;
   gfx::Size GetSize() const override;
 
diff --git a/ui/ozone/public/client_native_pixmap.h b/ui/ozone/public/client_native_pixmap.h
index e7aa3615..a94e34f 100644
--- a/ui/ozone/public/client_native_pixmap.h
+++ b/ui/ozone/public/client_native_pixmap.h
@@ -16,9 +16,13 @@
  public:
   virtual ~ClientNativePixmap() {}
 
-  virtual void* Map() = 0;
+  // Map each plane in the client address space.
+  // Return false on error.
+  virtual bool Map() = 0;
   virtual void Unmap() = 0;
-  virtual void GetStride(int* stride) const = 0;
+
+  virtual void* GetMemoryAddress(size_t plane) const = 0;
+  virtual int GetStride(size_t plane) const = 0;
 };
 
 }  // namespace ui
diff --git a/ui/views/mus/clipboard_mus.cc b/ui/views/mus/clipboard_mus.cc
index 8e43571d..3fb01b9 100644
--- a/ui/views/mus/clipboard_mus.cc
+++ b/ui/views/mus/clipboard_mus.cc
@@ -4,6 +4,10 @@
 
 #include "ui/views/mus/clipboard_mus.h"
 
+#include <string>
+#include <utility>
+#include <vector>
+
 #include "base/logging.h"
 #include "base/stl_util.h"
 #include "base/strings/utf_string_conversions.h"
@@ -256,7 +260,8 @@
 
 void ClipboardMus::WriteObjects(ui::ClipboardType type,
                                 const ObjectMap& objects) {
-  current_clipboard_.reset(new mojo::Map<mojo::String, mojo::Array<uint8_t>>);
+  current_clipboard_ =
+      base::MakeUnique<mojo::Map<mojo::String, mojo::Array<uint8_t>>>();
   for (const auto& p : objects)
     DispatchObject(static_cast<ObjectType>(p.first), p.second);
 
diff --git a/ui/views/mus/input_method_mus.cc b/ui/views/mus/input_method_mus.cc
index fb28dbd..9540e984 100644
--- a/ui/views/mus/input_method_mus.cc
+++ b/ui/views/mus/input_method_mus.cc
@@ -114,7 +114,7 @@
   InputMethodBase::OnDidChangeFocusedClient(focused_before, focused);
   UpdateTextInputType();
 
-  text_input_client_.reset(new TextInputClientImpl(focused, this));
+  text_input_client_ = base::MakeUnique<TextInputClientImpl>(focused, this);
   ime_server_->StartSession(text_input_client_->CreateInterfacePtrAndBind(),
                             GetProxy(&input_method_));
 }
diff --git a/ui/views/mus/input_method_mus_unittest.cc b/ui/views/mus/input_method_mus_unittest.cc
index 0c0e3c6..618a46b3 100644
--- a/ui/views/mus/input_method_mus_unittest.cc
+++ b/ui/views/mus/input_method_mus_unittest.cc
@@ -4,6 +4,8 @@
 
 #include "ui/views/mus/input_method_mus.h"
 
+#include <memory>
+
 #include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
 #include "testing/gtest/include/gtest/gtest.h"
@@ -37,7 +39,7 @@
   ~TestTextInputClient() override {}
 
   ui::KeyEvent* WaitUntilInputReceieved() {
-    run_loop_.reset(new base::RunLoop);
+    run_loop_ = base::MakeUnique<base::RunLoop>();
     run_loop_->Run();
     run_loop_.reset();
 
diff --git a/ui/views/mus/pointer_watcher_event_router_unittest.cc b/ui/views/mus/pointer_watcher_event_router_unittest.cc
index ba6cec9..511cc33 100644
--- a/ui/views/mus/pointer_watcher_event_router_unittest.cc
+++ b/ui/views/mus/pointer_watcher_event_router_unittest.cc
@@ -30,7 +30,7 @@
   void OnPointerEventObserved(const ui::PointerEvent& event,
                               const gfx::Point& location_in_screen,
                               Widget* target) override {
-    last_event_observed_.reset(new ui::PointerEvent(event));
+    last_event_observed_ = base::MakeUnique<ui::PointerEvent>(event);
   }
 
  private:
diff --git a/ui/views/mus/views_mus_test_suite.cc b/ui/views/mus/views_mus_test_suite.cc
index 701ea56..bf63030 100644
--- a/ui/views/mus/views_mus_test_suite.cc
+++ b/ui/views/mus/views_mus_test_suite.cc
@@ -5,6 +5,7 @@
 #include "ui/views/mus/views_mus_test_suite.h"
 
 #include <memory>
+#include <string>
 
 #include "base/command_line.h"
 #include "base/files/file_path.h"
@@ -33,7 +34,7 @@
 
 class DefaultService : public shell::Service {
  public:
-   DefaultService() {}
+  DefaultService() {}
   ~DefaultService() override {}
 
  private:
@@ -114,12 +115,11 @@
   }
 
   void SetUpConnections(base::WaitableEvent* wait) {
-    background_shell_.reset(new shell::BackgroundShell);
+    background_shell_ = base::MakeUnique<shell::BackgroundShell>();
     background_shell_->Init(nullptr);
-    service_.reset(new DefaultService);
-    shell_connection_.reset(new shell::ServiceContext(
-        service_.get(),
-        background_shell_->CreateServiceRequest(GetTestName())));
+    service_ = base::MakeUnique<DefaultService>();
+    shell_connection_ = base::MakeUnique<shell::ServiceContext>(
+        service_.get(), background_shell_->CreateServiceRequest(GetTestName()));
 
     // ui/views/mus requires a WindowManager running, so launch test_wm.
     shell::Connector* connector = shell_connection_->connector();
@@ -166,7 +166,7 @@
   EnsureCommandLineSwitch(ui::switches::kUseTestConfig);
 
   ViewsTestSuite::Initialize();
-  shell_connections_.reset(new ShellConnection);
+  shell_connections_ = base::MakeUnique<ShellConnection>();
 }
 
 void ViewsMusTestSuite::Shutdown() {
diff --git a/ui/views/mus/window_manager_connection.cc b/ui/views/mus/window_manager_connection.cc
index 7b30672..8c4cf85 100644
--- a/ui/views/mus/window_manager_connection.cc
+++ b/ui/views/mus/window_manager_connection.cc
@@ -4,6 +4,7 @@
 
 #include "ui/views/mus/window_manager_connection.h"
 
+#include <set>
 #include <utility>
 
 #include "base/lazy_instance.h"
@@ -113,20 +114,20 @@
   lazy_tls_ptr.Pointer()->Set(this);
 
   gpu_service_ = ui::GpuService::Create(connector, std::move(task_runner));
-  compositor_context_factory_.reset(
-      new views::SurfaceContextFactory(gpu_service_.get()));
+  compositor_context_factory_ =
+      base::MakeUnique<views::SurfaceContextFactory>(gpu_service_.get());
   aura::Env::GetInstance()->set_context_factory(
       compositor_context_factory_.get());
-  client_.reset(new ui::WindowTreeClient(this, nullptr, nullptr));
+  client_ = base::MakeUnique<ui::WindowTreeClient>(this, nullptr, nullptr);
   client_->ConnectViaWindowTreeFactory(connector_);
 
-  pointer_watcher_event_router_.reset(
-      new PointerWatcherEventRouter(client_.get()));
+  pointer_watcher_event_router_ =
+      base::MakeUnique<PointerWatcherEventRouter>(client_.get());
 
-  screen_.reset(new ScreenMus(this));
+  screen_ = base::MakeUnique<ScreenMus>(this);
   screen_->Init(connector);
 
-  std::unique_ptr<ClipboardMus> clipboard(new ClipboardMus);
+  std::unique_ptr<ClipboardMus> clipboard = base::MakeUnique<ClipboardMus>();
   clipboard->Init(connector);
   ui::Clipboard::SetClipboardForCurrentThread(std::move(clipboard));
 
diff --git a/ui/views/mus/window_tree_host_mus.cc b/ui/views/mus/window_tree_host_mus.cc
index 745c1a6c..caed8943 100644
--- a/ui/views/mus/window_tree_host_mus.cc
+++ b/ui/views/mus/window_tree_host_mus.cc
@@ -54,7 +54,7 @@
   dispatcher()->set_transform_events(false);
   compositor()->SetHostHasTransparentBackground(true);
 
-  input_method_.reset(new InputMethodMus(this, window));
+  input_method_ = base::MakeUnique<InputMethodMus>(this, window);
   SetSharedInputMethod(input_method_.get());
 }