diff --git a/BUILD.gn b/BUILD.gn
index 2beb6626..5f9f3a9 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -25,7 +25,7 @@
   root_extra_deps = []
 }
 
-# This file defines the following four main targets:
+# This file defines the following five main targets:
 #
 # "both_gn_and_gyp" should list every root target (target that nothing else
 # depends on) built by GN that is also built in the GYP build.
@@ -33,19 +33,29 @@
 # "gn_all" should (transitively) cause everything to be built; if you run
 # 'ninja gn_all' and then 'ninja all', the second build should do no work.
 #
-# "gn_only" should list every root target that is *not* intended to be built
-# in a GYP build. Because GN has different rules for deciding what an 'all'
-# build is, this may end up including targets that are actually defined in a
-# GYP build but not dependencies of GYP's "all" (and so not actually built).
+# "gn_only" should list every root target that is *not* intended to be built in
+# a GYP build. Because GN has different rules for deciding what an 'all' build
+# is, this may end up including targets that are actually defined in a GYP
+# build but not dependencies of GYP's "all" (and so not actually built).
 #
 # "gn_visibility": targets that are normally not visible to top-level targets,
-# but are built anyway by "all". Since we don't want any such targets, we
-# have this placeholder to make sure hidden targets that aren't otherwise
-# depended on yet are accounted for.
+# but are built anyway by "all". Since we don't want any such targets, we have
+# this placeholder to make sure hidden targets that aren't otherwise depended
+# on yet are accounted for.
+#
+# "All" is an alias for "gn_all". It exists for bot compatibility w/ GYP for
+# the iOS bots and the official builders, but should not be generally used
+# during the GYP->GN migration.  We cannot guarantee that GN's "All" builds the
+# same set of targets as GYP's "All" does, because GYP's "All" supports
+# wildcards.
+#
+# Lastly, none of these targets are guaranteed to be the same as what ninja
+# will build with "all". For more on how "all" works and the differences in how
+# GYP and GN determine "all", see crbug.com/503241.
 #
 # TODO(GYP): crbug.com/481694. Make sure that the above is true and there are
-# scripts run on the bots that enforce this. Once the GYP migration is over,
-# we can collapse all of these targets as desired.
+# scripts run on the bots that enforce this. Once the GYP migration is over, we
+# can collapse all of these targets as desired.
 
 group("gn_all") {
   testonly = true
@@ -57,6 +67,16 @@
   ]
 }
 
+# TODO(GYP): This target exists for compatibility with GYP, specifically
+# for the iOS bots and the official builders.
+group("All") {
+  testonly = true
+
+  deps = [
+    ":gn_all",
+  ]
+}
+
 # The "both_gn_and_gyp" target should reflect every target that is built
 # in both the GN and GYP builds, and ideally it should match the
 # "both_gn_and_gyp" target in build/gn_migration.gypi line-for-line.
diff --git a/DEPS b/DEPS
index b16b9c6..6c08c19 100644
--- a/DEPS
+++ b/DEPS
@@ -43,7 +43,7 @@
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling V8
   # and whatever else without interference from each other.
-  'v8_revision': '10449d46aa20f10f39598627bf07f70def597029',
+  'v8_revision': '00820330372dd1588a7f96649ad83fe5ffb9bbbf',
   # Three lines of non-changing comments so that
   # the commit queue can handle CLs rolling swarming_client
   # and whatever else without interference from each other.
diff --git a/build/linux/install-chromeos-fonts.py b/build/linux/install-chromeos-fonts.py
index a24adc92..460f10d 100755
--- a/build/linux/install-chromeos-fonts.py
+++ b/build/linux/install-chromeos-fonts.py
@@ -12,10 +12,21 @@
 import subprocess
 import sys
 
-# Taken from the media-fonts/notofonts ebuild in chromiumos-overlay.
-VERSION = '20140815'
-URL = ('https://commondatastorage.googleapis.com/chromeos-localmirror/'
-       'distfiles/notofonts-%s.tar.bz2') % (VERSION)
+URL_TEMPLATE = ('https://commondatastorage.googleapis.com/chromeos-localmirror/'
+                'distfiles/%(name)s-%(version)s.tar.bz2')
+
+# Taken from the media-fonts/<name> ebuilds in chromiumos-overlay.
+SOURCES = [
+  {
+    'name': 'notofonts',
+    'version': '20150706'
+  }, {
+    'name': 'robotofonts',
+    'version': '20150625'
+  }
+]
+
+URLS = sorted([URL_TEMPLATE % d for d in SOURCES])
 FONTS_DIR = '/usr/local/share/fonts'
 
 def main(args):
@@ -36,7 +47,7 @@
   stamp = os.path.join(dest_dir, ".stamp02")
   if os.path.exists(stamp):
     with open(stamp) as s:
-      if s.read() == URL:
+      if s.read() == '\n'.join(URLS):
         print "Chrome OS fonts already up-to-date in %s." % dest_dir
         return 0
 
@@ -46,11 +57,12 @@
   os.chmod(dest_dir, 0755)
 
   print "Installing Chrome OS fonts to %s." % dest_dir
-  tarball = os.path.join(dest_dir, os.path.basename(URL))
-  subprocess.check_call(['curl', '-L', URL, '-o', tarball])
-  subprocess.check_call(['tar', '--no-same-owner', '--no-same-permissions',
-                         '-xf', tarball, '-C', dest_dir])
-  os.remove(tarball)
+  for url in URLS:
+    tarball = os.path.join(dest_dir, os.path.basename(url))
+    subprocess.check_call(['curl', '-L', url, '-o', tarball])
+    subprocess.check_call(['tar', '--no-same-owner', '--no-same-permissions',
+                           '-xf', tarball, '-C', dest_dir])
+    os.remove(tarball)
 
   readme = os.path.join(dest_dir, "README")
   with open(readme, 'w') as s:
@@ -59,7 +71,7 @@
     s.write("Script: %s\n" % __file__)
 
   with open(stamp, 'w') as s:
-    s.write(URL)
+    s.write('\n'.join(URLS))
 
   for base, dirs, files in os.walk(dest_dir):
     for dir in dirs:
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
index b8ba464..837ce237 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeActivity.java
@@ -123,10 +123,10 @@
 import org.chromium.chrome.browser.util.FeatureUtilities;
 import org.chromium.chrome.browser.webapps.AddToHomescreenDialog;
 import org.chromium.chrome.browser.widget.ControlContainer;
-import org.chromium.content.browser.ContentReadbackHandler;
 import org.chromium.content.browser.ContentVideoView;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.common.ContentSwitches;
+import org.chromium.content_public.browser.ContentBitmapCallback;
 import org.chromium.content_public.browser.LoadUrlParams;
 import org.chromium.content_public.browser.readback_types.ReadbackResponse;
 import org.chromium.policy.CombinedPolicyProvider.PolicyChangeListener;
@@ -177,6 +177,7 @@
      */
     private static final int PARTNER_BROWSER_CUSTOMIZATIONS_TIMEOUT_MS = 10000;
     private static final String TAG = "cr.ChromeActivity";
+    private static final Rect EMPTY_RECT = new Rect();
 
     private TabModelSelector mTabModelSelector;
     private TabModelSelectorTabObserver mTabModelSelectorTabObserver;
@@ -903,10 +904,9 @@
         if (currentTab == null) return;
 
         final Activity mainActivity = this;
-        ContentReadbackHandler.GetBitmapCallback bitmapCallback =
-                new ContentReadbackHandler.GetBitmapCallback() {
+        ContentBitmapCallback callback = new ContentBitmapCallback() {
                     @Override
-                    public void onFinishGetBitmap(Bitmap bitmap, int reponse) {
+                    public void onFinishGetBitmap(Bitmap bitmap, int response) {
                         ShareHelper.share(shareDirectly, mainActivity, currentTab.getTitle(),
                                 currentTab.getUrl(), bitmap);
                         if (shareDirectly) {
@@ -916,12 +916,11 @@
                         }
                     }
                 };
-        ContentReadbackHandler readbackHandler = getContentReadbackHandler();
-        if (isIncognito || readbackHandler == null || currentTab.getContentViewCore() == null) {
-            bitmapCallback.onFinishGetBitmap(null, ReadbackResponse.SURFACE_UNAVAILABLE);
+        if (isIncognito || currentTab.getWebContents() == null) {
+            callback.onFinishGetBitmap(null, ReadbackResponse.SURFACE_UNAVAILABLE);
         } else {
-            readbackHandler.getContentBitmapAsync(1, new Rect(), currentTab.getContentViewCore(),
-                    Bitmap.Config.ARGB_8888, bitmapCallback);
+            currentTab.getWebContents().getContentBitmapAsync(
+                    Bitmap.Config.ARGB_8888, 1.f, EMPTY_RECT, callback);
         }
     }
 
@@ -1185,13 +1184,6 @@
     }
 
     /**
-     * @return The content readback handler, may be null.
-     */
-    public ContentReadbackHandler getContentReadbackHandler() {
-        return mCompositorViewHolder.getContentReadbackHandler();
-    }
-
-    /**
      * @return The {@code ContextualSearchManager} or {@code null} if none;
      */
     public ContextualSearchManager getContextualSearchManager() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
index 0a44cbd..3d0f4d8 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorView.java
@@ -39,7 +39,6 @@
 import org.chromium.chrome.browser.multiwindow.MultiWindowUtils;
 import org.chromium.chrome.browser.tabmodel.TabModelImpl;
 import org.chromium.chrome.browser.widget.ClipDrawableProgressBar.DrawingInfo;
-import org.chromium.content.browser.ContentReadbackHandler;
 import org.chromium.ui.base.DeviceFormFactor;
 import org.chromium.ui.base.WindowAndroid;
 import org.chromium.ui.resources.AndroidResourceType;
@@ -80,8 +79,6 @@
     private int mSurfaceHeight;
     private boolean mPreloadedResources;
 
-    private ContentReadbackHandler mContentReadbackHandler;
-
     // The current SurfaceView pixel format. Defaults to OPAQUE.
     private int mCurrentPixelFormat = PixelFormat.OPAQUE;
 
@@ -97,12 +94,6 @@
         resetFlags();
         setVisibility(View.INVISIBLE);
         setZOrderMediaOverlay(true);
-        mContentReadbackHandler = new ContentReadbackHandler() {
-            @Override
-            protected boolean readyForReadback() {
-                return mNativeCompositorView != 0;
-            }
-        };
     }
 
     /**
@@ -166,13 +157,6 @@
     }
 
     /**
-     * @return The content readback handler.
-     */
-    public ContentReadbackHandler getContentReadbackHandler() {
-        return mContentReadbackHandler;
-    }
-
-    /**
      * @return The ResourceManager.
      */
     public ResourceManager getResourceManager() {
@@ -199,8 +183,6 @@
      */
     public void shutDown() {
         getHolder().removeCallback(this);
-        mContentReadbackHandler.destroy();
-        mContentReadbackHandler = null;
         if (mNativeCompositorView != 0) nativeDestroy(mNativeCompositorView);
         mNativeCompositorView = 0;
     }
@@ -232,8 +214,6 @@
 
         // Grab the Resource Manager
         mResourceManager = nativeGetResourceManager(mNativeCompositorView);
-
-        mContentReadbackHandler.initNativeContentReadbackHandler();
     }
 
     @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
index 6344a84..74f6685d 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/CompositorViewHolder.java
@@ -51,7 +51,6 @@
 import org.chromium.chrome.browser.util.ColorUtils;
 import org.chromium.chrome.browser.widget.ClipDrawableProgressBar.DrawingInfo;
 import org.chromium.chrome.browser.widget.ControlContainer;
-import org.chromium.content.browser.ContentReadbackHandler;
 import org.chromium.content.browser.ContentViewClient;
 import org.chromium.content.browser.ContentViewCore;
 import org.chromium.content.browser.SPenSupport;
@@ -322,14 +321,6 @@
     }
 
     /**
-     * @return The content readback handler.
-     */
-    public ContentReadbackHandler getContentReadbackHandler() {
-        if (mCompositorView == null) return null;
-        return mCompositorView.getContentReadbackHandler();
-    }
-
-    /**
      * @return The {@link DynamicResourceLoader} for registering resources.
      */
     public DynamicResourceLoader getDynamicResourceLoader() {
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index f008f51..11f5399f 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -575,22 +575,19 @@
     # These files are only built in a GN build because they bring in
     # dependencies that don't build with GYP.
     sources += [
-      "mojo_runner_state.cc",
-      "mojo_runner_state.h",
       "ui/views/frame/browser_frame_mus.cc",
       "ui/views/frame/browser_frame_mus.h",
     ]
     deps += [
-      "//components/mus/public/interfaces",
+      "//content/public/common",
       "//mojo/runner/child:lib",
-      "//mojo/converters/network",
       "//ui/aura",
       "//ui/compositor",
       "//ui/keyboard",
       "//ui/keyboard:keyboard_with_content",
-      "//ui/views/mus",
+      "//ui/views/mus:for_component",
     ]
-    defines += [ "MOJO_RUNNER_CLIENT" ]
+    defines += [ "MOJO_SHELL_CLIENT" ]
     data_deps += [ "//components/mus/example/wm:example_wm" ]
   }
   if (ui_compositor_image_transport) {
diff --git a/chrome/browser/browsing_data/browsing_data_remover.cc b/chrome/browser/browsing_data/browsing_data_remover.cc
index ffa822f..f8865d3 100644
--- a/chrome/browser/browsing_data/browsing_data_remover.cc
+++ b/chrome/browser/browsing_data/browsing_data_remover.cc
@@ -581,11 +581,14 @@
   }
 #endif
 
+  if (remove_mask & REMOVE_SITE_USAGE_DATA) {
+    HostContentSettingsMapFactory::GetForProfile(profile_)
+        ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT);
+  }
+
   if (remove_mask & REMOVE_SITE_USAGE_DATA || remove_mask & REMOVE_HISTORY) {
     HostContentSettingsMapFactory::GetForProfile(profile_)
         ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_APP_BANNER);
-    HostContentSettingsMapFactory::GetForProfile(profile_)
-        ->ClearSettingsForOneType(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT);
   }
 
   if (remove_mask & REMOVE_PASSWORDS) {
diff --git a/chrome/browser/chrome_browser_main.cc b/chrome/browser/chrome_browser_main.cc
index 58be71c..5114e39 100644
--- a/chrome/browser/chrome_browser_main.cc
+++ b/chrome/browser/chrome_browser_main.cc
@@ -63,7 +63,6 @@
 #include "chrome/browser/memory/tab_manager.h"
 #include "chrome/browser/metrics/field_trial_synchronizer.h"
 #include "chrome/browser/metrics/thread_watcher.h"
-#include "chrome/browser/mojo_runner_util.h"
 #include "chrome/browser/nacl_host/nacl_browser_delegate_impl.h"
 #include "chrome/browser/net/crl_set_fetcher.h"
 #include "chrome/browser/performance_monitor/performance_monitor.h"
@@ -248,10 +247,6 @@
 #include "components/webusb/webusb_detector.h"
 #endif
 
-#if defined(MOJO_RUNNER_CLIENT)
-#include "chrome/browser/mojo_runner_state.h"
-#endif
-
 using content::BrowserThread;
 
 namespace {
@@ -1217,13 +1212,6 @@
   SCOPED_UMA_HISTOGRAM_LONG_TIMER("Startup.PreMainMessageLoopRunImplLongTime");
   const base::TimeTicks start_time_step1 = base::TimeTicks::Now();
 
-#if defined(MOJO_RUNNER_CLIENT)
-  if (IsRunningInMojoRunner()) {
-    mojo_runner_state_.reset(new MojoRunnerState);
-    mojo_runner_state_->WaitForConnection();
-  }
-#endif  // defined(MOJO_RUNNER_CLIENT)
-
 #if defined(OS_WIN)
   // Windows parental controls calls can be slow, so we do an early init here
   // that calculates this value off of the UI thread.
diff --git a/chrome/browser/chrome_browser_main.h b/chrome/browser/chrome_browser_main.h
index bc3face..140a960 100644
--- a/chrome/browser/chrome_browser_main.h
+++ b/chrome/browser/chrome_browser_main.h
@@ -23,7 +23,6 @@
 class ChromeBrowserMainExtraParts;
 class FieldTrialSynchronizer;
 class MetricsService;
-class MojoRunnerState;
 class PrefService;
 class ProcessPowerCollector;
 class Profile;
@@ -192,10 +191,6 @@
   // Members needed across shutdown methods.
   bool restart_last_session_;
 
-#if defined(MOJO_RUNNER_CLIENT)
-  scoped_ptr<MojoRunnerState> mojo_runner_state_;
-#endif
-
   DISALLOW_COPY_AND_ASSIGN(ChromeBrowserMainParts);
 };
 
diff --git a/chrome/browser/chromeos/drive/fileapi/fileapi_worker.cc b/chrome/browser/chromeos/drive/fileapi/fileapi_worker.cc
index 128b42c..1df0ae2 100644
--- a/chrome/browser/chromeos/drive/fileapi/fileapi_worker.cc
+++ b/chrome/browser/chromeos/drive/fileapi/fileapi_worker.cc
@@ -82,9 +82,6 @@
 
     const PlatformFileInfoProto& file_info = resource_entry.file_info();
     entry.is_directory = file_info.is_directory();
-    entry.size = file_info.size();
-    entry.last_modified_time =
-        base::Time::FromInternalValue(file_info.last_modified());
     entries.push_back(entry);
   }
 
diff --git a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
index d218101..fb3fce5 100644
--- a/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
+++ b/chrome/browser/chromeos/file_system_provider/fake_provided_file_system.cc
@@ -136,11 +136,9 @@
     if (file_path == directory_path || directory_path.IsParent(file_path)) {
       const EntryMetadata* const metadata = it->second->metadata.get();
       entry_list.push_back(storage::DirectoryEntry(
-          metadata->name,
-          metadata->is_directory ? storage::DirectoryEntry::DIRECTORY
-                                 : storage::DirectoryEntry::FILE,
-          metadata->size,
-          metadata->modification_time));
+          metadata->name, metadata->is_directory
+                              ? storage::DirectoryEntry::DIRECTORY
+                              : storage::DirectoryEntry::FILE));
     }
   }
 
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc
index f98a1459..0cc8389 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata.cc
@@ -32,10 +32,10 @@
 
   output->name = params->metadata.name;
   output->is_directory = params->metadata.is_directory;
-  output->size = static_cast<int64>(params->metadata.size);
+  output->size = static_cast<int64>(*params->metadata.size);
 
   std::string input_modification_time;
-  if (!params->metadata.modification_time.additional_properties.GetString(
+  if (!params->metadata.modification_time->additional_properties.GetString(
           "value", &input_modification_time)) {
     NOTREACHED();
   }
@@ -65,7 +65,8 @@
     return false;
 
   std::string input_modification_time;
-  if (!metadata.modification_time.additional_properties.GetString(
+  if (metadata.modification_time.get() &&
+      !metadata.modification_time->additional_properties.GetString(
           "value", &input_modification_time)) {
     return false;
   }
diff --git a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
index efdd4994..59ec1aa 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/get_metadata_unittest.cc
@@ -92,6 +92,9 @@
 
 }  // namespace
 
+using ModificationTime =
+    extensions::api::file_system_provider::EntryMetadata::ModificationTime;
+
 class FileSystemProviderOperationsGetMetadataTest : public testing::Test {
  protected:
   FileSystemProviderOperationsGetMetadataTest() {}
@@ -127,7 +130,8 @@
   {
     EntryMetadata metadata;
     metadata.name = kValidFileName;
-    metadata.modification_time.additional_properties.SetString(
+    metadata.modification_time.reset(new ModificationTime());
+    metadata.modification_time->additional_properties.SetString(
         "value", "invalid-date-time");  // Invalid modification time is OK.
     metadata.thumbnail.reset(new std::string(kValidThumbnailUrl));
     EXPECT_TRUE(ValidateIDLEntryMetadata(metadata, false /* root_path */));
@@ -137,7 +141,8 @@
   {
     EntryMetadata metadata;
     metadata.name = kValidFileName;
-    metadata.modification_time.additional_properties.SetString(
+    metadata.modification_time.reset(new ModificationTime());
+    metadata.modification_time->additional_properties.SetString(
         "value", "invalid-date-time");  // Invalid modification time is OK.
     EXPECT_TRUE(ValidateIDLEntryMetadata(metadata, false /* root_path */));
   }
@@ -146,7 +151,8 @@
   {
     EntryMetadata metadata;
     metadata.name = "";
-    metadata.modification_time.additional_properties.SetString(
+    metadata.modification_time.reset(new ModificationTime());
+    metadata.modification_time->additional_properties.SetString(
         "value", "invalid-date-time");  // Invalid modification time is OK.
     EXPECT_TRUE(ValidateIDLEntryMetadata(metadata, true /* root_path */));
   }
@@ -155,7 +161,8 @@
   {
     EntryMetadata metadata;
     metadata.name = "hello/world";
-    metadata.modification_time.additional_properties.SetString(
+    metadata.modification_time.reset(new ModificationTime());
+    metadata.modification_time->additional_properties.SetString(
         "value", "invalid-date-time");  // Invalid modification time is OK.
     metadata.thumbnail.reset(new std::string(kValidThumbnailUrl));
     EXPECT_FALSE(ValidateIDLEntryMetadata(metadata, false /* root_path */));
@@ -165,25 +172,27 @@
   {
     EntryMetadata metadata;
     metadata.name = "";
-    metadata.modification_time.additional_properties.SetString(
+    metadata.modification_time.reset(new ModificationTime());
+    metadata.modification_time->additional_properties.SetString(
         "value", "invalid-date-time");  // Invalid modification time is OK.
     metadata.thumbnail.reset(new std::string(kValidThumbnailUrl));
     EXPECT_FALSE(ValidateIDLEntryMetadata(metadata, false /* root_path */));
   }
 
-  // Missing date time.
+  // Missing last modification time is allowed.
   {
     EntryMetadata metadata;
     metadata.name = kValidFileName;
     metadata.thumbnail.reset(new std::string(kValidThumbnailUrl));
-    EXPECT_FALSE(ValidateIDLEntryMetadata(metadata, false /* root_path */));
+    EXPECT_TRUE(ValidateIDLEntryMetadata(metadata, false /* root_path */));
   }
 
   // Invalid thumbnail.
   {
     EntryMetadata metadata;
     metadata.name = kValidFileName;
-    metadata.modification_time.additional_properties.SetString(
+    metadata.modification_time.reset(new ModificationTime());
+    metadata.modification_time->additional_properties.SetString(
         "value", "invalid-date-time");  // Invalid modification time is OK.
     metadata.thumbnail.reset(new std::string("http://invalid-scheme"));
     EXPECT_FALSE(ValidateIDLEntryMetadata(metadata, false /* root_path */));
diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_directory.cc b/chrome/browser/chromeos/file_system_provider/operations/read_directory.cc
index d9f34c16..72ec917 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/read_directory.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/read_directory.cc
@@ -35,17 +35,6 @@
     storage::DirectoryEntry output_entry;
     output_entry.is_directory = entry_metadata->is_directory;
     output_entry.name = entry_metadata->name;
-    output_entry.size = static_cast<int64>(entry_metadata->size);
-
-    std::string input_modification_time;
-    if (!entry_metadata->modification_time.additional_properties.GetString(
-            "value", &input_modification_time)) {
-      NOTREACHED();
-    }
-    if (!base::Time::FromString(input_modification_time.c_str(),
-                                &output_entry.last_modified_time)) {
-      NOTREACHED();
-    }
 
     output->push_back(output_entry);
   }
diff --git a/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc b/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
index b763990..4c2f2a1 100644
--- a/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
+++ b/chrome/browser/chromeos/file_system_provider/operations/read_directory_unittest.cc
@@ -185,11 +185,7 @@
       "  [\n"
       "    {\n"
       "      \"isDirectory\": false,\n"
-      "      \"name\": \"blueberries.txt\",\n"
-      "      \"size\": 4096,\n"
-      "      \"modificationTime\": {\n"
-      "        \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n"
-      "      }\n"
+      "      \"name\": \"blueberries.txt\"\n"
       "    }\n"
       "  ],\n"
       "  false,\n"  // has_more
@@ -209,11 +205,6 @@
   const storage::DirectoryEntry entry = event->entry_list()[0];
   EXPECT_FALSE(entry.is_directory);
   EXPECT_EQ("blueberries.txt", entry.name);
-  EXPECT_EQ(4096, entry.size);
-  base::Time expected_time;
-  EXPECT_TRUE(
-      base::Time::FromString("Thu Apr 24 00:46:52 UTC 2014", &expected_time));
-  EXPECT_EQ(expected_time, entry.last_modified_time);
 }
 
 TEST_F(FileSystemProviderOperationsReadDirectoryTest,
@@ -241,11 +232,7 @@
       "  [\n"
       "    {\n"
       "      \"isDirectory\": false,\n"
-      "      \"name\": \"blue/berries.txt\",\n"
-      "      \"size\": 4096,\n"
-      "      \"modificationTime\": {\n"
-      "        \"value\": \"Thu Apr 24 00:46:52 UTC 2014\"\n"
-      "      }\n"
+      "      \"name\": \"blue/berries.txt\"\n"
       "    }\n"
       "  ],\n"
       "  false,\n"  // has_more
diff --git a/chrome/browser/engagement/site_engagement_service.cc b/chrome/browser/engagement/site_engagement_service.cc
index 95e01c9..9198efc8 100644
--- a/chrome/browser/engagement/site_engagement_service.cc
+++ b/chrome/browser/engagement/site_engagement_service.cc
@@ -19,9 +19,11 @@
 #include "chrome/browser/engagement/site_engagement_eviction_policy.h"
 #include "chrome/browser/engagement/site_engagement_helper.h"
 #include "chrome/browser/engagement/site_engagement_service_factory.h"
+#include "chrome/browser/history/history_service_factory.h"
 #include "chrome/common/chrome_switches.h"
 #include "components/content_settings/core/browser/host_content_settings_map.h"
 #include "components/content_settings/core/common/content_settings_pattern.h"
+#include "components/history/core/browser/history_service.h"
 #include "components/variations/variations_associated_data.h"
 #include "content/public/browser/browser_thread.h"
 #include "url/gurl.h"
@@ -292,25 +294,6 @@
   return base::StartsWith(group_name, "Enabled", base::CompareCase::SENSITIVE);
 }
 
-// static
-void SiteEngagementService::ClearHistoryForURLs(Profile* profile,
-                                                const std::set<GURL>& origins) {
-  HostContentSettingsMap* settings_map =
-      HostContentSettingsMapFactory::GetForProfile(profile);
-
-  for (const GURL& origin_url : origins) {
-    ContentSettingsPattern pattern(
-        ContentSettingsPattern::FromURLNoWildcard(origin_url));
-    if (!pattern.IsValid())
-      continue;
-
-    settings_map->SetWebsiteSetting(pattern, ContentSettingsPattern::Wildcard(),
-                                    CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT,
-                                    std::string(), nullptr);
-  }
-  settings_map->FlushLossyWebsiteSettings();
-}
-
 SiteEngagementService::SiteEngagementService(Profile* profile)
     : SiteEngagementService(profile, make_scoped_ptr(new base::DefaultClock)) {
   content::BrowserThread::PostAfterStartupTask(
@@ -326,6 +309,10 @@
 }
 
 SiteEngagementService::~SiteEngagementService() {
+  history::HistoryService* history = HistoryServiceFactory::GetForProfile(
+      profile_, ServiceAccessType::IMPLICIT_ACCESS);
+  if (history)
+    history->RemoveObserver(this);
 }
 
 void SiteEngagementService::HandleNavigation(const GURL& url,
@@ -357,6 +344,23 @@
   RecordMetrics();
 }
 
+void SiteEngagementService::OnURLsDeleted(
+    history::HistoryService* history_service,
+    bool all_history,
+    bool expired,
+    const history::URLRows& deleted_rows,
+    const std::set<GURL>& favicon_urls) {
+  std::set<GURL> origins;
+  for (const history::URLRow& row : deleted_rows)
+    origins.insert(row.url().GetOrigin());
+
+  history::HistoryService* hs = HistoryServiceFactory::GetForProfile(
+      profile_, ServiceAccessType::EXPLICIT_ACCESS);
+  hs->GetCountsForOrigins(
+      origins, base::Bind(&SiteEngagementService::GetCountsForOriginsComplete,
+                          weak_factory_.GetWeakPtr()));
+}
+
 double SiteEngagementService::GetScore(const GURL& url) {
   HostContentSettingsMap* settings_map =
     HostContentSettingsMapFactory::GetForProfile(profile_);
@@ -400,7 +404,13 @@
 
 SiteEngagementService::SiteEngagementService(Profile* profile,
                                              scoped_ptr<base::Clock> clock)
-    : profile_(profile), clock_(clock.Pass()), weak_factory_(this) {}
+    : profile_(profile), clock_(clock.Pass()), weak_factory_(this) {
+  // May be null in tests.
+  history::HistoryService* history = HistoryServiceFactory::GetForProfile(
+      profile, ServiceAccessType::IMPLICIT_ACCESS);
+  if (history)
+    history->AddObserver(this);
+}
 
 void SiteEngagementService::AddPoints(const GURL& url, double points) {
   HostContentSettingsMap* settings_map =
@@ -537,3 +547,22 @@
 
   return total_origins;
 }
+
+void SiteEngagementService::GetCountsForOriginsComplete(
+    const history::OriginCountMap& origin_counts) {
+  HostContentSettingsMap* settings_map =
+      HostContentSettingsMapFactory::GetForProfile(profile_);
+  for (const auto& origin_to_count : origin_counts) {
+    if (origin_to_count.second != 0)
+      continue;
+
+    ContentSettingsPattern pattern(
+        ContentSettingsPattern::FromURLNoWildcard(origin_to_count.first));
+    if (!pattern.IsValid())
+      continue;
+
+    settings_map->SetWebsiteSetting(pattern, ContentSettingsPattern::Wildcard(),
+                                    CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT,
+                                    std::string(), nullptr);
+  }
+}
diff --git a/chrome/browser/engagement/site_engagement_service.h b/chrome/browser/engagement/site_engagement_service.h
index 85dca08..6489fff 100644
--- a/chrome/browser/engagement/site_engagement_service.h
+++ b/chrome/browser/engagement/site_engagement_service.h
@@ -13,6 +13,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/time/time.h"
 #include "chrome/browser/engagement/site_engagement_metrics.h"
+#include "components/history/core/browser/history_service_observer.h"
 #include "components/keyed_service/core/keyed_service.h"
 #include "ui/base/page_transition_types.h"
 
@@ -129,6 +130,7 @@
 // such as rejecting permission prompts or not responding to notifications, will
 // decrease the site engagement score.
 class SiteEngagementService : public KeyedService,
+                              public history::HistoryServiceObserver,
                               public SiteEngagementScoreProvider {
  public:
   // The name of the site engagement variation field trial.
@@ -139,10 +141,6 @@
   // Returns whether or not the SiteEngagementService is enabled.
   static bool IsEnabled();
 
-  // Clears engagement scores for the given origins.
-  static void ClearHistoryForURLs(Profile* profile,
-                                  const std::set<GURL>& origins);
-
   explicit SiteEngagementService(Profile* profile);
   ~SiteEngagementService() override;
 
@@ -162,6 +160,13 @@
   // tab.
   void HandleMediaPlaying(const GURL& url, bool is_hidden);
 
+  // Overridden from history::HistoryServiceObserver:
+  void OnURLsDeleted(history::HistoryService* history_service,
+                     bool all_history,
+                     bool expired,
+                     const history::URLRows& deleted_rows,
+                     const std::set<GURL>& favicon_urls) override;
+
   // Overridden from SiteEngagementScoreProvider:
   double GetScore(const GURL& url) override;
   double GetTotalEngagementPoints() override;
@@ -173,6 +178,8 @@
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, GetMedianEngagement);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, GetTotalNavigationPoints);
   FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest, GetTotalUserInputPoints);
+  FRIEND_TEST_ALL_PREFIXES(SiteEngagementServiceTest,
+                           CleanupOriginsOnHistoryDeletion);
 
   // Only used in tests.
   SiteEngagementService(Profile* profile, scoped_ptr<base::Clock> clock);
@@ -195,6 +202,9 @@
   int OriginsWithMaxDailyEngagement();
   int OriginsWithMaxEngagement(std::map<GURL, double>& score_map);
 
+  void GetCountsForOriginsComplete(
+      const history::OriginCountMap& origin_counts);
+
   Profile* profile_;
 
   // The clock used to vend times.
diff --git a/chrome/browser/engagement/site_engagement_service_unittest.cc b/chrome/browser/engagement/site_engagement_service_unittest.cc
index e182598..bc5471c 100644
--- a/chrome/browser/engagement/site_engagement_service_unittest.cc
+++ b/chrome/browser/engagement/site_engagement_service_unittest.cc
@@ -3,21 +3,31 @@
 // found in the LICENSE file.
 
 #include "base/command_line.h"
+#include "base/run_loop.h"
 #include "base/test/histogram_tester.h"
 #include "base/test/simple_test_clock.h"
 #include "base/values.h"
+#include "chrome/browser/content_settings/host_content_settings_map_factory.h"
 #include "chrome/browser/engagement/site_engagement_helper.h"
 #include "chrome/browser/engagement/site_engagement_metrics.h"
 #include "chrome/browser/engagement/site_engagement_service.h"
 #include "chrome/browser/engagement/site_engagement_service_factory.h"
+#include "chrome/browser/history/history_service_factory.h"
 #include "chrome/browser/ui/tabs/tab_strip_model.h"
 #include "chrome/common/chrome_switches.h"
 #include "chrome/test/base/browser_with_test_window_test.h"
+#include "components/content_settings/core/browser/content_settings_observer.h"
+#include "components/content_settings/core/browser/host_content_settings_map.h"
+#include "components/history/core/browser/history_database_params.h"
+#include "components/history/core/browser/history_service.h"
+#include "components/history/core/test/test_history_database.h"
 #include "content/public/browser/page_navigator.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace {
 
+base::FilePath g_temp_history_dir;
+
 const int kLessAccumulationsThanNeededToMaxDailyEngagement = 2;
 const int kMoreAccumulationsThanNeededToMaxDailyEngagement = 40;
 const int kMoreAccumulationsThanNeededToMaxTotalEngagement = 200;
@@ -26,6 +36,37 @@
 const int kLessPeriodsThanNeededToDecayMaxScore = 2;
 const int kMorePeriodsThanNeededToDecayMaxScore = 40;
 
+// Waits until a change is observed in site engagement content settings.
+class SiteEngagementChangeWaiter : public content_settings::Observer {
+ public:
+  explicit SiteEngagementChangeWaiter(Profile* profile) : profile_(profile) {
+    HostContentSettingsMapFactory::GetForProfile(profile)->AddObserver(this);
+  }
+  ~SiteEngagementChangeWaiter() override {
+    HostContentSettingsMapFactory::GetForProfile(profile_)
+        ->RemoveObserver(this);
+  }
+
+  // Overridden from content_settings::Observer:
+  void OnContentSettingChanged(const ContentSettingsPattern& primary_pattern,
+                               const ContentSettingsPattern& secondary_pattern,
+                               ContentSettingsType content_type,
+                               std::string resource_identifier) override {
+    if (content_type == CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT)
+      Proceed();
+  }
+
+  void Wait() { run_loop_.Run(); }
+
+ private:
+  void Proceed() { run_loop_.Quit(); }
+
+  Profile* profile_;
+  base::RunLoop run_loop_;
+
+  DISALLOW_COPY_AND_ASSIGN(SiteEngagementChangeWaiter);
+};
+
 base::Time GetReferenceTime() {
   base::Time::Exploded exploded_reference_time;
   exploded_reference_time.year = 2015;
@@ -40,6 +81,14 @@
   return base::Time::FromLocalExploded(exploded_reference_time);
 }
 
+scoped_ptr<KeyedService> BuildTestHistoryService(
+    content::BrowserContext* context) {
+  scoped_ptr<history::HistoryService> service(new history::HistoryService());
+  service->Init(std::string(),
+                history::TestHistoryDatabaseParamsForPath(g_temp_history_dir));
+  return service.Pass();
+}
+
 }  // namespace
 
 class SiteEngagementScoreTest : public testing::Test {
@@ -313,13 +362,16 @@
   TestScoreInitializesAndUpdates(&dict, 1, 2, GetReferenceTime());
 }
 
-
 class SiteEngagementServiceTest : public BrowserWithTestWindowTest {
  public:
   SiteEngagementServiceTest() {}
 
   void SetUp() override {
     BrowserWithTestWindowTest::SetUp();
+    ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
+    g_temp_history_dir = temp_dir_.path();
+    HistoryServiceFactory::GetInstance()->SetTestingFactory(
+        profile(), &BuildTestHistoryService);
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnableSiteEngagementService);
   }
@@ -351,12 +403,15 @@
     CommitPendingLoad(controller);
     EXPECT_EQ(prev_score, service->GetScore(url));
   }
+
+ private:
+  base::ScopedTempDir temp_dir_;
 };
 
 TEST_F(SiteEngagementServiceTest, GetMedianEngagement) {
   SiteEngagementService* service =
       SiteEngagementServiceFactory::GetForProfile(profile());
-  DCHECK(service);
+  ASSERT_TRUE(service);
 
   GURL url1("http://www.google.com/");
   GURL url2("https://www.google.com/");
@@ -423,7 +478,7 @@
 TEST_F(SiteEngagementServiceTest, ScoreIncrementsOnPageRequest) {
   SiteEngagementService* service =
       SiteEngagementServiceFactory::GetForProfile(profile());
-  DCHECK(service);
+  ASSERT_TRUE(service);
 
   GURL url("http://www.google.com/");
   EXPECT_EQ(0, service->GetScore(url));
@@ -441,7 +496,7 @@
 TEST_F(SiteEngagementServiceTest, GetTotalNavigationPoints) {
   SiteEngagementService* service =
       SiteEngagementServiceFactory::GetForProfile(profile());
-  DCHECK(service);
+  ASSERT_TRUE(service);
 
   // The https and http versions of www.google.com should be separate.
   GURL url1("https://www.google.com/");
@@ -478,7 +533,7 @@
 TEST_F(SiteEngagementServiceTest, GetTotalUserInputPoints) {
   SiteEngagementService* service =
       SiteEngagementServiceFactory::GetForProfile(profile());
-  DCHECK(service);
+  ASSERT_TRUE(service);
 
   // The https and http versions of www.google.com should be separate.
   GURL url1("https://www.google.com/");
@@ -768,52 +823,13 @@
   }
 }
 
-// Expect that history can be cleared for given origins.
-TEST_F(SiteEngagementServiceTest, ClearHistoryForURLs) {
-  SiteEngagementService* service =
-      SiteEngagementServiceFactory::GetForProfile(profile());
-
-  GURL url1("https://www.google.com/");
-  GURL url2("http://www.google.com/");
-  GURL url3("http://www.example.com/");
-
-  EXPECT_EQ(0u, service->GetScoreMap().size());
-
-  service->AddPoints(url1, 5.0);
-  EXPECT_EQ(5.0, service->GetScore(url1));
-  service->AddPoints(url2, 5.0);
-  EXPECT_EQ(5.0, service->GetScore(url2));
-  service->AddPoints(url3, 5.0);
-  EXPECT_EQ(5.0, service->GetScore(url3));
-  EXPECT_EQ(3u, service->GetScoreMap().size());
-
-  // Delete 2 of the origins, leaving one left.
-  std::set<GURL> origins_to_clear;
-  origins_to_clear.insert(url1);
-  origins_to_clear.insert(url3);
-
-  SiteEngagementService::ClearHistoryForURLs(profile(), origins_to_clear);
-
-  std::map<GURL, double> score_map = service->GetScoreMap();
-  EXPECT_EQ(1u, score_map.size());
-  EXPECT_DOUBLE_EQ(5.0, score_map[url2]);
-
-  // Ensure nothing bad happens when URLs in the clear list are not in the site
-  // engagement service.
-  SiteEngagementService::ClearHistoryForURLs(profile(), origins_to_clear);
-
-  score_map = service->GetScoreMap();
-  EXPECT_EQ(1u, score_map.size());
-  EXPECT_DOUBLE_EQ(5.0, score_map[url2]);
-}
-
 TEST_F(SiteEngagementServiceTest, NavigationAccumulation) {
   AddTab(browser(), GURL("about:blank"));
   GURL url("https://www.google.com/");
 
   SiteEngagementService* service =
     SiteEngagementServiceFactory::GetForProfile(browser()->profile());
-  DCHECK(service);
+  ASSERT_TRUE(service);
 
   // Only direct navigation should trigger engagement.
   NavigateWithTransitionAndExpectHigherScore(service, url,
@@ -835,3 +851,78 @@
   NavigateWithTransitionAndExpectEqualScore(service, url,
                                             ui::PAGE_TRANSITION_FORM_SUBMIT);
 }
+
+TEST_F(SiteEngagementServiceTest, CleanupOriginsOnHistoryDeletion) {
+  SiteEngagementService* engagement =
+      SiteEngagementServiceFactory::GetForProfile(profile());
+  ASSERT_TRUE(engagement);
+
+  GURL origin1("http://www.google.com/");
+  GURL origin1a("http://www.google.com/search?q=asdf");
+  GURL origin2("https://drive.google.com/");
+  GURL origin2a("https://drive.google.com/somedoc");
+  GURL origin3("http://notdeleted.com/");
+
+  base::Time today = GetReferenceTime();
+  base::Time yesterday = GetReferenceTime() - base::TimeDelta::FromDays(1);
+  base::Time yesterday_afternoon = GetReferenceTime() -
+                                   base::TimeDelta::FromDays(1) +
+                                   base::TimeDelta::FromHours(4);
+
+  history::HistoryService* history = HistoryServiceFactory::GetForProfile(
+      profile(), ServiceAccessType::IMPLICIT_ACCESS);
+
+  history->AddPage(origin1, yesterday_afternoon, history::SOURCE_BROWSED);
+  history->AddPage(origin1a, today, history::SOURCE_BROWSED);
+  engagement->AddPoints(origin1, 5.0);
+
+  history->AddPage(origin2, yesterday_afternoon, history::SOURCE_BROWSED);
+  history->AddPage(origin2a, yesterday_afternoon, history::SOURCE_BROWSED);
+  engagement->AddPoints(origin2, 5.0);
+
+  history->AddPage(origin3, today, history::SOURCE_BROWSED);
+  engagement->AddPoints(origin3, 5.0);
+
+  EXPECT_EQ(5.0, engagement->GetScore(origin1));
+  EXPECT_EQ(5.0, engagement->GetScore(origin2));
+  EXPECT_EQ(5.0, engagement->GetScore(origin3));
+
+  {
+    SiteEngagementChangeWaiter waiter(profile());
+
+    base::CancelableTaskTracker task_tracker;
+    // Expire origin1, origin2 and origin2a.
+    history->ExpireHistoryBetween(std::set<GURL>(), yesterday, today,
+                                  base::Bind(&base::DoNothing), &task_tracker);
+    waiter.Wait();
+
+    // origin2 is cleaned up because all its urls are deleted. origin1a is still
+    // in history, maintaining origin1's score. origin3 is untouched.
+    EXPECT_EQ(5.0, engagement->GetScore(origin1));
+    EXPECT_EQ(0, engagement->GetScore(origin2));
+    EXPECT_EQ(5.0, engagement->GetScore(origin3));
+    EXPECT_EQ(10.0, engagement->GetTotalEngagementPoints());
+  }
+
+  {
+    SiteEngagementChangeWaiter waiter(profile());
+
+    // Expire origin1a.
+    std::vector<history::ExpireHistoryArgs> expire_list;
+    history::ExpireHistoryArgs args;
+    args.urls.insert(origin1a);
+    args.SetTimeRangeForOneDay(today);
+    expire_list.push_back(args);
+
+    base::CancelableTaskTracker task_tracker;
+    history->ExpireHistory(expire_list, base::Bind(&base::DoNothing),
+                           &task_tracker);
+    waiter.Wait();
+
+    // Only origin3 remains.
+    EXPECT_EQ(0, engagement->GetScore(origin1));
+    EXPECT_EQ(0, engagement->GetScore(origin2));
+    EXPECT_EQ(5.0, engagement->GetScore(origin3));
+    EXPECT_EQ(5.0, engagement->GetTotalEngagementPoints());
+  }
+}
diff --git a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
index 2616be14e..bbf6f29 100644
--- a/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
+++ b/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc
@@ -8,6 +8,7 @@
 #include "base/lazy_instance.h"
 #include "base/memory/linked_ptr.h"
 #include "base/thread_task_runner_handle.h"
+#include "chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h"
 #include "chrome/browser/extensions/api/gcd_private/privet_v3_session.h"
 #include "chrome/browser/local_discovery/endpoint_resolver.h"
 #include "chrome/browser/local_discovery/service_discovery_shared_client.h"
@@ -101,12 +102,13 @@
 
   content::BrowserContext* const browser_context_;
 
+  scoped_refptr<PrivetV3ContextGetter> context_getter_;
+
   base::WeakPtrFactory<GcdPrivateAPIImpl> weak_ptr_factory_{this};
 
   DISALLOW_COPY_AND_ASSIGN(GcdPrivateAPIImpl);
 };
 
-
 GcdPrivateAPIImpl::GcdPrivateAPIImpl(content::BrowserContext* context)
     : browser_context_(context) {
   DCHECK(browser_context_);
@@ -145,9 +147,14 @@
                         base::DictionaryValue());
   }
   auto& session_data = sessions_[session_id];
-  session_data.session.reset(
-      new PrivetV3Session(browser_context_->GetRequestContext(),
-                          net::HostPortPair::FromIPEndPoint(endpoint)));
+
+  if (!context_getter_) {
+    context_getter_ = new PrivetV3ContextGetter(
+        browser_context_->GetRequestContext()->GetNetworkTaskRunner());
+  }
+
+  session_data.session.reset(new PrivetV3Session(
+      context_getter_, net::HostPortPair::FromIPEndPoint(endpoint)));
   session_data.session->Init(base::Bind(callback, session_id));
 }
 
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.cc b/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.cc
index 26c425e..3ae118ba 100644
--- a/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.cc
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.cc
@@ -19,11 +19,9 @@
 // Class verifies certificate by its fingerprint received using different
 // channel. It's the only know information about device with self-signed
 // certificate.
-class FingerprintVerifier : public net::CertVerifier {
+class PrivetV3ContextGetter::CertVerifier : public net::CertVerifier {
  public:
-  explicit FingerprintVerifier(
-      const net::SHA256HashValue& certificate_fingerprint)
-      : certificate_fingerprint_(certificate_fingerprint) {}
+  CertVerifier() {}
 
   int Verify(net::X509Certificate* cert,
              const std::string& hostname,
@@ -39,39 +37,35 @@
     verify_result->verified_cert = cert;
     verify_result->cert_status = net::CERT_STATUS_INVALID;
 
+    auto it = fingerprints_.find(hostname);
+    if (it == fingerprints_.end())
+      return net::ERR_CERT_INVALID;
+
     auto fingerprint =
         net::X509Certificate::CalculateFingerprint256(cert->os_cert_handle());
+    return it->second.Equals(fingerprint) ? net::OK : net::ERR_CERT_INVALID;
+  }
 
-    return certificate_fingerprint_.Equals(fingerprint) ? net::OK
-                                                        : net::ERR_CERT_INVALID;
+  void AddPairedHost(const std::string& host,
+                     const net::SHA256HashValue& certificate_fingerprint) {
+    fingerprints_[host] = certificate_fingerprint;
   }
 
  private:
-  net::SHA256HashValue certificate_fingerprint_;
+  std::map<std::string, net::SHA256HashValue> fingerprints_;
 
-  DISALLOW_COPY_AND_ASSIGN(FingerprintVerifier);
+  DISALLOW_COPY_AND_ASSIGN(CertVerifier);
 };
 
 PrivetV3ContextGetter::PrivetV3ContextGetter(
-    const scoped_refptr<base::SingleThreadTaskRunner>& net_task_runner,
-    const net::SHA256HashValue& certificate_fingerprint)
-    : verifier_(new FingerprintVerifier(certificate_fingerprint)),
-      net_task_runner_(net_task_runner) {
+    const scoped_refptr<base::SingleThreadTaskRunner>& net_task_runner)
+    : net_task_runner_(net_task_runner), weak_ptr_factory_(this) {
   CHECK(base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kEnablePrivetV3));
 }
 
 net::URLRequestContext* PrivetV3ContextGetter::GetURLRequestContext() {
-  DCHECK(net_task_runner_->BelongsToCurrentThread());
-  if (!context_) {
-    net::URLRequestContextBuilder builder;
-    builder.set_proxy_service(net::ProxyService::CreateDirect());
-    builder.SetSpdyAndQuicEnabled(false, false);
-    builder.DisableHttpCache();
-    builder.SetCertVerifier(verifier_.Pass());
-    builder.set_user_agent(::GetUserAgent());
-    context_ = builder.Build();
-  }
+  InitOnNetThread();
   return context_.get();
 }
 
@@ -80,6 +74,38 @@
   return net_task_runner_;
 }
 
+void PrivetV3ContextGetter::InitOnNetThread() {
+  DCHECK(net_task_runner_->BelongsToCurrentThread());
+  if (!context_) {
+    net::URLRequestContextBuilder builder;
+    builder.set_proxy_service(net::ProxyService::CreateDirect());
+    builder.SetSpdyAndQuicEnabled(false, false);
+    builder.DisableHttpCache();
+    cert_verifier_ = new CertVerifier();
+    builder.SetCertVerifier(make_scoped_ptr(cert_verifier_));
+    builder.set_user_agent(::GetUserAgent());
+    context_ = builder.Build();
+  }
+}
+
+void PrivetV3ContextGetter::AddPairedHost(
+    const std::string& host,
+    const net::SHA256HashValue& certificate_fingerprint,
+    const base::Closure& callback) {
+  net_task_runner_->PostTaskAndReply(
+      FROM_HERE,
+      base::Bind(&PrivetV3ContextGetter::AddPairedHostOnNetThread,
+                 weak_ptr_factory_.GetWeakPtr(), host, certificate_fingerprint),
+      callback);
+}
+
+void PrivetV3ContextGetter::AddPairedHostOnNetThread(
+    const std::string& host,
+    const net::SHA256HashValue& certificate_fingerprint) {
+  InitOnNetThread();
+  cert_verifier_->AddPairedHost(host, certificate_fingerprint);
+}
+
 PrivetV3ContextGetter::~PrivetV3ContextGetter() {
   DCHECK(net_task_runner_->BelongsToCurrentThread());
 }
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h b/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h
index 5bef50ba8..0dc5d71 100644
--- a/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h
@@ -25,22 +25,36 @@
 class PrivetV3ContextGetter : public net::URLRequestContextGetter {
  public:
   PrivetV3ContextGetter(
-      const scoped_refptr<base::SingleThreadTaskRunner>& net_task_runner,
-      const net::SHA256HashValue& certificate_fingerprint);
+      const scoped_refptr<base::SingleThreadTaskRunner>& net_task_runner);
 
   net::URLRequestContext* GetURLRequestContext() override;
 
   scoped_refptr<base::SingleThreadTaskRunner> GetNetworkTaskRunner()
       const override;
 
+  void AddPairedHost(const std::string& host,
+                     const net::SHA256HashValue& certificate_fingerprint,
+                     const base::Closure& callback);
+
  protected:
   ~PrivetV3ContextGetter() override;
 
  private:
-  scoped_ptr<net::CertVerifier> verifier_;
+  class CertVerifier;
+
+  void InitOnNetThread();
+  void AddPairedHostOnNetThread(
+      const std::string& host,
+      const net::SHA256HashValue& certificate_fingerprint);
+
+  // Owned by context_
+  CertVerifier* cert_verifier_ = nullptr;
   scoped_ptr<net::URLRequestContext> context_;
+
   scoped_refptr<base::SingleThreadTaskRunner> net_task_runner_;
 
+  base::WeakPtrFactory<PrivetV3ContextGetter> weak_ptr_factory_;
+
   DISALLOW_COPY_AND_ASSIGN(PrivetV3ContextGetter);
 };
 
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter_unittest.cc b/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter_unittest.cc
new file mode 100644
index 0000000..a1f04a0
--- /dev/null
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_context_getter_unittest.cc
@@ -0,0 +1,133 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h"
+
+#include "base/command_line.h"
+#include "base/path_service.h"
+#include "base/run_loop.h"
+#include "chrome/common/chrome_switches.h"
+#include "content/public/browser/browser_thread.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/test/embedded_test_server/embedded_test_server.h"
+#include "net/url_request/url_fetcher.h"
+#include "net/url_request/url_fetcher_delegate.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace extensions {
+
+namespace {
+
+using content::BrowserThread;
+using net::EmbeddedTestServer;
+
+class PrivetV3ContextGetterTest : public testing::Test,
+                                  public net::URLFetcherDelegate {
+ protected:
+  PrivetV3ContextGetterTest()
+      : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
+
+  void SetUp() override {
+    base::CommandLine::ForCurrentProcess()->AppendSwitch(
+        switches::kEnablePrivetV3);
+
+    context_getter_ = new extensions::PrivetV3ContextGetter(
+        BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
+  }
+
+  void OnURLFetchComplete(const net::URLFetcher* source) override {
+    done_ = true;
+    status_ = source->GetStatus();
+
+    base::MessageLoop::current()->PostTask(FROM_HERE, quit_);
+  }
+
+  void CreateServer(EmbeddedTestServer::Type type) {
+    server_.reset(new EmbeddedTestServer(type));
+    ASSERT_TRUE(server_->InitializeAndWaitUntilReady());
+
+    base::FilePath test_data_dir;
+    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+    server_->ServeFilesFromDirectory(
+        test_data_dir.Append(FILE_PATH_LITERAL("chrome/test/data")));
+  }
+
+  net::URLRequestStatus::Status Run() {
+    done_ = false;
+    status_ = net::URLRequestStatus();
+
+    base::RunLoop run_loop;
+    quit_ = run_loop.QuitClosure();
+
+    fetcher_ = net::URLFetcher::Create(server_->GetURL("/simple.html"),
+                                       net::URLFetcher::GET, this);
+    fetcher_->SetRequestContext(context_getter_.get());
+    fetcher_->Start();
+
+    run_loop.Run();
+
+    EXPECT_TRUE(done_);
+    return status_.status();
+  }
+
+  void SetFingerprint(const net::SHA256HashValue& fingerprint) {
+    base::RunLoop run_loop;
+    context_getter_->AddPairedHost(server_->host_port_pair().host(),
+                                   fingerprint, run_loop.QuitClosure());
+    run_loop.Run();
+  }
+
+  net::SHA256HashValue GetServerFingerprint() const {
+    return net::X509Certificate::CalculateFingerprint256(
+        server_->GetCertificate()->os_cert_handle());
+  }
+
+ private:
+  bool done_ = false;
+  net::URLRequestStatus status_ = net::URLRequestStatus();
+  content::TestBrowserThreadBundle thread_bundle_;
+  scoped_refptr<extensions::PrivetV3ContextGetter> context_getter_;
+  scoped_ptr<EmbeddedTestServer> server_;
+  scoped_ptr<net::URLFetcher> fetcher_;
+
+  base::Closure quit_;
+};
+
+TEST_F(PrivetV3ContextGetterTest, Http) {
+  CreateServer(EmbeddedTestServer::TYPE_HTTP);
+  EXPECT_EQ(net::URLRequestStatus::SUCCESS, Run());
+}
+
+TEST_F(PrivetV3ContextGetterTest, HttpsUnknownHost) {
+  CreateServer(EmbeddedTestServer::TYPE_HTTPS);
+  EXPECT_EQ(net::URLRequestStatus::CANCELED, Run());
+}
+
+TEST_F(PrivetV3ContextGetterTest, HttpsInvalidFingerprint) {
+  CreateServer(EmbeddedTestServer::TYPE_HTTPS);
+  SetFingerprint(net::SHA256HashValue());
+  EXPECT_EQ(net::URLRequestStatus::CANCELED, Run());
+}
+
+TEST_F(PrivetV3ContextGetterTest, HttpsValidFingerprint) {
+  CreateServer(EmbeddedTestServer::TYPE_HTTPS);
+  SetFingerprint(GetServerFingerprint());
+  EXPECT_EQ(net::URLRequestStatus::SUCCESS, Run());
+}
+
+TEST_F(PrivetV3ContextGetterTest, HttpsFingerprintOverride) {
+  for (size_t i = 0; i < 3; ++i) {
+    CreateServer(EmbeddedTestServer::TYPE_HTTPS);
+    SetFingerprint(net::SHA256HashValue());
+    EXPECT_EQ(net::URLRequestStatus::CANCELED, Run());
+
+    CreateServer(EmbeddedTestServer::TYPE_HTTPS);
+    SetFingerprint(GetServerFingerprint());
+    EXPECT_EQ(net::URLRequestStatus::SUCCESS, Run());
+  }
+}
+
+}  // namespace
+
+}  // namespace extensions
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_session.cc b/chrome/browser/extensions/api/gcd_private/privet_v3_session.cc
index 5564df32..d5d70f09 100644
--- a/chrome/browser/extensions/api/gcd_private/privet_v3_session.cc
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_session.cc
@@ -10,6 +10,7 @@
 #include "base/logging.h"
 #include "base/single_thread_task_runner.h"
 #include "base/thread_task_runner_handle.h"
+#include "chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h"
 #include "chrome/browser/local_discovery/privet_constants.h"
 #include "chrome/browser/local_discovery/privet_http.h"
 #include "chrome/browser/local_discovery/privet_http_impl.h"
@@ -209,12 +210,15 @@
 }
 
 PrivetV3Session::PrivetV3Session(
-    const scoped_refptr<net::URLRequestContextGetter>& context_getter,
+    const scoped_refptr<PrivetV3ContextGetter>& context_getter,
     const net::HostPortPair& host_port)
     : client_(new local_discovery::PrivetHTTPClientImpl("",
                                                         host_port,
                                                         context_getter)),
-      weak_ptr_factory_(this) {}
+      context_getter_(context_getter),
+      weak_ptr_factory_(this) {
+  CHECK(context_getter_);
+}
 
 PrivetV3Session::~PrivetV3Session() {
   Cancel();
@@ -367,9 +371,18 @@
     return callback.Run(Result::STATUS_SESSIONERROR);
   }
 
-  // From now use only https with fixed certificate.
   VLOG(1) << "Expected certificate: " << fingerprint;
-  client_->SwitchToHttps(https_port_, hash);
+  context_getter_->AddPairedHost(
+      client_->GetHost(), hash,
+      base::Bind(&PrivetV3Session::OnPairedHostAddedToContext,
+                 weak_ptr_factory_.GetWeakPtr(), auth_code, callback));
+}
+
+void PrivetV3Session::OnPairedHostAddedToContext(
+    const std::string& auth_code,
+    const ResultCallback& callback) {
+  // Now use https with fixed certificate.
+  client_->SwitchToHttps(https_port_);
 
   std::string auth_code_base64;
   base::Base64Encode(auth_code, &auth_code_base64);
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_session.h b/chrome/browser/extensions/api/gcd_private/privet_v3_session.h
index eef8871..9455ca99 100644
--- a/chrome/browser/extensions/api/gcd_private/privet_v3_session.h
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_session.h
@@ -32,6 +32,8 @@
 
 namespace extensions {
 
+class PrivetV3ContextGetter;
+
 // Manages secure communication between browser and local Privet device.
 class PrivetV3Session {
  private:
@@ -49,9 +51,8 @@
                               const base::DictionaryValue& response)>
       MessageCallback;
 
-  PrivetV3Session(
-      const scoped_refptr<net::URLRequestContextGetter>& context_getter,
-      const net::HostPortPair& host_port);
+  PrivetV3Session(const scoped_refptr<PrivetV3ContextGetter>& context_getter,
+                  const net::HostPortPair& host_port);
   ~PrivetV3Session();
 
   // Initializes session. Queries /privet/info and returns supported pairing
@@ -83,6 +84,8 @@
   void OnPairingConfirmDone(const ResultCallback& callback,
                             Result result,
                             const base::DictionaryValue& response);
+  void OnPairedHostAddedToContext(const std::string& auth_code,
+                                  const ResultCallback& callback);
   void OnAuthenticateDone(const ResultCallback& callback,
                           Result result,
                           const base::DictionaryValue& response);
@@ -102,6 +105,9 @@
   // Creates instances of PrivetURLFetcher.
   scoped_ptr<local_discovery::PrivetHTTPClient> client_;
 
+  // Provides context for client_.
+  scoped_refptr<PrivetV3ContextGetter> context_getter_;
+
   // Current authentication token.
   std::string privet_auth_token_;
 
diff --git a/chrome/browser/extensions/api/gcd_private/privet_v3_session_unittest.cc b/chrome/browser/extensions/api/gcd_private/privet_v3_session_unittest.cc
index ba5ec90..002f6c9 100644
--- a/chrome/browser/extensions/api/gcd_private/privet_v3_session_unittest.cc
+++ b/chrome/browser/extensions/api/gcd_private/privet_v3_session_unittest.cc
@@ -8,6 +8,7 @@
 #include "base/command_line.h"
 #include "base/strings/stringprintf.h"
 #include "base/thread_task_runner_handle.h"
+#include "chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h"
 #include "chrome/browser/local_discovery/privet_http.h"
 #include "chrome/common/chrome_switches.h"
 #include "content/public/test/test_browser_thread_bundle.h"
@@ -73,10 +74,8 @@
     base::CommandLine::ForCurrentProcess()->AppendSwitch(
         switches::kEnablePrivetV3);
 
-    scoped_refptr<net::TestURLRequestContextGetter> context_getter =
-        new net::TestURLRequestContextGetter(
-            content::BrowserThread::GetMessageLoopProxyForThread(
-                content::BrowserThread::IO));
+    scoped_refptr<PrivetV3ContextGetter> context_getter =
+        new PrivetV3ContextGetter(base::ThreadTaskRunnerHandle::Get());
 
     session_.reset(
         new PrivetV3Session(context_getter, net::HostPortPair("host", 80)));
diff --git a/chrome/browser/local_discovery/privet_http.h b/chrome/browser/local_discovery/privet_http.h
index f2d29d8b..607be5be 100644
--- a/chrome/browser/local_discovery/privet_http.h
+++ b/chrome/browser/local_discovery/privet_http.h
@@ -75,9 +75,7 @@
   // fingerprint.
   // For more information on this protocol:
   // https://developers.google.com/cloud-devices/v1/reference/local-api/pairing_start
-  virtual void SwitchToHttps(
-      uint16_t port,
-      const net::SHA256HashValue& certificate_fingerprint) = 0;
+  virtual void SwitchToHttps(uint16_t port) = 0;
 
   virtual bool IsInHttpsMode() const = 0;
 
diff --git a/chrome/browser/local_discovery/privet_http_impl.cc b/chrome/browser/local_discovery/privet_http_impl.cc
index ff43e24..d3861ff 100644
--- a/chrome/browser/local_discovery/privet_http_impl.cc
+++ b/chrome/browser/local_discovery/privet_http_impl.cc
@@ -739,13 +739,9 @@
   }
 }
 
-void PrivetHTTPClientImpl::SwitchToHttps(
-    uint16_t port,
-    const net::SHA256HashValue& certificate_fingerprint) {
+void PrivetHTTPClientImpl::SwitchToHttps(uint16_t port) {
   use_https_ = true;
   host_port_.set_port(port);
-  context_getter_ = new extensions::PrivetV3ContextGetter(
-      context_getter_->GetNetworkTaskRunner(), certificate_fingerprint);
 }
 
 bool PrivetHTTPClientImpl::IsInHttpsMode() const {
diff --git a/chrome/browser/local_discovery/privet_http_impl.h b/chrome/browser/local_discovery/privet_http_impl.h
index 86fd8e7..b0a3a34f 100644
--- a/chrome/browser/local_discovery/privet_http_impl.h
+++ b/chrome/browser/local_discovery/privet_http_impl.h
@@ -253,9 +253,7 @@
       PrivetURLFetcher::Delegate* delegate) override;
   void RefreshPrivetToken(
       const PrivetURLFetcher::TokenCallback& token_callback) override;
-  void SwitchToHttps(
-      uint16_t port,
-      const net::SHA256HashValue& certificate_fingerprint) override;
+  void SwitchToHttps(uint16_t port) override;
   bool IsInHttpsMode() const override;
   std::string GetHost() const override;
 
diff --git a/chrome/browser/local_discovery/privet_http_unittest.cc b/chrome/browser/local_discovery/privet_http_unittest.cc
index 43cfebb5..6afee4f 100644
--- a/chrome/browser/local_discovery/privet_http_unittest.cc
+++ b/chrome/browser/local_discovery/privet_http_unittest.cc
@@ -2,31 +2,23 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "base/bind.h"
-#include "base/command_line.h"
+#include "chrome/browser/local_discovery/privet_http.h"
+
 #include "base/json/json_reader.h"
 #include "base/json/json_writer.h"
-#include "base/location.h"
-#include "base/message_loop/message_loop.h"
 #include "base/run_loop.h"
-#include "base/single_thread_task_runner.h"
-#include "base/thread_task_runner_handle.h"
 #include "chrome/browser/local_discovery/privet_http_impl.h"
-#include "chrome/common/chrome_switches.h"
 #include "content/public/browser/browser_thread.h"
 #include "content/public/test/test_browser_thread_bundle.h"
-#include "net/base/host_port_pair.h"
-#include "net/base/net_errors.h"
 #include "net/test/embedded_test_server/embedded_test_server.h"
 #include "net/url_request/test_url_fetcher_factory.h"
-#include "net/url_request/url_fetcher.h"
 #include "net/url_request/url_request_test_util.h"
-#include "printing/pwg_raster_settings.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 #if defined(ENABLE_PRINT_PREVIEW)
 #include "chrome/browser/local_discovery/pwg_raster_converter.h"
+#include "printing/pwg_raster_settings.h"
 #endif  // ENABLE_PRINT_PREVIEW
 
 namespace local_discovery {
@@ -1040,10 +1032,19 @@
       : thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) {}
 
   void SetUp() override {
-    base::CommandLine::ForCurrentProcess()->AppendSwitch(
-        switches::kEnablePrivetV3);
     context_getter_ = new net::TestURLRequestContextGetter(
         BrowserThread::GetMessageLoopProxyForThread(BrowserThread::IO));
+
+    server_.reset(new EmbeddedTestServer(EmbeddedTestServer::TYPE_HTTP));
+    ASSERT_TRUE(server_->InitializeAndWaitUntilReady());
+
+    base::FilePath test_data_dir;
+    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
+    server_->ServeFilesFromDirectory(
+        test_data_dir.Append(FILE_PATH_LITERAL("chrome/test/data")));
+
+    client_.reset(new PrivetHTTPClientImpl("test", server_->host_port_pair(),
+                                           context_getter_));
   }
 
   void OnError(PrivetURLFetcher* fetcher,
@@ -1073,22 +1074,7 @@
     return true;
   }
 
-  void CreateServer(EmbeddedTestServer::Type type) {
-    server_.reset(new EmbeddedTestServer(type));
-    ASSERT_TRUE(server_->InitializeAndWaitUntilReady());
-
-    base::FilePath test_data_dir;
-    ASSERT_TRUE(PathService::Get(base::DIR_SOURCE_ROOT, &test_data_dir));
-    server_->ServeFilesFromDirectory(
-        test_data_dir.Append(FILE_PATH_LITERAL("chrome/test/data")));
-  }
-
-  void CreateClient() {
-    client_.reset(new PrivetHTTPClientImpl("test", server_->host_port_pair(),
-                                           context_getter_));
-  }
-
-  void Run() {
+  bool Run() {
     success_ = false;
     done_ = false;
 
@@ -1105,6 +1091,7 @@
     run_loop.Run();
 
     EXPECT_TRUE(done_);
+    return success_;
   }
 
   bool success_ = false;
@@ -1119,42 +1106,7 @@
 };
 
 TEST_F(PrivetHttpWithServerTest, HttpServer) {
-  CreateServer(EmbeddedTestServer::TYPE_HTTP);
-
-  CreateClient();
-  Run();
-  EXPECT_TRUE(success_);
-
-  CreateClient();
-  net::SHA256HashValue fingerprint = {};
-  client_->SwitchToHttps(server_->host_port_pair().port(), fingerprint);
-  Run();
-  EXPECT_FALSE(success_);
-  EXPECT_EQ(PrivetURLFetcher::UNKNOWN_ERROR, error_);
-}
-
-TEST_F(PrivetHttpWithServerTest, HttpsServer) {
-  CreateServer(EmbeddedTestServer::TYPE_HTTPS);
-
-  CreateClient();
-  Run();
-  EXPECT_FALSE(success_);
-  EXPECT_EQ(PrivetURLFetcher::UNKNOWN_ERROR, error_);
-
-  CreateClient();
-  net::SHA256HashValue fingerprint =
-      net::X509Certificate::CalculateFingerprint256(
-          server_->GetCertificate()->os_cert_handle());
-  client_->SwitchToHttps(server_->host_port_pair().port(), fingerprint);
-  Run();
-  EXPECT_TRUE(success_);
-
-  CreateClient();
-  fingerprint = {};
-  client_->SwitchToHttps(server_->host_port_pair().port(), fingerprint);
-  Run();
-  EXPECT_FALSE(success_);
-  EXPECT_EQ(PrivetURLFetcher::REQUEST_CANCELED, error_);
+  EXPECT_TRUE(Run());
 }
 
 }  // namespace
diff --git a/chrome/browser/media_galleries/fileapi/iphoto_file_util.cc b/chrome/browser/media_galleries/fileapi/iphoto_file_util.cc
index 317d19fe..112def1 100644
--- a/chrome/browser/media_galleries/fileapi/iphoto_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/iphoto_file_util.cc
@@ -246,9 +246,8 @@
 
   // Root directory. Child is the /Albums dir.
   if (components.size() == 0) {
-    file_list->push_back(DirectoryEntry(kIPhotoAlbumsDir,
-                                        DirectoryEntry::DIRECTORY,
-                                        0, base::Time()));
+    file_list->push_back(
+        DirectoryEntry(kIPhotoAlbumsDir, DirectoryEntry::DIRECTORY));
     return base::File::FILE_OK;
   }
 
@@ -259,8 +258,7 @@
           GetDataProvider()->GetAlbumNames();
       for (std::vector<std::string>::const_iterator it = albums.begin();
            it != albums.end(); it++) {
-        file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
-                                            0, base::Time()));
+        file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY));
       }
       return base::File::FILE_OK;
     } else if (components.size() == 2) {
@@ -271,9 +269,8 @@
 
       // Album dirs contain all photos in them.
       if (GetDataProvider()->HasOriginals(components[1])) {
-        file_list->push_back(DirectoryEntry(kIPhotoOriginalsDir,
-                                            DirectoryEntry::DIRECTORY,
-                                            0, base::Time()));
+        file_list->push_back(
+            DirectoryEntry(kIPhotoOriginalsDir, DirectoryEntry::DIRECTORY));
       }
       std::map<std::string, base::FilePath> locations =
           GetDataProvider()->GetAlbumContents(components[1]);
@@ -283,8 +280,7 @@
         base::File::Info info;
         if (!base::GetFileInfo(it->second, &info))
           return base::File::FILE_ERROR_IO;
-        file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
-                                            info.size, info.last_modified));
+        file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE));
       }
       return base::File::FILE_OK;
     } else if (components.size() == 3 &&
@@ -298,8 +294,7 @@
         base::File::Info info;
         if (!base::GetFileInfo(it->second, &info))
           return base::File::FILE_ERROR_IO;
-        file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
-                                            info.size, info.last_modified));
+        file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE));
       }
       return base::File::FILE_OK;
     }
diff --git a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
index add9982..da4aeb00 100644
--- a/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/itunes_file_util.cc
@@ -195,12 +195,10 @@
     base::File::Info xml_info;
     if (!base::GetFileInfo(GetDataProvider()->library_path(), &xml_info))
       return base::File::FILE_ERROR_IO;
-    file_list->push_back(DirectoryEntry(kITunesLibraryXML,
-                                        DirectoryEntry::FILE,
-                                        xml_info.size, xml_info.last_modified));
-    file_list->push_back(DirectoryEntry(kITunesMediaDir,
-                                        DirectoryEntry::DIRECTORY,
-                                        0, base::Time()));
+    file_list->push_back(
+        DirectoryEntry(kITunesLibraryXML, DirectoryEntry::FILE));
+    file_list->push_back(
+        DirectoryEntry(kITunesMediaDir, DirectoryEntry::DIRECTORY));
     return base::File::FILE_OK;
   }
 
@@ -212,13 +210,11 @@
 
   if (components.size() == 1) {
     if (!GetDataProvider()->auto_add_path().empty()) {
-      file_list->push_back(DirectoryEntry(kITunesAutoAddDir,
-                                          DirectoryEntry::DIRECTORY,
-                                          0, base::Time()));
+      file_list->push_back(
+          DirectoryEntry(kITunesAutoAddDir, DirectoryEntry::DIRECTORY));
     }
-    file_list->push_back(DirectoryEntry(kITunesMusicDir,
-                                        DirectoryEntry::DIRECTORY,
-                                        0, base::Time()));
+    file_list->push_back(
+        DirectoryEntry(kITunesMusicDir, DirectoryEntry::DIRECTORY));
     return base::File::FILE_OK;
   }
 
@@ -235,8 +231,7 @@
         GetDataProvider()->GetArtistNames();
     std::set<ITunesDataProvider::ArtistName>::const_iterator it;
     for (it = artists.begin(); it != artists.end(); ++it)
-      file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
-                                          0, base::Time()));
+      file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY));
     return base::File::FILE_OK;
   }
 
@@ -247,8 +242,7 @@
       return base::File::FILE_ERROR_NOT_FOUND;
     std::set<ITunesDataProvider::AlbumName>::const_iterator it;
     for (it = albums.begin(); it != albums.end(); ++it)
-      file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY,
-                                          0, base::Time()));
+      file_list->push_back(DirectoryEntry(*it, DirectoryEntry::DIRECTORY));
     return base::File::FILE_OK;
   }
 
@@ -262,9 +256,7 @@
       base::File::Info file_info;
       if (media_path_filter()->Match(it->second) &&
           base::GetFileInfo(it->second, &file_info)) {
-        file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE,
-                                            file_info.size,
-                                            file_info.last_modified));
+        file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE));
       }
     }
     return base::File::FILE_OK;
diff --git a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
index 05a3b53..7be547d 100644
--- a/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/native_media_file_util.cc
@@ -579,8 +579,6 @@
     storage::DirectoryEntry entry;
     entry.is_directory = info.IsDirectory();
     entry.name = enum_path.BaseName().value();
-    entry.size = info.GetSize();
-    entry.last_modified_time = info.GetLastModifiedTime();
 
     file_list->push_back(entry);
   }
diff --git a/chrome/browser/media_galleries/fileapi/picasa_file_util.cc b/chrome/browser/media_galleries/fileapi/picasa_file_util.cc
index 65a2c3cf..3417fe5 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_file_util.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_file_util.cc
@@ -207,11 +207,9 @@
     case 0: {
       // Root directory.
       file_list->push_back(
-          DirectoryEntry(kPicasaDirAlbums, DirectoryEntry::DIRECTORY, 0,
-                         base::Time()));
+          DirectoryEntry(kPicasaDirAlbums, DirectoryEntry::DIRECTORY));
       file_list->push_back(
-          DirectoryEntry(kPicasaDirFolders, DirectoryEntry::DIRECTORY, 0,
-                         base::Time()));
+          DirectoryEntry(kPicasaDirFolders, DirectoryEntry::DIRECTORY));
       break;
     }
     case 1:
@@ -223,8 +221,7 @@
         for (AlbumMap::const_iterator it = albums->begin();
              it != albums->end(); ++it) {
           file_list->push_back(
-              DirectoryEntry(it->first, DirectoryEntry::DIRECTORY, 0,
-                             it->second.timestamp));
+              DirectoryEntry(it->first, DirectoryEntry::DIRECTORY));
         }
       } else if (components[0] == kPicasaDirFolders) {
         scoped_ptr<AlbumMap> folders = GetDataProvider()->GetFolders();
@@ -234,8 +231,7 @@
         for (AlbumMap::const_iterator it = folders->begin();
              it != folders->end(); ++it) {
           file_list->push_back(
-              DirectoryEntry(it->first, DirectoryEntry::DIRECTORY, 0,
-                             it->second.timestamp));
+              DirectoryEntry(it->first, DirectoryEntry::DIRECTORY));
         }
       }
       break;
@@ -265,8 +261,7 @@
             continue;
           }
 
-          file_list->push_back(DirectoryEntry(
-              it->first, DirectoryEntry::FILE, info.size, info.last_modified));
+          file_list->push_back(DirectoryEntry(it->first, DirectoryEntry::FILE));
         }
       }
 
diff --git a/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc b/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
index 6b597e48..8b1c080 100644
--- a/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
+++ b/chrome/browser/media_galleries/fileapi/picasa_file_util_unittest.cc
@@ -303,12 +303,6 @@
     for (size_t i = 0; i < contents.size(); ++i) {
       EXPECT_TRUE(contents[i].is_directory);
 
-      // Because the timestamp is written out as a floating point Microsoft
-      // variant time, we only expect it to be accurate to within a second.
-      base::TimeDelta delta = test_folders[i]->folder_info().timestamp -
-                              contents[i].last_modified_time;
-      EXPECT_LT(delta, base::TimeDelta::FromSeconds(1));
-
       FileSystemOperation::FileEntryList folder_contents;
       FileSystemURL folder_url = CreateURL(
           std::string(kPicasaDirFolders) + "/" +
@@ -441,7 +435,6 @@
   for (size_t i = 0; i < contents.size(); ++i) {
     EXPECT_EQ(expected_names[i],
               base::FilePath(contents[i].name).AsUTF8Unsafe());
-    EXPECT_EQ(test_folders[i]->timestamp(), contents[i].last_modified_time);
     EXPECT_TRUE(contents[i].is_directory);
   }
 }
@@ -461,9 +454,6 @@
   EXPECT_TRUE(contents.front().is_directory);
   EXPECT_TRUE(contents.back().is_directory);
 
-  EXPECT_EQ(0, contents.front().size);
-  EXPECT_EQ(0, contents.back().size);
-
   EXPECT_EQ(FILE_PATH_LITERAL("albums"), contents.front().name);
   EXPECT_EQ(FILE_PATH_LITERAL("folders"), contents.back().name);
 }
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
index f627e22..aacc58a 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
+++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.cc
@@ -16,7 +16,6 @@
 #include "base/strings/string_number_conversions.h"
 #include "base/strings/string_split.h"
 #include "base/strings/string_util.h"
-#include "chrome/browser/media_galleries/linux/mtp_device_task_helper.h"
 #include "chrome/browser/media_galleries/linux/mtp_device_task_helper_map_service.h"
 #include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
 #include "net/base/io_buffer.h"
@@ -554,15 +553,8 @@
   if (it != file_info_cache_.end()) {
     // TODO(thestig): This code is repeated in several places. Combine them.
     // e.g. c/b/media_galleries/win/mtp_device_operations_util.cc
-    const storage::DirectoryEntry& cached_file_entry = it->second;
-    base::File::Info info;
-    info.size = cached_file_entry.size;
-    info.is_directory = cached_file_entry.is_directory;
-    info.is_symbolic_link = false;
-    info.last_modified = cached_file_entry.last_modified_time;
-    info.creation_time = base::Time();
-
-    success_callback.Run(info);
+    const MTPDeviceTaskHelper::MTPEntry& cached_file_entry = it->second;
+    success_callback.Run(cached_file_entry.file_info);
     return;
   }
   base::Closure closure =
@@ -1225,7 +1217,7 @@
     const bool exclusive,
     const CreateDirectorySuccessCallback& success_callback,
     const ErrorCallback& error_callback,
-    const storage::AsyncFileUtil::EntryList& /* file_list */,
+    const storage::AsyncFileUtil::EntryList& /* entries */,
     const bool has_more) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
@@ -1245,7 +1237,7 @@
     const uint32 directory_id,
     const DeleteDirectorySuccessCallback& success_callback,
     const ErrorCallback& error_callback,
-    const storage::AsyncFileUtil::EntryList& entries,
+    const MTPDeviceTaskHelper::MTPEntries& entries,
     const bool has_more) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(!has_more);
@@ -1570,7 +1562,7 @@
 void MTPDeviceDelegateImplLinux::OnDidReadDirectory(
     uint32 dir_id,
     const ReadDirectorySuccessCallback& success_callback,
-    const storage::AsyncFileUtil::EntryList& file_list,
+    const MTPDeviceTaskHelper::MTPEntries& mtp_entries,
     bool has_more) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
 
@@ -1586,33 +1578,25 @@
     parent_node = parent_node->parent();
   }
   base::FilePath dir_path = device_path_;
-  for (size_t i = 0; i < dir_path_parts.size(); ++i)
-    dir_path = dir_path.Append(dir_path_parts[i]);
+  for (const auto& dir_path_part : dir_path_parts)
+    dir_path = dir_path.Append(dir_path_part);
 
-  storage::AsyncFileUtil::EntryList normalized_file_list;
-  for (size_t i = 0; i < file_list.size(); ++i) {
-    normalized_file_list.push_back(file_list[i]);
-    storage::DirectoryEntry& entry = normalized_file_list.back();
-
-    // |entry.name| has the file id encoded in it. Decode here.
-    size_t separator_idx = entry.name.find_last_of(',');
-    DCHECK_NE(std::string::npos, separator_idx);
-    std::string file_id_str = entry.name.substr(separator_idx);
-    file_id_str = file_id_str.substr(1);  // Get rid of the comma.
-    uint32 file_id = 0;
-    bool ret = base::StringToUint(file_id_str, &file_id);
-    DCHECK(ret);
-    entry.name = entry.name.substr(0, separator_idx);
+  storage::AsyncFileUtil::EntryList file_list;
+  for (const auto& mtp_entry : mtp_entries) {
+    storage::DirectoryEntry entry;
+    entry.name = mtp_entry.name;
+    entry.is_directory = mtp_entry.file_info.is_directory;
+    file_list.push_back(entry);
 
     // Refresh the in memory tree.
-    dir_node->EnsureChildExists(entry.name, file_id);
+    dir_node->EnsureChildExists(entry.name, mtp_entry.file_id);
     child_nodes_seen_.insert(entry.name);
 
     // Add to |file_info_cache_|.
-    file_info_cache_[dir_path.Append(entry.name)] = entry;
+    file_info_cache_[dir_path.Append(entry.name)] = mtp_entry;
   }
 
-  success_callback.Run(normalized_file_list, has_more);
+  success_callback.Run(file_list, has_more);
   if (has_more)
     return;  // Wait to be called again.
 
@@ -1654,7 +1638,7 @@
 
 void MTPDeviceDelegateImplLinux::OnDidFillFileCache(
     const base::FilePath& path,
-    const storage::AsyncFileUtil::EntryList& /* file_list */,
+    const storage::AsyncFileUtil::EntryList& /* entries */,
     bool has_more) {
   DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
   DCHECK(path.IsParent(pending_tasks_.front().path));
diff --git a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
index fb25cc4..5b5cee18 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_delegate_impl_linux.h
@@ -17,6 +17,7 @@
 #include "base/memory/scoped_ptr.h"
 #include "base/memory/weak_ptr.h"
 #include "chrome/browser/media_galleries/fileapi/mtp_device_async_delegate.h"
+#include "chrome/browser/media_galleries/linux/mtp_device_task_helper.h"
 #include "content/public/browser/browser_thread.h"
 #include "storage/browser/fileapi/async_file_util.h"
 
@@ -62,7 +63,7 @@
   typedef std::map<uint32, MTPFileNode*> FileIdToMTPFileNodeMap;
 
   // Maps file paths to file info.
-  typedef std::map<base::FilePath, storage::DirectoryEntry> FileInfoCache;
+  typedef std::map<base::FilePath, MTPDeviceTaskHelper::MTPEntry> FileInfoCache;
 
   typedef base::Closure DeleteObjectSuccessCallback;
 
@@ -200,7 +201,7 @@
       const bool exclusive,
       const CreateDirectorySuccessCallback& success_callback,
       const ErrorCallback& error_callback,
-      const storage::AsyncFileUtil::EntryList& /* file_list */,
+      const storage::AsyncFileUtil::EntryList& entries,
       const bool has_more);
 
   // Called when ReadDirectory succeeds.
@@ -209,7 +210,7 @@
       const uint32 directory_id,
       const DeleteDirectorySuccessCallback& success_callback,
       const ErrorCallback& error_callback,
-      const storage::AsyncFileUtil::EntryList& entries,
+      const MTPDeviceTaskHelper::MTPEntries& entries,
       const bool has_more);
 
   // Calls DeleteObjectOnUIThread on UI thread.
@@ -348,7 +349,7 @@
   // |has_more| is true if there are more file entries to read.
   void OnDidReadDirectory(uint32 dir_id,
                           const ReadDirectorySuccessCallback& success_callback,
-                          const storage::AsyncFileUtil::EntryList& file_list,
+                          const MTPDeviceTaskHelper::MTPEntries& mtp_entries,
                           bool has_more);
 
   // Called when WriteDataIntoSnapshotFile() succeeds.
@@ -377,9 +378,10 @@
                       const base::File::Info& file_info, int bytes_read);
 
   // Called when FillFileCache() succeeds.
-  void OnDidFillFileCache(const base::FilePath& path,
-                          const storage::AsyncFileUtil::EntryList& file_list,
-                          bool has_more);
+  void OnDidFillFileCache(
+      const base::FilePath& path,
+      const storage::AsyncFileUtil::EntryList& /* entries */,
+      bool has_more);
 
   // Called when FillFileCache() fails.
   void OnFillFileCacheFailed(base::File::Error error);
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc b/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
index 43891ab..c7596ea 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.cc
@@ -7,8 +7,6 @@
 #include <algorithm>
 
 #include "base/logging.h"
-#include "base/numerics/safe_conversions.h"
-#include "base/strings/string_number_conversions.h"
 #include "chrome/browser/media_galleries/linux/mtp_device_object_enumerator.h"
 #include "chrome/browser/media_galleries/linux/mtp_read_file_worker.h"
 #include "chrome/browser/media_galleries/linux/snapshot_file_details.h"
@@ -168,6 +166,8 @@
                  error_callback));
 }
 
+MTPDeviceTaskHelper::MTPEntry::MTPEntry() : file_id(0) {}
+
 // TODO(yawano) storage_name is not used, delete it.
 void MTPDeviceTaskHelper::CopyFileFromLocal(
     const std::string& storage_name,
@@ -260,20 +260,17 @@
   if (error)
     return HandleDeviceError(error_callback, base::File::FILE_ERROR_FAILED);
 
-  storage::AsyncFileUtil::EntryList entries;
+  MTPEntries entries;
   base::FilePath current;
   MTPDeviceObjectEnumerator file_enum(file_entries);
   while (!(current = file_enum.Next()).empty()) {
-    storage::DirectoryEntry entry;
+    MTPEntry entry;
     entry.name = storage::VirtualPath::BaseName(current).value();
-    uint32 file_id = 0;
-    bool ret = file_enum.GetEntryId(&file_id);
+    bool ret = file_enum.GetEntryId(&entry.file_id);
     DCHECK(ret);
-    entry.name.push_back(',');
-    entry.name += base::UintToString(file_id);
-    entry.is_directory = file_enum.IsDirectory();
-    entry.size = file_enum.Size();
-    entry.last_modified_time = file_enum.LastModifiedTime();
+    entry.file_info.is_directory = file_enum.IsDirectory();
+    entry.file_info.size = file_enum.Size();
+    entry.file_info.last_modified = file_enum.LastModifiedTime();
     entries.push_back(entry);
   }
   content::BrowserThread::PostTask(
diff --git a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
index c21c8527..5af1487 100644
--- a/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
+++ b/chrome/browser/media_galleries/linux/mtp_device_task_helper.h
@@ -26,6 +26,16 @@
 // MTP device storage.
 class MTPDeviceTaskHelper {
  public:
+  struct MTPEntry {
+    MTPEntry();
+
+    uint32_t file_id;
+    std::string name;
+    base::File::Info file_info;
+  };
+
+  typedef std::vector<MTPEntry> MTPEntries;
+
   typedef base::Callback<void(bool succeeded)> OpenStorageCallback;
 
   typedef MTPDeviceAsyncDelegate::GetFileInfoSuccessCallback
@@ -33,10 +43,8 @@
 
   typedef base::Closure CreateDirectorySuccessCallback;
 
-  // NOTE: The file names in the entry list have their file id appended at the
-  // end. e.g. foo.jpg with file id 45 becomes foo.jpg,45.
-  typedef base::Callback<void(const storage::AsyncFileUtil::EntryList& entries,
-                              bool has_more)> ReadDirectorySuccessCallback;
+  typedef base::Callback<void(const MTPEntries& entries, bool has_more)>
+      ReadDirectorySuccessCallback;
 
   typedef base::Closure RenameObjectSuccessCallback;
 
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
index 89e5108..743866b 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac.mm
@@ -467,8 +467,6 @@
       storage::DirectoryEntry entry;
       entry.name = relative_path.value();
       entry.is_directory = info.is_directory;
-      entry.size = info.size;
-      entry.last_modified_time = info.last_modified;
       entry_list.push_back(entry);
     }
 
diff --git a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
index 7c8deb47..e418d65 100644
--- a/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
+++ b/chrome/browser/media_galleries/mac/mtp_device_delegate_impl_mac_unittest.mm
@@ -400,11 +400,9 @@
   EXPECT_EQ(base::File::FILE_OK, ReadDir(base::FilePath(kDevicePath)));
 
   ASSERT_EQ(2U, file_list_.size());
-  EXPECT_EQ(time1, file_list_[0].last_modified_time);
   EXPECT_FALSE(file_list_[0].is_directory);
   EXPECT_EQ("name1", file_list_[0].name);
 
-  EXPECT_EQ(time1, file_list_[1].last_modified_time);
   EXPECT_FALSE(file_list_[1].is_directory);
   EXPECT_EQ("name2", file_list_[1].name);
 }
@@ -433,11 +431,9 @@
   ASSERT_EQ(4U, file_list_.size());
   EXPECT_EQ("dir1", file_list_[0].name);
   EXPECT_EQ("dir2", file_list_[1].name);
-  EXPECT_EQ(time1, file_list_[2].last_modified_time);
   EXPECT_FALSE(file_list_[2].is_directory);
   EXPECT_EQ("name1", file_list_[2].name);
 
-  EXPECT_EQ(time1, file_list_[3].last_modified_time);
   EXPECT_FALSE(file_list_[3].is_directory);
   EXPECT_EQ("name2", file_list_[3].name);
 }
diff --git a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
index 8dbca7f6..b21cf6d3 100644
--- a/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
+++ b/chrome/browser/media_galleries/win/mtp_device_delegate_impl_win.cc
@@ -203,8 +203,6 @@
     storage::DirectoryEntry entry;
     entry.is_directory = file_enum->IsDirectory();
     entry.name = storage::VirtualPath::BaseName(current).value();
-    entry.size = file_enum->Size();
-    entry.last_modified_time = file_enum->LastModifiedTime();
     entries->push_back(entry);
   }
   return error;
diff --git a/chrome/browser/mojo_runner_state.cc b/chrome/browser/mojo_runner_state.cc
deleted file mode 100644
index 4d9461fa..0000000
--- a/chrome/browser/mojo_runner_state.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/mojo_runner_state.h"
-
-#include "components/mus/public/interfaces/window_manager.mojom.h"
-#include "mojo/application/public/cpp/application_delegate.h"
-#include "mojo/application/public/cpp/application_impl.h"
-#include "mojo/converters/network/network_type_converters.h"
-#include "mojo/runner/child/runner_connection.h"
-#include "ui/views/mus/window_manager_connection.h"
-
-class ChromeApplicationDelegate : public mojo::ApplicationDelegate {
- public:
-  ChromeApplicationDelegate() {}
-  ~ChromeApplicationDelegate() override {}
-
- private:
-  void Initialize(mojo::ApplicationImpl* application) override {
-    mus::mojom::WindowManagerPtr window_manager;
-    application->ConnectToService(
-        mojo::URLRequest::From(std::string("mojo:example_wm")),
-        &window_manager);
-    views::WindowManagerConnection::Create(window_manager.Pass(), application);
-  }
-  bool ConfigureIncomingConnection(
-      mojo::ApplicationConnection* connection) override {
-    return false;
-  }
-
-  DISALLOW_COPY_AND_ASSIGN(ChromeApplicationDelegate);
-};
-
-MojoRunnerState::MojoRunnerState() {}
-MojoRunnerState::~MojoRunnerState() {}
-
-void MojoRunnerState::WaitForConnection() {
-  mojo::InterfaceRequest<mojo::Application> application_request;
-  runner_connection_.reset(
-      mojo::runner::RunnerConnection::ConnectToRunner(&application_request));
-  application_delegate_.reset(new ChromeApplicationDelegate);
-  application_impl_.reset(new mojo::ApplicationImpl(
-      application_delegate_.get(), application_request.Pass()));
-  application_impl_->WaitForInitialize();
-}
diff --git a/chrome/browser/mojo_runner_state.h b/chrome/browser/mojo_runner_state.h
deleted file mode 100644
index 09eaa62c..0000000
--- a/chrome/browser/mojo_runner_state.h
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MOJO_RUNNER_STATE_H_
-#define CHROME_BROWSER_MOJO_RUNNER_STATE_H_
-
-#include "base/macros.h"
-#include "base/memory/scoped_ptr.h"
-
-namespace mojo {
-class ApplicationImpl;
-namespace runner {
-class RunnerConnection;
-}
-}
-
-class ChromeApplicationDelegate;
-
-// Encapsulates a connection to a spawning mojo_runner/shell.
-// TODO(beng): figure out if/how this should be exposed to other layers
-//             of code in Chrome.
-class MojoRunnerState {
- public:
-  MojoRunnerState();
-  ~MojoRunnerState();
-
-  // Blocks the calling thread until a connection to the spawning mojo_runner
-  // is established, an Application request from it is bound, and the
-  // Initialize() method on that application is called.
-  void WaitForConnection();
-
- private:
-  scoped_ptr<mojo::runner::RunnerConnection> runner_connection_;
-  scoped_ptr<mojo::ApplicationImpl> application_impl_;
-  scoped_ptr<ChromeApplicationDelegate> application_delegate_;
-
-  DISALLOW_COPY_AND_ASSIGN(MojoRunnerState);
-};
-
-#endif  // CHROME_BROWSER_MOJO_RUNNER_STATE_H_
diff --git a/chrome/browser/mojo_runner_util.cc b/chrome/browser/mojo_runner_util.cc
deleted file mode 100644
index ec6560e..0000000
--- a/chrome/browser/mojo_runner_util.cc
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/browser/mojo_runner_util.h"
-
-#include "base/command_line.h"
-
-bool IsRunningInMojoRunner() {
-  return base::CommandLine::ForCurrentProcess()->HasSwitch(
-      "mojo-platform-channel-handle");
-}
diff --git a/chrome/browser/mojo_runner_util.h b/chrome/browser/mojo_runner_util.h
deleted file mode 100644
index ff1a2e9..0000000
--- a/chrome/browser/mojo_runner_util.h
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2015 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_MOJO_RUNNER_UTIL_H_
-#define CHROME_BROWSER_MOJO_RUNNER_UTIL_H_
-
-// Returns true if the Chrome browser process was launched from the mojo_runner.
-bool IsRunningInMojoRunner();
-
-#endif  // CHROME_BROWSER_MOJO_RUNNER_UTIL_H_
diff --git a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
index f85ea309..d56a7ec 100644
--- a/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
+++ b/chrome/browser/page_load_metrics/page_load_metrics_browsertest.cc
@@ -24,9 +24,9 @@
 IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NoNavigation) {
   ASSERT_TRUE(test_server()->Start());
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0);
 }
 
 IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, NewPage) {
@@ -37,9 +37,9 @@
   ui_test_utils::NavigateToURL(browser(),
                                test_server()->GetURL("/title2.html"));
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 1);
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 1);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
 }
 
 IN_PROC_BROWSER_TEST_F(MetricsWebContentsObserverBrowserTest, AnchorLink) {
@@ -52,9 +52,9 @@
   ui_test_utils::NavigateToURL(browser(),
                                test_server()->GetURL("/title2.html"));
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 1);
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 1);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
 }
 
 }  // namespace page_load_metrics
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index 54f16d1..d4cdb3c 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -299,6 +299,7 @@
       "//ui/keyboard:resources",
       "//ui/wm",
     ]
+    defines += [ "MOJO_SHELL_CLIENT" ]
     if (!is_chromeos) {
       sources += rebase_path(gypi_values.chrome_browser_ui_aura_non_chromeos,
                              ".",
diff --git a/chrome/browser/ui/views/frame/browser_view.cc b/chrome/browser/ui/views/frame/browser_view.cc
index 5be19270..91265cb6 100644
--- a/chrome/browser/ui/views/frame/browser_view.cc
+++ b/chrome/browser/ui/views/frame/browser_view.cc
@@ -26,7 +26,6 @@
 #include "chrome/browser/extensions/extension_util.h"
 #include "chrome/browser/extensions/tab_helper.h"
 #include "chrome/browser/infobars/infobar_service.h"
-#include "chrome/browser/mojo_runner_util.h"
 #include "chrome/browser/native_window_notification_source.h"
 #include "chrome/browser/profiles/avatar_menu.h"
 #include "chrome/browser/profiles/profile.h"
@@ -171,6 +170,10 @@
 #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
 #endif
 
+#if defined(MOJO_SHELL_CLIENT)
+#include "content/public/common/mojo_shell_connection.h"
+#endif
+
 using base::TimeDelta;
 using base::UserMetricsAction;
 using content::NativeWebKeyboardEvent;
@@ -2389,8 +2392,10 @@
   // TODO(beng): for some reason GetFocusManager() returns null in this case,
   //             investigate, but for now just disable accelerators in this
   //             mode.
-  if (IsRunningInMojoRunner())
+#if defined(MOJO_SHELL_CLIENT)
+  if (content::MojoShellConnection::Get())
     return;
+#endif
 
   views::FocusManager* focus_manager = GetFocusManager();
   DCHECK(focus_manager);
diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_auralinux.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_auralinux.cc
index 339fb3a..8c8211f3 100644
--- a/chrome/browser/ui/views/frame/native_browser_frame_factory_auralinux.cc
+++ b/chrome/browser/ui/views/frame/native_browser_frame_factory_auralinux.cc
@@ -4,19 +4,19 @@
 
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 
-#include "chrome/browser/mojo_runner_util.h"
 #include "chrome/browser/ui/views/frame/browser_frame_ash.h"
 #include "chrome/browser/ui/views/frame/desktop_browser_frame_auralinux.h"
 
-#if defined(MOJO_RUNNER_CLIENT)
+#if defined(MOJO_SHELL_CLIENT)
 #include "chrome/browser/ui/views/frame/browser_frame_mus.h"
+#include "content/public/common/mojo_shell_connection.h"
 #endif
 
 NativeBrowserFrame* NativeBrowserFrameFactory::Create(
     BrowserFrame* browser_frame,
     BrowserView* browser_view) {
-#if defined(MOJO_RUNNER_CLIENT)
-  if (IsRunningInMojoRunner())
+#if defined(MOJO_SHELL_CLIENT)
+  if (content::MojoShellConnection::Get())
     return new BrowserFrameMus(browser_frame, browser_view);
 #endif
 
diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_aurawin.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_aurawin.cc
index efb82a5..0b01bf0 100644
--- a/chrome/browser/ui/views/frame/native_browser_frame_factory_aurawin.cc
+++ b/chrome/browser/ui/views/frame/native_browser_frame_factory_aurawin.cc
@@ -5,19 +5,19 @@
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 
 #include "ash/shell.h"
-#include "chrome/browser/mojo_runner_util.h"
 #include "chrome/browser/ui/views/frame/browser_frame_ashwin.h"
 #include "chrome/browser/ui/views/frame/desktop_browser_frame_aura.h"
 
-#if defined(MOJO_RUNNER_CLIENT)
+#if defined(MOJO_SHELL_CLIENT)
 #include "chrome/browser/ui/views/frame/browser_frame_mus.h"
+#include "content/public/common/mojo_shell_connection.h"
 #endif
 
 NativeBrowserFrame* NativeBrowserFrameFactory::Create(
     BrowserFrame* browser_frame,
     BrowserView* browser_view) {
-#if defined(MOJO_RUNNER_CLIENT)
-  if (IsRunningInMojoRunner())
+#if defined(MOJO_SHELL_CLIENT)
+  if (content::MojoShellConnection::Get())
     return new BrowserFrameMus(browser_frame, browser_view);
 #endif
 
diff --git a/chrome/browser/ui/views/frame/native_browser_frame_factory_chromeos.cc b/chrome/browser/ui/views/frame/native_browser_frame_factory_chromeos.cc
index 1f42d7e..dba92a0 100644
--- a/chrome/browser/ui/views/frame/native_browser_frame_factory_chromeos.cc
+++ b/chrome/browser/ui/views/frame/native_browser_frame_factory_chromeos.cc
@@ -4,18 +4,18 @@
 
 #include "chrome/browser/ui/views/frame/native_browser_frame_factory.h"
 
-#include "chrome/browser/mojo_runner_util.h"
 #include "chrome/browser/ui/views/frame/browser_frame_ash.h"
 
-#if defined(MOJO_RUNNER_CLIENT)
+#if defined(MOJO_SHELL_CLIENT)
 #include "chrome/browser/ui/views/frame/browser_frame_mus.h"
+#include "content/public/common/mojo_shell_connection.h"
 #endif
 
 NativeBrowserFrame* NativeBrowserFrameFactory::Create(
     BrowserFrame* browser_frame,
     BrowserView* browser_view) {
-#if defined(MOJO_RUNNER_CLIENT)
-  if (IsRunningInMojoRunner())
+#if defined(MOJO_SHELL_CLIENT)
+  if (content::MojoShellConnection::Get())
     return new BrowserFrameMus(browser_frame, browser_view);
 #endif
   return new BrowserFrameAsh(browser_frame, browser_view);
diff --git a/chrome/browser/ui/webui/history_ui.cc b/chrome/browser/ui/webui/history_ui.cc
index d910fd5..36cc8c2 100644
--- a/chrome/browser/ui/webui/history_ui.cc
+++ b/chrome/browser/ui/webui/history_ui.cc
@@ -685,10 +685,8 @@
   }
 #endif
 
-  for (const history::ExpireHistoryArgs& expire_entry : expire_list) {
+  for (const history::ExpireHistoryArgs& expire_entry : expire_list)
     AppBannerSettingsHelper::ClearHistoryForURLs(profile, expire_entry.urls);
-    SiteEngagementService::ClearHistoryForURLs(profile, expire_entry.urls);
-  }
 }
 
 void BrowsingHistoryHandler::HandleClearBrowsingData(
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index d126685..54098fd 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -671,8 +671,6 @@
       'browser/memory_details_win.cc',
       'browser/mod_pagespeed/mod_pagespeed_metrics.cc',
       'browser/mod_pagespeed/mod_pagespeed_metrics.h',
-      'browser/mojo_runner_util.cc',
-      'browser/mojo_runner_util.h',
       'browser/native_window_notification_source.h',
       'browser/net/predictor_tab_helper.cc',
       'browser/net/predictor_tab_helper.h',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi
index dc77a37..2d5b7c1 100644
--- a/chrome/chrome_tests_unit.gypi
+++ b/chrome/chrome_tests_unit.gypi
@@ -624,6 +624,7 @@
       'browser/extensions/api/file_handlers/api_file_handler_util_unittest.cc',
       'browser/extensions/api/file_handlers/mime_util_unittest.cc',
       'browser/extensions/api/file_system/file_system_api_unittest.cc',
+      'browser/extensions/api/gcd_private/privet_v3_context_getter_unittest.cc',
       'browser/extensions/api/gcd_private/privet_v3_session_unittest.cc',
       'browser/extensions/api/identity/extension_token_key_unittest.cc',
       'browser/extensions/api/identity/gaia_web_auth_flow_unittest.cc',
diff --git a/chrome/common/extensions/api/file_system_provider.idl b/chrome/common/extensions/api/file_system_provider.idl
index 1908c18..b6ab86d 100644
--- a/chrome/common/extensions/api/file_system_provider.idl
+++ b/chrome/common/extensions/api/file_system_provider.idl
@@ -61,11 +61,12 @@
     // it must be empty.
     DOMString name;
 
-    // File size in bytes.
-    double size;
+    // File size in bytes. Required for <code>OnGetMetadataRequested</code>.
+    double? size;
 
-    // The last modified time of this entry.
-    [instanceOf=Date] object modificationTime;
+    // The last modified time of this entry. Required for
+    // <code>OnGetMetadataRequested</code>.
+    [instanceOf=Date] object? modificationTime;
 
     // Mime type for the entry.
     DOMString? mimeType;
diff --git a/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js b/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js
index 46f3d744..b43a9d7 100644
--- a/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js
+++ b/chrome/renderer/resources/extensions/file_system_provider_custom_bindings.js
@@ -60,12 +60,14 @@
   var result = {
     isDirectory: metadata.isDirectory,
     name: metadata.name,
-    size: metadata.size,
-    modificationTime: annotateDate(metadata.modificationTime)
   };
-  if ('mimeType' in metadata)
+  if (metadata.size !== undefined)
+    result.size = metadata.size;
+  if (metadata.modificationTime !== undefined)
+    result.modificationTime = annotateDate(metadata.modificationTime);
+  if (metadata.mimeType !== undefined)
     result.mimeType = metadata.mimeType;
-  if ('thumbnail' in metadata)
+  if (metadata.thumbnail !== undefined)
     result.thumbnail = metadata.thumbnail;
   return result;
 }
@@ -102,6 +104,13 @@
       var options = args[0];
       var onSuccessCallback = function(metadata) {
         var error;
+        // TODO(mtomasz): Remove the following two fields once crbug.com/413161
+        // is landed.
+        if (options.size !== undefined)
+          error = 'Size is required for this event.';
+        if (options.modificationTime !== undefined)
+          error = 'Last modified time is required for this event.';
+
         // It is invalid to return a thumbnail when it's not requested. The
         // restriction is added in order to avoid fetching the thumbnail while
         // it's not needed.
diff --git a/chrome/test/data/chromeproxy/OWNERS b/chrome/test/data/chromeproxy/OWNERS
new file mode 100644
index 0000000..4e641323
--- /dev/null
+++ b/chrome/test/data/chromeproxy/OWNERS
@@ -0,0 +1,3 @@
+bustamante@chromium.org
+kundaji@chromium.org
+bengr@chromium.org
diff --git a/chrome/test/data/chromeproxy/README b/chrome/test/data/chromeproxy/README
new file mode 100644
index 0000000..fffa42c
--- /dev/null
+++ b/chrome/test/data/chromeproxy/README
@@ -0,0 +1,4 @@
+This directory contains test resources for Chrome Proxy tests.
+
+/extension/... is the "Data Saver (Beta)" extension pulled from
+the Chrome Web Store.
diff --git a/chrome/test/data/chromeproxy/extension/_locales/am/messages.json b/chrome/test/data/chromeproxy/extension/_locales/am/messages.json
new file mode 100644
index 0000000..bbb3784
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/am/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "ከታመቀ በኋላ፦ \u003Cb>$1 ባይት\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "ከእጨቃ በኋላ፦ \u003Cb>$1 ጊባ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "ከእጨቃ በኋላ፦ \u003Cb>$1 ኪባ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "ከእጨቃ በኋላ፦ \u003Cb>$1 ሜባ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "የውሂብ አስቀማጭን አጥፋ"
+   },
+   "enabledatasaverlabel": {
+      "message": "የውሂብ አስቀማጭን አብራ"
+   },
+   "extdesc": {
+      "message": "የሚጎበኙዋቸውን ገጾች ለማላቅ Google አገልጋዮችን በመጠቀም የውሂብ አጠቃቀምን ይቀንሱ።"
+   },
+   "extname": {
+      "message": "የውሂብ አስቀማጭ"
+   },
+   "extnamebeta": {
+      "message": "ውሂብ ቆጣቢ (ቅድመ-ይሁንታ)"
+   },
+   "helpandfeedback": {
+      "message": "እገዛ እና ግብረመልስ"
+   },
+   "incognitomessage": {
+      "message": "ይህ ቅጥያ ማንነት በማያሳውቅ ሁነታ ላይ መጠቀም አይቻልም።"
+   },
+   "info1": {
+      "message": "Google የጎበኟቸውን ገጾች እንዲያመቻች በመጠቀም በውሂብ ላይ ያነሰ ያጥፉ።"
+   },
+   "info2": {
+      "message": "በHTTPS ወይም ማንነት በማያሳውቅ ሁነታ የተደረሰባቸው ገጾች በGoogle አይመቻቹም ወይም አይታዩም።"
+   },
+   "learnmorelinktext": {
+      "message": "ተጨማሪ ለመረዳት"
+   },
+   "originalsizeformat": {
+      "message": "የመጀመሪያ መጠን፦ \u003Cb>$1 ባይት\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "የመጀመሪያ መጠን፦ \u003Cb>$1 ጊባ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "የመጀመሪያ መጠን፦ \u003Cb>$1 ኪባ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "የመጀመሪያ መጠን፦ \u003Cb>$1 ሜባ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "የውሂብ አጠቃቀም ቀንስ"
+   },
+   "reportissue": {
+      "message": "ችግር ሪፖርት ያድርጉ"
+   },
+   "versionnotcompatible": {
+      "message": "ይህ የChrome ስሪት ከዚህ ቅጥያ ጋር ተኳዃኝ አይደለም። እባክዎ Chromeን ወደ ቅርብ ጊዜው ስሪት ያዘምኑት። M41 Beta የመጀመሪያው የሚደገፍ ስሪት ነው።"
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ar/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ar/messages.json
new file mode 100644
index 0000000..a617d8f0
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ar/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "بعد الضغط: \u003Cb>$1 بايت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "بعد الضغط: \u003Cb>$1 غيغابايت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "بعد الضغط: \u003Cb>$1 كيلوبايت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "بعد الضغط: \u003Cb>$1 ميغابايت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "إيقاف توفير البيانات"
+   },
+   "enabledatasaverlabel": {
+      "message": "تشغيل توفير البيانات"
+   },
+   "extdesc": {
+      "message": "تقليل استخدام البيانات باستخدام خوادم Google لتحسين الصفحات التي تزورها."
+   },
+   "extname": {
+      "message": "توفير البيانات"
+   },
+   "extnamebeta": {
+      "message": "توفير البيانات (تجريبي)"
+   },
+   "helpandfeedback": {
+      "message": "المساعدة والتعليقات"
+   },
+   "incognitomessage": {
+      "message": "لا يمكن استخدام هذه الإضافة في وضع التصفح المتخفي."
+   },
+   "info1": {
+      "message": "يمكنك تخفيض الاستهلاك المتعلق بالبيانات من خلال استخدام Google لتحسين الصفحات التي تزورها."
+   },
+   "info2": {
+      "message": "لن يتم تحسين الصفحات التي يتم الدخول إليها باستخدام HTTPS أو التصفح المتخفي، ولن يكتشفها متصفح Google."
+   },
+   "learnmorelinktext": {
+      "message": "مزيد من المعلومات"
+   },
+   "originalsizeformat": {
+      "message": "الحجم الأصلي: \u003Cb>$1 بايت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "الحجم الأصلي: \u003Cb>$1 غيغابايت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "الحجم الأصلي: \u003Cb>$1 كيلوبايت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "الحجم الأصلي: \u003Cb>$1 ميغابايت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "تقليل استخدام البيانات"
+   },
+   "reportissue": {
+      "message": "الإبلاغ عن مشكلة"
+   },
+   "versionnotcompatible": {
+      "message": "لا يتوافق هذا الإصدار من Chrome مع هذه الإضافة. يُرجى تحديث Chrome لأحدث إصدار. الإصدار التجريبي M41 هو الإصدار المدعوم الأول."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/bg/messages.json b/chrome/test/data/chromeproxy/extension/_locales/bg/messages.json
new file mode 100644
index 0000000..a5fc8a30
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/bg/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "След компресиране: \u003Cb>$1 байта\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "След компресиране: \u003Cb>$1 ГБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "След компресиране: \u003Cb>$1 КБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "След компресиране: \u003Cb>$1 МБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Изключване на „Икономия на данни“"
+   },
+   "enabledatasaverlabel": {
+      "message": "Включване на „Икономия на данни“"
+   },
+   "extdesc": {
+      "message": "Намалява преноса на данни, като използва сървърите на Google за оптимизиране на посещаваните от вас страници."
+   },
+   "extname": {
+      "message": "Икономия на данни"
+   },
+   "extnamebeta": {
+      "message": "Икономия на данни (бета)"
+   },
+   "helpandfeedback": {
+      "message": "Помощ и отзиви"
+   },
+   "incognitomessage": {
+      "message": "Това разширение не може да се използва в режим „инкогнито“."
+   },
+   "info1": {
+      "message": "Намалете разходите за данни, като използвате Google за оптимизиране на посещаваните страници."
+   },
+   "info2": {
+      "message": "Не оптимизираме, нито виждаме страниците, отваряни с HTTPS или в режим „инкогнито“."
+   },
+   "learnmorelinktext": {
+      "message": "Научете повече"
+   },
+   "originalsizeformat": {
+      "message": "Първоначален размер: \u003Cb>$1 байта\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Първоначален размер: \u003Cb>$1 ГБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Първоначален размер: \u003Cb>$1 КБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Първоначален размер: \u003Cb>$1 МБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Намаляване на използването на данни"
+   },
+   "reportissue": {
+      "message": "Подаване на сигнал за проблем"
+   },
+   "versionnotcompatible": {
+      "message": "Тази версия на Chrome не е съвместима с разширението. Моля, актуализирайте браузъра до последната версия. Първата поддържана е M41 бета."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/bn/messages.json b/chrome/test/data/chromeproxy/extension/_locales/bn/messages.json
new file mode 100644
index 0000000..484bc8a
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/bn/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "সংকোচনের পরে: \u003Cb>$1 বাইটস\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "সংকোচন পরে: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "সংকোচন পরে: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "সংকোচন পরে: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "ডেটা সেভার বন্ধ করুন"
+   },
+   "enabledatasaverlabel": {
+      "message": "ডেটা সেভার চালু করুন"
+   },
+   "extdesc": {
+      "message": "আপনার দর্শিত পৃষ্ঠাগুলি অপ্টিমাইজ করতে Google সার্ভারগুলি ব্যবহার করে আপনার ডেটার ব্যবহার কম করুন৷"
+   },
+   "extname": {
+      "message": "ডেটা সেভার"
+   },
+   "extnamebeta": {
+      "message": "ডেটা সেভার (বিটা)"
+   },
+   "helpandfeedback": {
+      "message": "সহায়তা এবং প্রতিক্রিয়া"
+   },
+   "incognitomessage": {
+      "message": "ছদ্মবেশি মোডে এই এক্সটেনশানটি ব্যবহার করা যাবে না৷"
+   },
+   "info1": {
+      "message": "আপনি যে পৃষ্ঠাগুলি দেখেন সেগুলি Google দ্বারা অপ্টিমাইজ করতে কম ডেটা খরচ করে।"
+   },
+   "info2": {
+      "message": "HTTPS বা ছদ্মবেশ ধরে অ্যাক্সেস করা পৃষ্ঠা Google দ্বারা অপ্টিমাইজ বা দেখা যাবে না।"
+   },
+   "learnmorelinktext": {
+      "message": "আরো জানুন"
+   },
+   "originalsizeformat": {
+      "message": "মূল আকার: \u003Cb>$1 বাইটস\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "মূল আকার: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "মূল আকার: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "মূল আকার: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "ডেটার ব্যবহার হ্রাস করুন"
+   },
+   "reportissue": {
+      "message": "কোনো সমস্যার প্রতিবেদন করুন"
+   },
+   "versionnotcompatible": {
+      "message": "Chrome এর এই সংস্করণটি এই এক্সটেনশনটির সাথে সঙ্গতিপূর্ণ নয়৷ দয়া করে Chrome এর সাম্প্রতিক সংস্করণে আপডেট করুন৷ M41 বিটা হ'ল প্রথম সমর্থিত সংস্করণ৷"
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ca/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ca/messages.json
new file mode 100644
index 0000000..f9a644a
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ca/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Després de la compressió: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Després de la compressió: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Després de la compressió: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Després de la compressió: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Desactiva Economitzador de dades"
+   },
+   "enabledatasaverlabel": {
+      "message": "Activa Economitzador de dades"
+   },
+   "extdesc": {
+      "message": "Redueix l'ús de dades utilitzant servidors de Google per optimitzar les pàgines que visiteu."
+   },
+   "extname": {
+      "message": "Economitzador de dades"
+   },
+   "extnamebeta": {
+      "message": "Economitzador de dades (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Ajuda i suggeriments"
+   },
+   "incognitomessage": {
+      "message": "Aquesta extensió no es pot utilitzar en mode d'incògnit."
+   },
+   "info1": {
+      "message": "Optimitzeu les pàgines que visiteu fent servir Google per reduir l'ús de dades."
+   },
+   "info2": {
+      "message": "Google no optimitzarà ni veurà pàgines a què hàgiu accedit en mode d'incògnit o amb HTTPS."
+   },
+   "learnmorelinktext": {
+      "message": "Més informació"
+   },
+   "originalsizeformat": {
+      "message": "Mida original: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Mida original: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Mida original: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Mida original: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reducció de l'ús de dades"
+   },
+   "reportissue": {
+      "message": "Informa d'un problema"
+   },
+   "versionnotcompatible": {
+      "message": "Aquesta versió de Chrome no és compatible amb aquesta extensió. Actualitzeu Chrome a la darrera versió. La versió M41 Beta és la primera que és compatible."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/cs/messages.json b/chrome/test/data/chromeproxy/extension/_locales/cs/messages.json
new file mode 100644
index 0000000..c8c428b
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/cs/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Po kompresi: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Po kompresi: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Po kompresi: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Po kompresi: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Vypnout Spořič dat"
+   },
+   "enabledatasaverlabel": {
+      "message": "Zapnout Spořič dat"
+   },
+   "extdesc": {
+      "message": "Snižuje množství dat tím, že stránky optimalizuje pomocí serverů Google."
+   },
+   "extname": {
+      "message": "Spořič dat"
+   },
+   "extnamebeta": {
+      "message": "Spořič dat (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Nápověda a zpětná vazba"
+   },
+   "incognitomessage": {
+      "message": "Toto rozšíření nelze používat v anonymním režimu."
+   },
+   "info1": {
+      "message": "Využijte Google k optimalizaci navštěvovaných stránek a utrácejte za data méně."
+   },
+   "info2": {
+      "message": "Stránky zobrazené prostřednictvím protokolu HTTPS nebo v anonymním režimu nebudou pro Google viditelné a nebudou optimalizovány."
+   },
+   "learnmorelinktext": {
+      "message": "Další informace"
+   },
+   "originalsizeformat": {
+      "message": "Původní velikost: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Původní velikost: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Původní velikost: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Původní velikost: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Snížit využití dat"
+   },
+   "reportissue": {
+      "message": "Nahlásit problém"
+   },
+   "versionnotcompatible": {
+      "message": "Tato verze Chromu s tímto rozšířením není kompatibilní. Aktualizujte Chrome na nejnovější verzi. První podporovanou verzí je M41 Beta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/da/messages.json b/chrome/test/data/chromeproxy/extension/_locales/da/messages.json
new file mode 100644
index 0000000..51922cc
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/da/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Efter komprimering: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Efter komprimering: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Efter komprimering: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Efter komprimering: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Slå datasparefunktionen fra"
+   },
+   "enabledatasaverlabel": {
+      "message": "Slå datasparefunktionen til"
+   },
+   "extdesc": {
+      "message": "Reducerer dataforbrug ved at anvende Googles servere til at optimere sider, du besøger."
+   },
+   "extname": {
+      "message": "Datasparefunktion"
+   },
+   "extnamebeta": {
+      "message": "Datasparefunktion (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Hjælp og feedback"
+   },
+   "incognitomessage": {
+      "message": "Denne udvidelse kan ikke bruges i inkognitotilstand."
+   },
+   "info1": {
+      "message": "Spar penge på data ved at bruge Google til at optimere de sider, du besøger."
+   },
+   "info2": {
+      "message": "Google optimerer og viser ikke sider, der besøges via HTTPS eller inkognito."
+   },
+   "learnmorelinktext": {
+      "message": "Få flere oplysninger"
+   },
+   "originalsizeformat": {
+      "message": "Oprindelig størrelse: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Oprindelig størrelse: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Oprindelig størrelse: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Oprindelig størrelse: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reducer dataforbruget"
+   },
+   "reportissue": {
+      "message": "Rapportér et problem"
+   },
+   "versionnotcompatible": {
+      "message": "Denne version af Chrome er ikke kompatibel med udvidelsen. Opdater Chrome til den nyeste version. M41 beta er den første understøttede version."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/de/messages.json b/chrome/test/data/chromeproxy/extension/_locales/de/messages.json
new file mode 100644
index 0000000..98cf5f05
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/de/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Nach der Komprimierung: \u003Cb>$1 Byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Nach der Komprimierung: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Nach der Komprimierung: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Nach der Komprimierung: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Datenkomprimierung deaktivieren"
+   },
+   "enabledatasaverlabel": {
+      "message": "Datenkomprimierung aktivieren"
+   },
+   "extdesc": {
+      "message": "Reduziert die Datennutzung, indem besuchte Seiten über die Google-Server optimiert werden"
+   },
+   "extname": {
+      "message": "Datenkomprimierung"
+   },
+   "extnamebeta": {
+      "message": "Datenkomprimierung (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Hilfe und Feedback"
+   },
+   "incognitomessage": {
+      "message": "Diese Erweiterung kann nicht im Inkognito-Modus verwendet werden."
+   },
+   "info1": {
+      "message": "Mit Google besuchte Seiten optimieren und so den Datenverbrauch verringern"
+   },
+   "info2": {
+      "message": "Über HTTPS oder den Inkognito-Modus aufgerufene Seiten werden von Google nicht optimiert oder protokolliert."
+   },
+   "learnmorelinktext": {
+      "message": "Weitere Informationen"
+   },
+   "originalsizeformat": {
+      "message": "Ursprüngliche Größe: \u003Cb>$1 Byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Ursprüngliche Größe: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Ursprüngliche Größe: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Ursprüngliche Größe: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Datennutzung reduzieren"
+   },
+   "reportissue": {
+      "message": "Problem melden"
+   },
+   "versionnotcompatible": {
+      "message": "Diese Version von Chrome ist nicht mit dieser Erweiterung kompatibel. Bitte aktualisieren Sie Chrome auf die neueste Version. M41 Beta ist die erste unterstützte Version."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/el/messages.json b/chrome/test/data/chromeproxy/extension/_locales/el/messages.json
new file mode 100644
index 0000000..dcb048bc
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/el/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Μετά τη συμπίεση: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Μετά τη συμπίεση: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Μετά τη συμπίεση: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Μετά τη συμπίεση: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Απενεργοποίηση Εξοικονόμησης δεδομένων"
+   },
+   "enabledatasaverlabel": {
+      "message": "Ενεργοποίηση Εξοικονόμησης δεδομένων"
+   },
+   "extdesc": {
+      "message": "Περιορίζει τη χρήση δεδομένων, αξιοποιώντας τους διακομιστές της Google για να βελτιστοποιήσει τις σελίδες που επισκέπτεστε."
+   },
+   "extname": {
+      "message": "Εξοικονόμηση δεδομένων"
+   },
+   "extnamebeta": {
+      "message": "Εξοικονόμηση δεδομένων (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Βοήθεια και σχόλια"
+   },
+   "incognitomessage": {
+      "message": "Αυτή η επέκταση δεν μπορεί να χρησιμοποιηθεί σε κατάσταση ανώνυμης περιήγησης."
+   },
+   "info1": {
+      "message": "Ξοδέψτε λιγότερα δεδομένα αξιοποιώντας τη βελτιστοποίηση των σελίδων που επισκέπτεστε από την Google."
+   },
+   "info2": {
+      "message": "Οι σελίδες στις οποίες αποκτάτε πρόσβαση μέσω του HTTPS ή της Ανώνυμης περιήγησης δεν θα βελτιστοποιηθούν ή δεν θα είναι ορατές από την Google."
+   },
+   "learnmorelinktext": {
+      "message": "Μάθετε περισσότερα"
+   },
+   "originalsizeformat": {
+      "message": "Αρχικό μέγεθος: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Αρχικό μέγεθος: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Αρχικό μέγεθος: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Αρχικό μέγεθος: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Μείωση χρήσης δεδομένων"
+   },
+   "reportissue": {
+      "message": "Αναφορά ζητήματος"
+   },
+   "versionnotcompatible": {
+      "message": "Αυτή η έκδοση του Chrome δεν είναι συμβατή με αυτήν την επέκταση. Ενημερώστε το Chrome στην πιο πρόσφατη έκδοση. Το M41 Beta είναι η πρώτη έκδοση που υποστηρίζεται."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/en/messages.json b/chrome/test/data/chromeproxy/extension/_locales/en/messages.json
new file mode 100644
index 0000000..66288bbb
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/en/messages.json
@@ -0,0 +1,192 @@
+{
+   "compressedSizeFormat": {
+      "description": "Message to display compressed size of the content which was browsed using this extension.",
+      "message": "After compression: $beginBold$$size$ bytes$endBold$",
+      "placeholders": {
+         "beginBold": {
+            "content": "\u003Cb>"
+         },
+         "endBold": {
+            "content": "\u003C/b>"
+         },
+         "size": {
+            "content": "$1",
+            "example": "229"
+         }
+      }
+   },
+   "compressedSizeFormatGb": {
+      "description": "Message to display compressed size of the content which was browsed using this extension.",
+      "message": "After compression: $beginBold$$size$ GB$endBold$",
+      "placeholders": {
+         "beginBold": {
+            "content": "\u003Cb>"
+         },
+         "endBold": {
+            "content": "\u003C/b>"
+         },
+         "size": {
+            "content": "$1",
+            "example": "229"
+         }
+      }
+   },
+   "compressedSizeFormatKb": {
+      "description": "Message to display compressed size of the content which was browsed using this extension.",
+      "message": "After compression: $beginBold$$size$ KB$endBold$",
+      "placeholders": {
+         "beginBold": {
+            "content": "\u003Cb>"
+         },
+         "endBold": {
+            "content": "\u003C/b>"
+         },
+         "size": {
+            "content": "$1",
+            "example": "229"
+         }
+      }
+   },
+   "compressedSizeFormatMb": {
+      "description": "Message to display compressed size of the content which was browsed using this extension.",
+      "message": "After compression: $beginBold$$size$ MB$endBold$",
+      "placeholders": {
+         "beginBold": {
+            "content": "\u003Cb>"
+         },
+         "endBold": {
+            "content": "\u003C/b>"
+         },
+         "size": {
+            "content": "$1",
+            "example": "229"
+         }
+      }
+   },
+   "dataSavingsPercentFormat": {
+      "description": "Message to display data savings obtained by using this extension.",
+      "message": "$dataSavings$%",
+      "placeholders": {
+         "dataSavings": {
+            "content": "$1",
+            "example": "26"
+         }
+      }
+   },
+   "disableDataSaverLabel": {
+      "description": "Label on button to turn off data saver.",
+      "message": "Turn Off Data Saver"
+   },
+   "enableDataSaverLabel": {
+      "description": "Label on button to turn on data saver.",
+      "message": "Turn On Data Saver"
+   },
+   "extDesc": {
+      "description": "Description of this Chrome extension. Displayed in Chrome Web Store. [CHAR LIMIT=132]",
+      "message": "Reduces data usage by using Google servers to optimize pages you visit."
+   },
+   "extName": {
+      "description": "Name of this Chrome extension. [CHAR LIMIT=45]",
+      "message": "Data Saver"
+   },
+   "extNameBeta": {
+      "description": "Name of this Chrome extension when in beta. [CHAR LIMIT=45]",
+      "message": "Data Saver (Beta)"
+   },
+   "helpAndFeedback": {
+      "description": "Text in the link which takes users to documentation regarding getting help and providing feedback. [CHAR LIMIT=45]",
+      "message": "Help and Feedback"
+   },
+   "incognitoMessage": {
+      "description": "Message shown to users when they attempt to use this extension in incognito mode.",
+      "message": "This extension cannot be used in incognito mode."
+   },
+   "info1": {
+      "description": "Information regarding how this extension works.",
+      "message": "Spend less on data by using Google to optimize the pages you visit."
+   },
+   "info2": {
+      "description": "Information regarding how this extension works with HTTPS and Incognito mode.",
+      "message": "Pages accessed with HTTPS or Incognito will not be optimized or seen by Google."
+   },
+   "learnMoreLinkText": {
+      "description": "Text in the link which takes users to more information about this extension.",
+      "message": "Learn more"
+   },
+   "originalSizeFormat": {
+      "description": "Message to display original size of the content which was browsed using this extension.",
+      "message": "Original size: $beginBold$$size$ bytes$endBold$",
+      "placeholders": {
+         "beginBold": {
+            "content": "\u003Cb>"
+         },
+         "endBold": {
+            "content": "\u003C/b>"
+         },
+         "size": {
+            "content": "$1",
+            "example": "263"
+         }
+      }
+   },
+   "originalSizeFormatGb": {
+      "description": "Message to display original size of the content which was browsed using this extension.",
+      "message": "Original size: $beginBold$$size$ GB$endBold$",
+      "placeholders": {
+         "beginBold": {
+            "content": "\u003Cb>"
+         },
+         "endBold": {
+            "content": "\u003C/b>"
+         },
+         "size": {
+            "content": "$1",
+            "example": "263"
+         }
+      }
+   },
+   "originalSizeFormatKb": {
+      "description": "Message to display original size of the content which was browsed using this extension.",
+      "message": "Original size: $beginBold$$size$ KB$endBold$",
+      "placeholders": {
+         "beginBold": {
+            "content": "\u003Cb>"
+         },
+         "endBold": {
+            "content": "\u003C/b>"
+         },
+         "size": {
+            "content": "$1",
+            "example": "263"
+         }
+      }
+   },
+   "originalSizeFormatMb": {
+      "description": "Message to display original size of the content which was browsed using this extension.",
+      "message": "Original size: $beginBold$$size$ MB$endBold$",
+      "placeholders": {
+         "beginBold": {
+            "content": "\u003Cb>"
+         },
+         "endBold": {
+            "content": "\u003C/b>"
+         },
+         "size": {
+            "content": "$1",
+            "example": "263"
+         }
+      }
+   },
+   "reduceDataUsageLabel": {
+      "description": "Label for UI element used to toggle reduce data usage feature.",
+      "message": "Reduce data usage"
+   },
+   "reportIssue": {
+      "description": "Text in the link which takes users to documentation regarding reporting bugs. [CHAR LIMIT=45]",
+      "message": "Report an issue"
+   },
+   "versionNotCompatible": {
+      "description": "Message shown to users when the version of Chrome is not compatible with this extension.",
+      "message": "This version of Chrome is not compatible with this extension. Please update Chrome to the latest version. M41 Beta is the first supported version."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/en_GB/messages.json b/chrome/test/data/chromeproxy/extension/_locales/en_GB/messages.json
new file mode 100644
index 0000000..cf257eca
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/en_GB/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "After compression: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "After compression: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "After compression: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "After compression: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Turn off Data Saver"
+   },
+   "enabledatasaverlabel": {
+      "message": "Turn on Data Saver"
+   },
+   "extdesc": {
+      "message": "Reduces data usage by using Google servers to optimize pages you visit."
+   },
+   "extname": {
+      "message": "Data Saver"
+   },
+   "extnamebeta": {
+      "message": "Data Saver (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Help and feedback"
+   },
+   "incognitomessage": {
+      "message": "This extension cannot be used in incognito mode."
+   },
+   "info1": {
+      "message": "Spend less on data by using Google to optimise the pages that you visit."
+   },
+   "info2": {
+      "message": "Pages accessed with HTTPS or Incognito will not be optimised or seen by Google."
+   },
+   "learnmorelinktext": {
+      "message": "Learn more"
+   },
+   "originalsizeformat": {
+      "message": "Original size: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Original size: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Original size: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Original size: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reduce data usage"
+   },
+   "reportissue": {
+      "message": "Report an issue"
+   },
+   "versionnotcompatible": {
+      "message": "This version of Chrome is not compatible with this extension. Please update Chrome to the latest version. M41 Beta is the first supported version."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/es/messages.json b/chrome/test/data/chromeproxy/extension/_locales/es/messages.json
new file mode 100644
index 0000000..9ec3f9bf9
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/es/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Después de comprimir: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Después de comprimir: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Después de comprimir: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Después de comprimir: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Desactivar Economizador de datos"
+   },
+   "enabledatasaverlabel": {
+      "message": "Activar Economizador de datos"
+   },
+   "extdesc": {
+      "message": "Utiliza los servidores de Google para optimizar las páginas que visitas y reducir el uso de datos."
+   },
+   "extname": {
+      "message": "Economizador de datos"
+   },
+   "extnamebeta": {
+      "message": "Economizador de datos (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Ayuda y comentarios"
+   },
+   "incognitomessage": {
+      "message": "Esta extensión no se puede utilizar en modo incógnito."
+   },
+   "info1": {
+      "message": "Optimiza las páginas que visitas utilizando Google para reducir el uso de datos."
+   },
+   "info2": {
+      "message": "Google no optimizará ni verá páginas a las que accedas con HTTPS o en Incógnito."
+   },
+   "learnmorelinktext": {
+      "message": "Más información"
+   },
+   "originalsizeformat": {
+      "message": "Tamaño original: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Tamaño original: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Tamaño original: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Tamaño original: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reducir el uso de datos"
+   },
+   "reportissue": {
+      "message": "Informar de un problema"
+   },
+   "versionnotcompatible": {
+      "message": "Esta versión de Chrome no es compatible con esta extensión. Actualiza Chrome a la última versión. La primera versión admitida es M41 Beta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/es_419/messages.json b/chrome/test/data/chromeproxy/extension/_locales/es_419/messages.json
new file mode 100644
index 0000000..e0c6ad8
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/es_419/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Poscompresión: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Poscompresión: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Poscompresión: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Poscompresión: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Desactivar extensión para Reducir datos"
+   },
+   "enabledatasaverlabel": {
+      "message": "Activar extensión para Reducir datos"
+   },
+   "extdesc": {
+      "message": "Reduce el uso de datos mediante el uso de los servidores de Google para optimizar las páginas que visitas."
+   },
+   "extname": {
+      "message": "Reducir datos"
+   },
+   "extnamebeta": {
+      "message": "Reducir datos (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Ayuda y comentarios"
+   },
+   "incognitomessage": {
+      "message": "No se puede usar esta extensión en modo de navegación de incógnito."
+   },
+   "info1": {
+      "message": "Reduce el gasto de datos utilizando Google para optimizar las páginas visitadas."
+   },
+   "info2": {
+      "message": "Google no optimizará ni verá páginas a las que accedas con HTTPS o en modo de navegación de incógnito."
+   },
+   "learnmorelinktext": {
+      "message": "Más información"
+   },
+   "originalsizeformat": {
+      "message": "Tamaño original: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Tamaño original: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Tamaño original: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Tamaño original: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reducir el uso de datos"
+   },
+   "reportissue": {
+      "message": "Informar un problema"
+   },
+   "versionnotcompatible": {
+      "message": "Esta versión de Chrome no es compatible con esta extensión. Actualiza Chrome a la última versión. M41 Beta es la primera versión compatible."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/et/messages.json b/chrome/test/data/chromeproxy/extension/_locales/et/messages.json
new file mode 100644
index 0000000..355fc324
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/et/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Pärast tihendamist: \u003Cb>$1 baiti\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Pärast tihendamist: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Pärast tihendamist: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Pärast tihendamist: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Lülita Andmemahu säästja välja"
+   },
+   "enabledatasaverlabel": {
+      "message": "Lülita Andmemahu säästja sisse"
+   },
+   "extdesc": {
+      "message": "Vähendab andmekasutust, kasutades Google'i servereid külastatavate lehtede optimeerimiseks."
+   },
+   "extname": {
+      "message": "Andmemahu säästja"
+   },
+   "extnamebeta": {
+      "message": "Data Saver (beeta)"
+   },
+   "helpandfeedback": {
+      "message": "Abi ja tagasiside"
+   },
+   "incognitomessage": {
+      "message": "Seda laiendust ei saa kasutada inkognito režiimis."
+   },
+   "info1": {
+      "message": "Kulutage vähem aega andmete peale, kasutades Google'it külastatavate lehtede optimeerimiseks."
+   },
+   "info2": {
+      "message": "Funktsiooniga HTTPS või Inkognito avatud lehti Google ei optimeeri ega näe."
+   },
+   "learnmorelinktext": {
+      "message": "Lisateave"
+   },
+   "originalsizeformat": {
+      "message": "Algne suurus: \u003Cb>$1 baiti\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Algne suurus: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Algne suurus: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Algne suurus: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Andmekasutuse vähendamine"
+   },
+   "reportissue": {
+      "message": "Probleemist teavitamine"
+   },
+   "versionnotcompatible": {
+      "message": "See Chrome'i versioon ei ühildu selle laiendusega. Värskendage Chrome uusimale versioonile. Esimene toetatud versioon on M41 beeta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/fa/messages.json b/chrome/test/data/chromeproxy/extension/_locales/fa/messages.json
new file mode 100644
index 0000000..8302001
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/fa/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "پس از فشرده‌سازی: \u003Cb>$1 بایت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "پس از فشرده‌سازی: \u003Cb>$1 گیگابایت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "پس از فشرده‌سازی: \u003Cb>$1 کیلوبایت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "پس از فشرده‌سازی: \u003Cb>$1 مگابایت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1٪",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "خاموش کردن صرفه‌جویی در مصرف داده"
+   },
+   "enabledatasaverlabel": {
+      "message": "روشن کردن صرفه‌جویی در مصرف داده"
+   },
+   "extdesc": {
+      "message": "با استفاده از سرورهای Google جهت بهینه کردن صفحاتی که بازدید می‌کنید، مصرف داده را کاهش می‌دهد."
+   },
+   "extname": {
+      "message": "صرفه‌جویی در مصرف داده"
+   },
+   "extnamebeta": {
+      "message": "صرفه‌جویی در مصرف داده (بتا)"
+   },
+   "helpandfeedback": {
+      "message": "راهنما و بازخورد"
+   },
+   "incognitomessage": {
+      "message": "این افزونه نمی‌تواند در حالت ناشناس استفاده شود."
+   },
+   "info1": {
+      "message": "با استفاده از Google برای بهینه‌سازی صفحاتی که بازدید می‌کنید، هزینه مصرف داده‌ را کاهش دهید."
+   },
+   "info2": {
+      "message": "Google صفحات بازدیدشده با HTTPS یا حالت ناشناس را بهینه یا مشاهده نمی‌کند."
+   },
+   "learnmorelinktext": {
+      "message": "بیشتر بدانید"
+   },
+   "originalsizeformat": {
+      "message": "اندازه اصلی: \u003Cb>$1 بایت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "اندازه اصلی: \u003Cb>$1 گیگابایت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "اندازه اصلی: \u003Cb>$1 کیلوبایت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "اندازه اصلی: \u003Cb>$1 مگابایت\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "کاهش مصرف داده"
+   },
+   "reportissue": {
+      "message": "گزارش مشکل"
+   },
+   "versionnotcompatible": {
+      "message": "این نسخه از Chrome با این افزونه سازگار نیست. لطفاً Chrome را به آخرین نسخه به‌روزرسانی کنید. M41 بتا اولین نسخه پشتیبانی شده است."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/fi/messages.json b/chrome/test/data/chromeproxy/extension/_locales/fi/messages.json
new file mode 100644
index 0000000..02d8dc22
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/fi/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Pakkaamisen jälkeen: \u003Cb>$1 tavua\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Pakkaamisen jälkeen: \u003Cb>$1 Gt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Pakkaamisen jälkeen: \u003Cb>$1 Kt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Pakkaamisen jälkeen: \u003Cb>$1 Mt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Poista Data Saver käytöstä"
+   },
+   "enabledatasaverlabel": {
+      "message": "Ota Data Saver käyttöön"
+   },
+   "extdesc": {
+      "message": "Vähentää tiedonsiirron määrää optimoimalla käyttämäsi sivut Google-palvelimien avulla."
+   },
+   "extname": {
+      "message": "Data Saver"
+   },
+   "extnamebeta": {
+      "message": "Data Saver (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Ohjeet ja palaute"
+   },
+   "incognitomessage": {
+      "message": "Laajennusta ei voi käyttää incognito-tilassa."
+   },
+   "info1": {
+      "message": "Säästä tiedonsiirrossa optimoimalla käyttämäsi sivut Googlen avulla."
+   },
+   "info2": {
+      "message": "Google ei optimoi tai näe HTTPS- tai incognito-tilassa käytettyjä sivuja."
+   },
+   "learnmorelinktext": {
+      "message": "Lisätietoja"
+   },
+   "originalsizeformat": {
+      "message": "Alkuperäinen koko: \u003Cb>$1 tavua\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Alkuperäinen koko: \u003Cb>$1 Gt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Alkuperäinen koko: \u003Cb>$1 Kt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Alkuperäinen koko: \u003Cb>$1 Mt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Tiedonsiirron vähentäminen"
+   },
+   "reportissue": {
+      "message": "Ilmoita ongelmasta"
+   },
+   "versionnotcompatible": {
+      "message": "Tämä Chrome-versio ei ole yhteensopiva tämän laajennuksen kanssa. Päivitä Chrome sen uusimpaan versioon. M41 Beta on ensimmäinen tuettu versio."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/fil/messages.json b/chrome/test/data/chromeproxy/extension/_locales/fil/messages.json
new file mode 100644
index 0000000..25caf963a
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/fil/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Pagkatapos ma-compress: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Pagkatapos ma-compress: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Pagkatapos ma-compress: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Pagkatapos ma-compress: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "I-off ang Data Saver"
+   },
+   "enabledatasaverlabel": {
+      "message": "I-on ang Data Saver"
+   },
+   "extdesc": {
+      "message": "Binabawasan ang paggamit ng data sa pamamagitan ng paggamit sa mga server ng Google upang i-optimize ang mga page na binibisita mo."
+   },
+   "extname": {
+      "message": "Data Saver"
+   },
+   "extnamebeta": {
+      "message": "Data Saver (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Tulong at Feedback"
+   },
+   "incognitomessage": {
+      "message": "Hindi magagamit ang extension na ito sa incognito mode."
+   },
+   "info1": {
+      "message": "Gumastos nang mas mababa sa data sa pamamagitan ng paggamit ng Google upang i-optimize ang mga page na binibisita mo."
+   },
+   "info2": {
+      "message": "Ang mga page na in-access sa HTTPS o Incognito ay hindi mao-optimize o makikita ng Google."
+   },
+   "learnmorelinktext": {
+      "message": "Matuto nang higit pa"
+   },
+   "originalsizeformat": {
+      "message": "Orihinal na laki: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Orihinal na laki: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Orihinal na laki: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Orihinal na laki: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Bawasan ang paggamit ng data"
+   },
+   "reportissue": {
+      "message": "Mag-ulat ng isyu"
+   },
+   "versionnotcompatible": {
+      "message": "Ang bersyong ito ng Chrome ay hindi gumagana sa extension na ito. Paki-update ang Chrome sa pinakabagong bersyon. Ang M41 Beta ay ang unang sinusuportahang bersyon."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/fr/messages.json b/chrome/test/data/chromeproxy/extension/_locales/fr/messages.json
new file mode 100644
index 0000000..5d29998
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/fr/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Après compression : \u003Cb>$1 octets\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Après compression : \u003Cb>$1 Go\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Après compression : \u003Cb>$1 Ko\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Après compression : \u003Cb>$1 Mo\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Désactiver Économiseur de données"
+   },
+   "enabledatasaverlabel": {
+      "message": "Activer Économiseur de données"
+   },
+   "extdesc": {
+      "message": "Réduit la consommation des données en utilisant les serveurs de Google pour optimiser les pages que vous consultez."
+   },
+   "extname": {
+      "message": "Économiseur de données"
+   },
+   "extnamebeta": {
+      "message": "Économiseur de données (version bêta)"
+   },
+   "helpandfeedback": {
+      "message": "Aide et commentaires"
+   },
+   "incognitomessage": {
+      "message": "Impossible d'utiliser cette extension en mode navigation privée."
+   },
+   "info1": {
+      "message": "Consommez moins de données grâce à l'optimisation des pages par Google."
+   },
+   "info2": {
+      "message": "Le HTTPS et la navigation privée empêchent la détection et l'optimisation des pages."
+   },
+   "learnmorelinktext": {
+      "message": "En savoir plus"
+   },
+   "originalsizeformat": {
+      "message": "Taille originale : \u003Cb>$1 octets\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Taille originale : \u003Cb>$1 Go\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Taille originale : \u003Cb>$1 Ko\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Taille originale : \u003Cb>$1 Mo\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Réduire la consommation des données"
+   },
+   "reportissue": {
+      "message": "Signaler un problème"
+   },
+   "versionnotcompatible": {
+      "message": "Cette version de Chrome n'est pas compatible avec cette extension. Veuillez mettre à jour Chrome pour utiliser la dernière version. La première version compatible est la version bêta M41."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/gu/messages.json b/chrome/test/data/chromeproxy/extension/_locales/gu/messages.json
new file mode 100644
index 0000000..6935141
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/gu/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "સંકુચન પછી: \u003Cb>$1 બાઇટ્સ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "સંકુચન પછી: \u003Cb>$1GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "સંકુચન પછી: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "સંકુચન પછી: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "ડેટા સેવર બંધ કરો"
+   },
+   "enabledatasaverlabel": {
+      "message": "ડેટા સેવર ચાલુ કરો"
+   },
+   "extdesc": {
+      "message": "તમે મુલાકાત લો છો તે પૃષ્ઠોને ઓપ્ટિમાઇઝ કરવા માટે Google સર્વર્સનો ઉપયોગ કરીને ડેટા વપરાશ ઘટાડે છે."
+   },
+   "extname": {
+      "message": "ડેટા સેવર"
+   },
+   "extnamebeta": {
+      "message": "ડેટા સેવર (બીટા)"
+   },
+   "helpandfeedback": {
+      "message": "સહાય અને પ્રતિસાદ"
+   },
+   "incognitomessage": {
+      "message": "આ એક્સટેન્શનનો છુપા મોડમાં ઉપયોગ કરી શકાતો નથી."
+   },
+   "info1": {
+      "message": "તમે મુલાકાત લો છો તે પૃષ્ઠો ઓપ્ટિમાઇઝ કરવા માટે Google નો ઉપયોગ કરીને ડેટા પર ઓછો ખર્ચ કરો."
+   },
+   "info2": {
+      "message": "HTTPS અથવા છુપા મોડ વડે ઍક્સેસ કરવામાં આવેલા પૃષ્ઠો ઓપ્ટિમાઇઝ થશે નહીં અથવા Google દ્વારા જોવામાં આવશે નહીં."
+   },
+   "learnmorelinktext": {
+      "message": "વધુ જાણો"
+   },
+   "originalsizeformat": {
+      "message": "મૂળ કદ: \u003Cb>$1 બાઇટ્સ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "મૂળ કદ: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "મૂળ કદ: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "મૂળ કદ: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "ડેટા વપરાશ ઘટાડો"
+   },
+   "reportissue": {
+      "message": "સમસ્યાની જાણ કરો"
+   },
+   "versionnotcompatible": {
+      "message": "આ એક્સ્ટેન્શન સાથે Chrome નું આ સંસ્કરણ સુસંગત નથી. કૃપા કરીને Chrome ને નવીનતમ સંસ્કરણ પર અપડેટ કરો. M41 બીટા એ પ્રથમ સમર્થિત સંસ્કરણ છે."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/he/messages.json b/chrome/test/data/chromeproxy/extension/_locales/he/messages.json
new file mode 100644
index 0000000..c47d118
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/he/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "לאחר דחיסה: \u003Cb>$1 בייטים\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "לאחר דחיסה: \u003Cb>‎$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "לאחר דחיסה: \u003Cb>‎$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "לאחר דחיסה: \u003Cb>‎$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "‎$1%‎",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "כבה את חוסך הנתונים (Data Saver)"
+   },
+   "enabledatasaverlabel": {
+      "message": "הפעל את חוסך הנתונים (Data Saver)"
+   },
+   "extdesc": {
+      "message": "מפחית את צריכת הנתונים על ידי שימוש בשרתי Google כדי לבצע אופטימיזציה של הדפים שבהם אתה מבקר."
+   },
+   "extname": {
+      "message": "חוסך הנתונים (Data Saver)"
+   },
+   "extnamebeta": {
+      "message": "חוסך הנתונים (Data Saver) (ביטא)"
+   },
+   "helpandfeedback": {
+      "message": "עזרה ומשוב"
+   },
+   "incognitomessage": {
+      "message": "לא ניתן להשתמש בתוסף הזה במצב גלישה בסתר."
+   },
+   "info1": {
+      "message": "חסוך בהוצאות על נתונים על ידי שימוש ב-Google לביצוע אופטימיזציה של דפים שאתה מבקר בהם."
+   },
+   "info2": {
+      "message": "Google לא תראה או תבצע אופטימיזציה של דפים שהגישה אליהם בוצעה דרך HTTPS או במצב גלישה בסתר."
+   },
+   "learnmorelinktext": {
+      "message": "למידע נוסף"
+   },
+   "originalsizeformat": {
+      "message": "גודל מקורי: \u003Cb>$1 בייטים\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "גודל מקורי: \u003Cb>‎$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "גודל מקורי: \u003Cb>‎$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "גודל מקורי: \u003Cb>‎$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "הפחת את צריכת הנתונים"
+   },
+   "reportissue": {
+      "message": "דווח על בעיה"
+   },
+   "versionnotcompatible": {
+      "message": "הגרסה הזו של Chrome אינה תואמת לתוסף הזה. עדכן את Chrome לגרסה האחרונה. תמיכה קיימת החל מגרסהM41 ביטא."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/hi/messages.json b/chrome/test/data/chromeproxy/extension/_locales/hi/messages.json
new file mode 100644
index 0000000..cd04f24
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/hi/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "संपीड़न के बाद: \u003Cb>$1 बाइट\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "संपीड़न के बाद: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "संपीड़न के बाद: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "संपीड़न के बाद: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "डेटा बचतकर्ता बंद करें"
+   },
+   "enabledatasaverlabel": {
+      "message": "डेटा बचतकर्ता चालू करें"
+   },
+   "extdesc": {
+      "message": "आपके द्वारा देखे जाने वाले पृष्ठों को ऑप्टिमाइज़ करने के लिए Google सर्वर का उपयोग करके डेटा उपयोग को कम करें."
+   },
+   "extname": {
+      "message": "डेटा बचतकर्ता"
+   },
+   "extnamebeta": {
+      "message": "डेटा सर्वर (बीटा)"
+   },
+   "helpandfeedback": {
+      "message": "सहायता और फ़ीडबैक"
+   },
+   "incognitomessage": {
+      "message": "इस एक्सटेंशन का उपयोग गुप्त मोड में नहीं किया जा सकता."
+   },
+   "info1": {
+      "message": "Google का उपयोग कर देखे जाने वाले पृष्ठ अनुकूलित करके डेटा पर कम खर्च करें."
+   },
+   "info2": {
+      "message": "HTTPS या गुप्त मोड से ऐक्‍सेस किए गए पृष्ठों को Google द्वारा अनुकूलित नहीं किया जाएगा या देखा नहीं जाएगा."
+   },
+   "learnmorelinktext": {
+      "message": "और जानें"
+   },
+   "originalsizeformat": {
+      "message": "मूल आकार: \u003Cb>$1 बाइट\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "मूल आकार: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "मूल आकार: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "मूल आकार: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "डेटा उपयोग में कमी लाना"
+   },
+   "reportissue": {
+      "message": "समस्या की रिपोर्ट करना"
+   },
+   "versionnotcompatible": {
+      "message": "Chrome का यह वर्शन इस एक्‍सटेंशन से संगत नहीं है. कृपया Chrome को नवीनतम वर्शन में अपडेट करें. M41 बीटा पहला समर्थित वर्शन है."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/hr/messages.json b/chrome/test/data/chromeproxy/extension/_locales/hr/messages.json
new file mode 100644
index 0000000..f699a039
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/hr/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Nakon kompresije: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Nakon kompresije: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Nakon kompresije: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Nakon kompresije: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Isključi uštedu podataka"
+   },
+   "enabledatasaverlabel": {
+      "message": "Uključi uštedu podataka"
+   },
+   "extdesc": {
+      "message": "Smanjuje potrošnju podataka upotrebljavajući Googleove poslužitelje za optimizaciju posjećenih stranica."
+   },
+   "extname": {
+      "message": "Ušteda podataka"
+   },
+   "extnamebeta": {
+      "message": "Ušteda podataka (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Pomoć i povratne informacije"
+   },
+   "incognitomessage": {
+      "message": "To se proširenje ne može upotrebljavati anonimno."
+   },
+   "info1": {
+      "message": "Google može optimizirati posjećene stranice radi uštede pri prijenosu podataka."
+   },
+   "info2": {
+      "message": "Google neće optimizirati niti vidjeti stranice kojima se pristupi HTTPS-om ili anonimno."
+   },
+   "learnmorelinktext": {
+      "message": "Saznajte više"
+   },
+   "originalsizeformat": {
+      "message": "Izvorna veličina: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Izvorna veličina: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Izvorna veličina: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Izvorna veličina: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Smanji podatkovni promet"
+   },
+   "reportissue": {
+      "message": "Prijava problema"
+   },
+   "versionnotcompatible": {
+      "message": "Ova verzija Chromea nije kompatibilna s ovim proširenjem. Ažurirajte Chrome na najnoviju verziju. Prva je podržana verzija M41 Beta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/hu/messages.json b/chrome/test/data/chromeproxy/extension/_locales/hu/messages.json
new file mode 100644
index 0000000..5ddcfcd
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/hu/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Tömörítést követően: \u003Cb>$1 bájt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Tömörítést követően: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Tömörítést követően: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Tömörítést követően: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Az Adatforgalom-csökkentő kikapcsolása"
+   },
+   "enabledatasaverlabel": {
+      "message": "Az Adatforgalom-csökkentő bekapcsolása"
+   },
+   "extdesc": {
+      "message": "Csökkenti az adathasználatot azáltal, hogy a Google szerverei optimalizálják az Ön által felkeresett oldalakat."
+   },
+   "extname": {
+      "message": "Adatforgalom-csökkentő"
+   },
+   "extnamebeta": {
+      "message": "Adatforgalom-csökkentő (béta)"
+   },
+   "helpandfeedback": {
+      "message": "Súgó és visszajelzés"
+   },
+   "incognitomessage": {
+      "message": "Ez a bővítmény nem használható inkognitómódban."
+   },
+   "info1": {
+      "message": "Kisebb az adatforgalom, ha a Google optimalizálja a felkeresett oldalakat."
+   },
+   "info2": {
+      "message": "A HTTPS vagy inkognitómód segítségével megnyitott oldalakat a Google nem optimalizálja és nem látja."
+   },
+   "learnmorelinktext": {
+      "message": "További információ"
+   },
+   "originalsizeformat": {
+      "message": "Eredeti méret: \u003Cb>$1 bájt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Eredeti méret: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Eredeti méret: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Eredeti méret: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Adathasználat csökkentése"
+   },
+   "reportissue": {
+      "message": "Hibabejelentés"
+   },
+   "versionnotcompatible": {
+      "message": "A Chrome ezen verziója nem kompatibilis ezzel a bővítménnyel. Kérjük, frissítse a Chrome-ot a legújabb verzióra. Az első támogatott verzió az M41 Beta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/id/messages.json b/chrome/test/data/chromeproxy/extension/_locales/id/messages.json
new file mode 100644
index 0000000..97f26f2
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/id/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Setelah kompresi: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Setelah kompresi: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Setelah kompresi: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Setelah kompresi: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Nonaktifkan Penghemat Data"
+   },
+   "enabledatasaverlabel": {
+      "message": "Aktifkan Penghemat Data"
+   },
+   "extdesc": {
+      "message": "Mengurangi penggunaan data dengan menggunakan server Google untuk mengoptimalkan laman yang Anda kunjungi."
+   },
+   "extname": {
+      "message": "Penghemat Data"
+   },
+   "extnamebeta": {
+      "message": "Penghemat Data (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Bantuan dan Masukan"
+   },
+   "incognitomessage": {
+      "message": "Ekstensi ini tidak dapat digunakan dalam mode penyamaran."
+   },
+   "info1": {
+      "message": "Menghemat data dengan menggunakan Google untuk mengoptimalkan laman yang Anda kunjungi."
+   },
+   "info2": {
+      "message": "Laman yang diakses dengan HTTPS atau Penyamaran tidak akan dioptimalkan atau dilihat oleh Google."
+   },
+   "learnmorelinktext": {
+      "message": "Pelajari lebih lanjut"
+   },
+   "originalsizeformat": {
+      "message": "Ukuran asli: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Ukuran asli: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Ukuran asli: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Ukuran asli: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Kurangi penggunaan data"
+   },
+   "reportissue": {
+      "message": "Laporkan masalah"
+   },
+   "versionnotcompatible": {
+      "message": "Versi Chrome ini tidak kompatibel dengan ekstensi berikut. Perbarui Chrome ke versi terbaru. M41 Beta adalah versi pertama yang didukung."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/it/messages.json b/chrome/test/data/chromeproxy/extension/_locales/it/messages.json
new file mode 100644
index 0000000..caa63e91
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/it/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Dopo la compressione: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Dopo la compressione: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Dopo la compressione: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Dopo la compressione: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Disattiva Risparmio dati"
+   },
+   "enabledatasaverlabel": {
+      "message": "Attiva Risparmio dati"
+   },
+   "extdesc": {
+      "message": "Consente di ridurre l'utilizzo dei dati impiegando i server di Google per ottimizzare le pagine visitate."
+   },
+   "extname": {
+      "message": "Risparmio dati"
+   },
+   "extnamebeta": {
+      "message": "Data Saver (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Assistenza e feedback"
+   },
+   "incognitomessage": {
+      "message": "Questa estensione non può essere utilizzata nella modalità di navigazione in incognito."
+   },
+   "info1": {
+      "message": "Consuma meno dati utilizzando Google per ottimizzare le pagine che visiti."
+   },
+   "info2": {
+      "message": "Le pagine visualizzate in modalità di navigazione in incognito o HTTPS non saranno ottimizzate o visualizzate da Google."
+   },
+   "learnmorelinktext": {
+      "message": "Ulteriori informazioni"
+   },
+   "originalsizeformat": {
+      "message": "Dimensioni originali: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Dimensioni originali: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Dimensioni originali: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Dimensioni originali: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Riduzione dell'utilizzo di dati"
+   },
+   "reportissue": {
+      "message": "Segnala un problema"
+   },
+   "versionnotcompatible": {
+      "message": "La versione di Chrome non è compatibile con questa estensione. Aggiorna Chrome all'ultima versione. La versione M41 Beta è la prima supportata."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ja/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ja/messages.json
new file mode 100644
index 0000000..5d35f08
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ja/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "圧縮後: \u003Cb>$1 バイト\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "圧縮後: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "圧縮後: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "圧縮後: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "データセーバーをオフにする"
+   },
+   "enabledatasaverlabel": {
+      "message": "データセーバーをオンにする"
+   },
+   "extdesc": {
+      "message": "アクセス先ページを最適に表示するためにGoogleのサーバーを使ってデータ使用量を削減します。"
+   },
+   "extname": {
+      "message": "データセーバー"
+   },
+   "extnamebeta": {
+      "message": "データセーバー(ベータ版)"
+   },
+   "helpandfeedback": {
+      "message": "ヘルプとフィードバック"
+   },
+   "incognitomessage": {
+      "message": "この拡張機能はシークレットモードでは使用できません。"
+   },
+   "info1": {
+      "message": "Googleを使用してデータ費用を抑え、アクセスしたページを最適化します。"
+   },
+   "info2": {
+      "message": "HTTPSやシークレットモードでアクセスしたページについては、Googleによる最適化や確認は行われません。"
+   },
+   "learnmorelinktext": {
+      "message": "詳しくはこちら"
+   },
+   "originalsizeformat": {
+      "message": "元のサイズ: \u003Cb>$1 バイト\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "元のサイズ: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "元のサイズ: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "元のサイズ: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "データ使用量を節約する"
+   },
+   "reportissue": {
+      "message": "問題を報告"
+   },
+   "versionnotcompatible": {
+      "message": "Chrome のこのバージョンではこの拡張機能を使用できません。Chrome を最新バージョンに更新してください。サポートされている最初のバージョンは M41 ベータ版です。"
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/kn/messages.json b/chrome/test/data/chromeproxy/extension/_locales/kn/messages.json
new file mode 100644
index 0000000..43a04e60
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/kn/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "ಕುಗ್ಗಿಸಿದ ನಂತರ: \u003Cb>$1 ಬೈಟ್ಸ್\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "ಕುಗ್ಗಿಸಿದ ನಂತರ: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "ಕುಗ್ಗಿಸಿದ ನಂತರ: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "ಕುಗ್ಗಿಸಿದ ನಂತರ: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "ಡೇಟಾ ಉಳಿಸುವಿಕೆ ಆಫ್ ಮಾಡಿ"
+   },
+   "enabledatasaverlabel": {
+      "message": "ಡೇಟಾ ಉಳಿಸುವಿಕೆ ಆನ್ ಮಾಡಿ"
+   },
+   "extdesc": {
+      "message": "ನೀವು ಭೇಟಿ ನೀಡುವ ಪುಟಗಳನ್ನು ಆಪ್ಟಿಮೈಸ್ ಮಾಡಲು Google ಸರ್ವರ್‌ಗಳನ್ನು ಬಳಸುವ ಮೂಲಕ ಡೇಟಾ ಬಳಕೆಯನ್ನು ಕಡಿಮೆ ಮಾಡುತ್ತದೆ."
+   },
+   "extname": {
+      "message": "ಡೇಟಾ ಉಳಿಸುವಿಕೆ"
+   },
+   "extnamebeta": {
+      "message": "ಡೇಟಾ ಉಳಿಸುವಿಕೆ (ಬೀಟಾ)"
+   },
+   "helpandfeedback": {
+      "message": "ಸಹಾಯ ಮತ್ತು ಪ್ರತಿಕ್ರಿಯೆ"
+   },
+   "incognitomessage": {
+      "message": "ಈ ವಿಸ್ತರಣೆಯನ್ನು ಅಜ್ಞಾತ ಮೋಡ್‌ನಲ್ಲಿ ಬಳಸಲಾಗುವುದಿಲ್ಲ."
+   },
+   "info1": {
+      "message": "ನೀವು ಭೇಟಿ ಮಾಡಿದ ಪುಟಗಳನ್ನು ಆಪ್ಟಿಮೈಜ್ ಮಾಡಲು Google ಬಳಸಿಕೊಂಡು ಡೇಟಾಗೆ ಕಡಿಮೆ ವ್ಯಯಿಸಿ."
+   },
+   "info2": {
+      "message": "HTTPS ಅಥವಾ ಅಜ್ಞಾತದಲ್ಲಿ ಪ್ರವೇಶಹೊಂದಿದ ಪುಟಗಳನ್ನು ಆಪ್ಟಿಮೈಜ್ ಮಾಡಲಾಗುವುದಿಲ್ಲ ಅಥವಾ Google ಗೆ ಗೋಚರಿಸುವುದಿಲ್ಲ."
+   },
+   "learnmorelinktext": {
+      "message": "ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"
+   },
+   "originalsizeformat": {
+      "message": "ಮೂಲ ಗಾತ್ರ: \u003Cb>\u003C/b> ಬೈಟ್ಸ್$1",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "ಮೂಲ ಗಾತ್ರ: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "ಮೂಲ ಗಾತ್ರ: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "ಮೂಲ ಗಾತ್ರ: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "ಡೇಟಾ ಬಳಕೆ ಕಡಿಮೆ ಮಾಡಿ"
+   },
+   "reportissue": {
+      "message": "ಸಮಸ್ಯೆ ವರದಿಮಾಡಿ"
+   },
+   "versionnotcompatible": {
+      "message": "ಈ ವಿಸ್ತರಣೆಯ ಜೊತೆಗೆ Chrome ನ ಈ ಆವೃತ್ತಿಯು ಹೊಂದಾಣಿಕೆಯಾಗುವುದಿಲ್ಲ. ದಯವಿಟ್ಟು ಇತ್ತೀಚಿನ ಆವೃತ್ತಿಗೆ Chrome ಅನ್ನು ನವೀಕರಿಸಿ. M41 ಬೀಟಾ ಮೊದಲ ಬೆಂಬಲಿತ ಆವೃತ್ತಿಯಾಗಿದೆ."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ko/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ko/messages.json
new file mode 100644
index 0000000..68819a4c
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ko/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "압축 후: \u003Cb>$1B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "압축 후: \u003Cb>$1GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "압축 후: \u003Cb>$1KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "압축 후: \u003Cb>$1MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "데이터 세이버 사용 중지"
+   },
+   "enabledatasaverlabel": {
+      "message": "데이터 세이버 사용"
+   },
+   "extdesc": {
+      "message": "Google 서버를 통해 방문하는 페이지를 최적화하여 데이터 사용량을 줄이세요."
+   },
+   "extname": {
+      "message": "데이터 세이버"
+   },
+   "extnamebeta": {
+      "message": "데이터 세이버(베타)"
+   },
+   "helpandfeedback": {
+      "message": "도움말 및 의견"
+   },
+   "incognitomessage": {
+      "message": "이 확장 프로그램은 시크릿 모드에서 사용할 수 없습니다."
+   },
+   "info1": {
+      "message": "Google을 사용해 방문하는 페이지를 최적화하여 데이터 사용량을 줄이세요."
+   },
+   "info2": {
+      "message": "HTTPS 또는 시크릿 모드를 통해 액세스된 페이지는 최적화되지 않으며 Google에서 볼 수 없습니다."
+   },
+   "learnmorelinktext": {
+      "message": "자세히 알아보기"
+   },
+   "originalsizeformat": {
+      "message": "원본 크기: \u003Cb>$1B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "원본 크기: \u003Cb>$1GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "원본 크기: \u003Cb>$1KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "원본 크기: \u003Cb>$1MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "데이터 사용량 줄이기"
+   },
+   "reportissue": {
+      "message": "문제 신고"
+   },
+   "versionnotcompatible": {
+      "message": "현재 Chrome 버전은 이 확장 프로그램과 호환되지 않습니다. Chrome을 최신 버전으로 업데이트하세요. M41 베타 버전 이상을 이용해야 합니다."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/lt/messages.json b/chrome/test/data/chromeproxy/extension/_locales/lt/messages.json
new file mode 100644
index 0000000..9988c61
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/lt/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Suglaudinus: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Suglaudinus: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Suglaudinus: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Suglaudinus: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Išjungti Duomenų taupymo priemonę"
+   },
+   "enabledatasaverlabel": {
+      "message": "Įjungti Duomenų taupymo priemonę"
+   },
+   "extdesc": {
+      "message": "Puslapiai optimizuojami naudojant „Google“ serverius, todėl naudojama mažiau duomenų."
+   },
+   "extname": {
+      "message": "Duomenų taupymo priemonė"
+   },
+   "extnamebeta": {
+      "message": "Duomenų taupymo priemonė (beta versija)"
+   },
+   "helpandfeedback": {
+      "message": "Pagalba ir atsiliepimai"
+   },
+   "incognitomessage": {
+      "message": "Plėtinio negalima naudoti inkognito režimu."
+   },
+   "info1": {
+      "message": "Išleiskite mažiau duomenims naudodami „Google“, kad optimizuotumėte puslapius, kuriuose lankotės."
+   },
+   "info2": {
+      "message": "Naudojant HTTPS arba inkognito režimą pasiekti puslapiai nebus optimizuojami ir „Google“ jų nematys."
+   },
+   "learnmorelinktext": {
+      "message": "Sužinokite daugiau"
+   },
+   "originalsizeformat": {
+      "message": "Pradinis dydis: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Pradinis dydis: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Pradinis dydis: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Pradinis dydis: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Duomenų naudojimo mažinimas"
+   },
+   "reportissue": {
+      "message": "Pranešti apie problemą"
+   },
+   "versionnotcompatible": {
+      "message": "Šios versijos „Chrome“ nesuderinama su šiuo plėtiniu. Atnaujinkite „Chrome“ į naujausią versiją. M41 beta versija yra pirmoji palaikoma versija."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/lv/messages.json b/chrome/test/data/chromeproxy/extension/_locales/lv/messages.json
new file mode 100644
index 0000000..4ee5769
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/lv/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Pēc saspiešanas: \u003Cb>$1 baiti\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Pēc saspiešanas: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Pēc saspiešanas: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Pēc saspiešanas: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Izslēgt Datu lietojuma samazinātāju"
+   },
+   "enabledatasaverlabel": {
+      "message": "Ieslēgt Datu lietojuma samazinātāju"
+   },
+   "extdesc": {
+      "message": "Izmantojot Google serverus, samazina datu lietojumu, lai optimizētu apmeklētās lapas."
+   },
+   "extname": {
+      "message": "Datu lietojuma samazinātājs"
+   },
+   "extnamebeta": {
+      "message": "Datu lietojuma samazinātājs (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Palīdzība un atsauksmes"
+   },
+   "incognitomessage": {
+      "message": "Šo paplašinājumu nevar izmantot inkognito režīmā."
+   },
+   "info1": {
+      "message": "Tērējiet mazāk līdzekļu par datu pārraidi, apmeklēto lapu optimizēšanai izmantojot Google."
+   },
+   "info2": {
+      "message": "Lapas, kuru atvēršanai tika izmantots protokols HTTPS vai inkognito režīms, netiks optimizētas, un Google tās nevarēs skatīt."
+   },
+   "learnmorelinktext": {
+      "message": "Uzziniet vairāk"
+   },
+   "originalsizeformat": {
+      "message": "Sākotnējais lielums: \u003Cb>$1 baiti\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Sākotnējais lielums: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Sākotnējais lielums: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Sākotnējais lielums: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Datu lietojuma samazināšana"
+   },
+   "reportissue": {
+      "message": "Ziņot par problēmu"
+   },
+   "versionnotcompatible": {
+      "message": "Izmantotā Chrome versija nav saderīga ar šo paplašinājumu. Lūdzu, atjauniniet pārlūku Chrome uz jaunāko versiju. Pirmā atbalstītā versija ir M41 beta versija."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ml/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ml/messages.json
new file mode 100644
index 0000000..6268eb7e
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ml/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "കംപ്രഷനുശേഷം: \u003Cb>$1 ബൈറ്റുകൾ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "കംപ്രഷനുശേഷം: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "കംപ്രഷനുശേഷം: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "കംപ്രഷനുശേഷം: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "ഡാറ്റ സേവർ ഓഫാക്കുക"
+   },
+   "enabledatasaverlabel": {
+      "message": "ഡാറ്റ സേവർ ഓണാക്കുക"
+   },
+   "extdesc": {
+      "message": "നിങ്ങൾ സന്ദർശിക്കുന്ന പേജുകൾ അനുരൂപമാക്കാൻ Google സെർവറുകൾ ഉപയോഗിച്ച് ഡാറ്റാ ഉപയോഗം കുറയ്‌ക്കുന്നു."
+   },
+   "extname": {
+      "message": "ഡാറ്റ സേവർ"
+   },
+   "extnamebeta": {
+      "message": "ഡാറ്റാ സേവർ (ബീറ്റ)"
+   },
+   "helpandfeedback": {
+      "message": "സഹായവും ഫീഡ്‌ബാക്കും"
+   },
+   "incognitomessage": {
+      "message": "ആൾമാറാട്ട മോഡിൽ ഈ വിപുലീകരണം ഉപയോഗിക്കാനാവില്ല."
+   },
+   "info1": {
+      "message": "നിങ്ങൾ സന്ദർശിക്കുന്ന പേജുകൾ അനുരൂപമാക്കാൻ Google ഉപയോഗിക്കുന്നതിലൂടെ കുറച്ചുമാത്രം ഡാറ്റ ചെലവഴിക്കുക."
+   },
+   "info2": {
+      "message": "HTTPS-ലോ ആൾമാറാട്ടത്തിലോ ആക്‌സസ്സുചെയ്ത പേജുകൾ Google അനുരൂപമാക്കുകയോ കാണുകയോ ചെയ്യില്ല."
+   },
+   "learnmorelinktext": {
+      "message": "കൂടുതലറിയുക"
+   },
+   "originalsizeformat": {
+      "message": "ഒറിജിനൽ വലുപ്പം: \u003Cb>$1 ബൈറ്റുകൾ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "ഒറിജിനൽ വലുപ്പം: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "ഒറിജിനൽ വലുപ്പം: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "ഒറിജിനൽ വലുപ്പം: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "ഡാറ്റ ഉപയോഗം കുറയ്ക്കുക"
+   },
+   "reportissue": {
+      "message": "ഒരു പ്രശ്‌നം റിപ്പോർട്ടുചെയ്യുക"
+   },
+   "versionnotcompatible": {
+      "message": "Chrome-ന്റെ ഈ പതിപ്പ് ഈ വിപുലീകരണത്തിന് അനുയോജ്യമല്ല. ഏറ്റവും പുതിയ പതിപ്പിലേക്ക് Chrome അപ്‌ഡേറ്റുചെയ്യുക. ആദ്യം പിന്തുണയ്ക്കുന്ന പതിപ്പ് M41 ബീറ്റയാണ്."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/mr/messages.json b/chrome/test/data/chromeproxy/extension/_locales/mr/messages.json
new file mode 100644
index 0000000..721d26f
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/mr/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "संक्षेपानंतर: \u003Cb>$1 बाइट\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "संक्षेपानंतर: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "संक्षेपानंतर: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "संक्षेपानंतर: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "डेटा बचतकर्ता बंद करा"
+   },
+   "enabledatasaverlabel": {
+      "message": "डेटा बचतकर्ता चालू करा"
+   },
+   "extdesc": {
+      "message": "आपण भेट देता ती पृष्ठे ऑप्टिमाइझ करण्यासाठी Google सर्व्हर वापरून डेटा वापर कमी करते."
+   },
+   "extname": {
+      "message": "डेटा बचतकर्ता"
+   },
+   "extnamebeta": {
+      "message": "डेटा बचतकर्ता (बीटा)"
+   },
+   "helpandfeedback": {
+      "message": "मदत आणि अभिप्राय"
+   },
+   "incognitomessage": {
+      "message": "हा विस्‍तार गुप्त मोडमध्‍ये वापरला जाऊ शकत नाही."
+   },
+   "info1": {
+      "message": "आपण भेट देता ती पृष्ठे ऑप्टिमाइझ करण्यासाठी Google वापरून डेटावर कमी खर्च करा."
+   },
+   "info2": {
+      "message": "HTTPS किंवा गुप्त सह प्रवेश केलेली पृष्ठे Google द्वारे ऑप्टिमाइझ केली जाणार नाहीत किंवा पाहिली जाणार नाहीत."
+   },
+   "learnmorelinktext": {
+      "message": "अधिक जाणून घ्या"
+   },
+   "originalsizeformat": {
+      "message": "मूळ आकार: \u003Cb>$1 बाइट\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "मूळ आकार: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "मूळ आकार: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "मूळ आकार: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "डेटा वापर कमी करा"
+   },
+   "reportissue": {
+      "message": "समस्येचा अहवाल द्या"
+   },
+   "versionnotcompatible": {
+      "message": "Chrome ची ही आवृत्ती या विस्तारासह सुसंगत नाही. कृपया नवीनतम आवृत्तीवर Chrome अद्यतनित करा. M41 बीटा ही प्रथम समर्थित आवृत्ती आहे."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ms/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ms/messages.json
new file mode 100644
index 0000000..6cc7dda
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ms/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Selepas pemampatan: \u003Cb>$1 bait\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Selepas pemampatan: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Selepas pemampatan: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Selepas pemampatan: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Matikan Penjimat Data"
+   },
+   "enabledatasaverlabel": {
+      "message": "Hidupkan Penjimat Data"
+   },
+   "extdesc": {
+      "message": "Mengurangkan penggunaan data oleh pelayan Google untuk mengoptimumkan halaman yang akan anda lawati."
+   },
+   "extname": {
+      "message": "Penjimat Data"
+   },
+   "extnamebeta": {
+      "message": "Penjimat Data (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Bantuan dan Maklum Balas"
+   },
+   "incognitomessage": {
+      "message": "Sambungan ini tidak boleh digunakan dalam mod inkognito."
+   },
+   "info1": {
+      "message": "Kurangkan penggunaan data dengan menggunakan Google untuk mengoptimumkan halaman yang anda lawati."
+   },
+   "info2": {
+      "message": "Halaman yang telah diakses dengan HTTPS atau Inkognito tidak akan dioptimumkan atau dilihat oleh Google."
+   },
+   "learnmorelinktext": {
+      "message": "Ketahui lebih lanjut"
+   },
+   "originalsizeformat": {
+      "message": "Saiz asal: \u003Cb>$1 bait\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Saiz asal: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Saiz asal: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Saiz asal: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Kurangkan penggunaan data"
+   },
+   "reportissue": {
+      "message": "Laporkan isu"
+   },
+   "versionnotcompatible": {
+      "message": "Versi Chrome ini tidak serasi dengan sambungan ini. Sila kemas kini Chrome kepada versi yang terkini. M41 Beta ialah versi pertama yang disokong."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/nb/messages.json b/chrome/test/data/chromeproxy/extension/_locales/nb/messages.json
new file mode 100644
index 0000000..fedb849
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/nb/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Etter komprimering: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Etter komprimering: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Etter komprimering: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Etter komprimering: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Slå av Datasparing"
+   },
+   "enabledatasaverlabel": {
+      "message": "Slå på Datasparing"
+   },
+   "extdesc": {
+      "message": "Reduserer dataforbruket ved å bruke Google-tjenerne til å optimalisere sidene du besøker."
+   },
+   "extname": {
+      "message": "Datasparing"
+   },
+   "extnamebeta": {
+      "message": "Datasparing (betaversjon)"
+   },
+   "helpandfeedback": {
+      "message": "Hjelp og tilbakemelding"
+   },
+   "incognitomessage": {
+      "message": "Denne utvidelsen kan ikke brukes i inkognitomodus."
+   },
+   "info1": {
+      "message": "Bruk mindre på data ved å la Google optimalisere sidene du besøker."
+   },
+   "info2": {
+      "message": "Sider som åpnes med HTTPS eller i inkognitomodus, blir ikke optimalisert eller sett av Google."
+   },
+   "learnmorelinktext": {
+      "message": "Finn ut mer"
+   },
+   "originalsizeformat": {
+      "message": "Opprinnelig størrelse: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Opprinnelig størrelse: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Opprinnelig størrelse: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Opprinnelig størrelse: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reduser dataforbruket"
+   },
+   "reportissue": {
+      "message": "Rapportér et problem"
+   },
+   "versionnotcompatible": {
+      "message": "Denne versjonen av Chrome er ikke kompatibel med denne utvidelsen. Vennligst oppdater Chrome til den nyeste versjonen. M41 Beta er den første versjonen som støttes."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/nl/messages.json b/chrome/test/data/chromeproxy/extension/_locales/nl/messages.json
new file mode 100644
index 0000000..d0bed8d
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/nl/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Na compressie: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Na compressie: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Na compressie: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Na compressie: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Databesparing uitschakelen"
+   },
+   "enabledatasaverlabel": {
+      "message": "Databesparing inschakelen"
+   },
+   "extdesc": {
+      "message": "Beperkt het gegevensverbruik door Google-servers te gebruiken om pagina's te optimaliseren die je bezoekt."
+   },
+   "extname": {
+      "message": "Databesparing"
+   },
+   "extnamebeta": {
+      "message": "Databesparing (bèta)"
+   },
+   "helpandfeedback": {
+      "message": "Help en feedback"
+   },
+   "incognitomessage": {
+      "message": "Deze extensie kan niet worden gebruikt in de incognitomodus."
+   },
+   "info1": {
+      "message": "Geef minder uit aan dataverkeer door Google te gebruiken om de door jou bezochte pagina's te optimaliseren."
+   },
+   "info2": {
+      "message": "Pagina's die via HTTPS of incognito worden geopend, worden niet geoptimaliseerd of gedetecteerd door Google."
+   },
+   "learnmorelinktext": {
+      "message": "Meer informatie"
+   },
+   "originalsizeformat": {
+      "message": "Oorspronkelijke grootte: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Oorspronkelijke grootte: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Oorspronkelijke grootte: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Oorspronkelijke grootte: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Gegevensgebruik beperken"
+   },
+   "reportissue": {
+      "message": "Een probleem melden"
+   },
+   "versionnotcompatible": {
+      "message": "Deze versie van Chrome is niet compatibel met deze extensie. Update Chrome naar de nieuwste versie. M41 (bèta) is de eerste ondersteunde versie."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/pl/messages.json b/chrome/test/data/chromeproxy/extension/_locales/pl/messages.json
new file mode 100644
index 0000000..8255f3b
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/pl/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Po skompresowaniu: \u003Cb>$1 bajty(ów)\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Po skompresowaniu: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Po skompresowaniu: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Po skompresowaniu: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Wyłącz Oszczędzanie danych"
+   },
+   "enabledatasaverlabel": {
+      "message": "Włącz Oszczędzanie danych"
+   },
+   "extdesc": {
+      "message": "Zmniejsza użycie danych dzięki wykorzystaniu serwerów Google do optymalizowania odwiedzanych stron."
+   },
+   "extname": {
+      "message": "Oszczędzanie danych"
+   },
+   "extnamebeta": {
+      "message": "Oszczędzanie danych (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Pomoc i opinie"
+   },
+   "incognitomessage": {
+      "message": "Z tego rozszerzenia nie można korzystać w trybie incognito."
+   },
+   "info1": {
+      "message": "Wydawaj mniej na przesyłanie danych, używając optymalizowania przeglądanych stron przez Google."
+   },
+   "info2": {
+      "message": "Google nie optymalizuje ani nie widzi stron, z którymi łączysz się przez HTTPS lub które przeglądasz w trybie incognito."
+   },
+   "learnmorelinktext": {
+      "message": "Więcej informacji"
+   },
+   "originalsizeformat": {
+      "message": "Oryginalny rozmiar: \u003Cb>$1 bajty(ów)\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Oryginalny rozmiar: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Oryginalny rozmiar: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Oryginalny rozmiar: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Ogranicz ilość danych"
+   },
+   "reportissue": {
+      "message": "Zgłoś problem"
+   },
+   "versionnotcompatible": {
+      "message": "Ta wersja Chrome jest niezgodna z tym rozszerzeniem. Zaktualizuj Chrome do najnowszej wersji. Pierwsza obsługiwana wersja to M41 Beta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/pt/messages.json b/chrome/test/data/chromeproxy/extension/_locales/pt/messages.json
new file mode 100644
index 0000000..a997981
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/pt/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Depois da compactação: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Depois da compactação: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Depois da compactação: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Depois da compactação: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Desativar Economia de dados"
+   },
+   "enabledatasaverlabel": {
+      "message": "Ativar Economia de dados"
+   },
+   "extdesc": {
+      "message": "Reduz o uso de dados usando os servidores do Google para otimizar as páginas visitadas."
+   },
+   "extname": {
+      "message": "Economia de dados"
+   },
+   "extnamebeta": {
+      "message": "Economia de dados (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Ajuda e feedback"
+   },
+   "incognitomessage": {
+      "message": "Não é possível usar esta extensão no modo de navegação anônima."
+   },
+   "info1": {
+      "message": "Gaste menos em dados usando o Google para otimizar as páginas que você visita."
+   },
+   "info2": {
+      "message": "Páginas acessadas com HTTPS ou no modo de navegação anônima não são otimizadas ou vistas pelo Google."
+   },
+   "learnmorelinktext": {
+      "message": "Saiba mais"
+   },
+   "originalsizeformat": {
+      "message": "Tamanho original: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Tamanho original: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Tamanho original: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Tamanho original: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reduzir uso de dados"
+   },
+   "reportissue": {
+      "message": "Informar um problema"
+   },
+   "versionnotcompatible": {
+      "message": "Esta versão do Google Chrome não é compatível com esta extensão. Atualize o Chrome para a versão mais recente. M41 Beta é a primeira versão compatível."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/pt_BR/messages.json b/chrome/test/data/chromeproxy/extension/_locales/pt_BR/messages.json
new file mode 100644
index 0000000..a997981
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/pt_BR/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Depois da compactação: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Depois da compactação: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Depois da compactação: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Depois da compactação: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Desativar Economia de dados"
+   },
+   "enabledatasaverlabel": {
+      "message": "Ativar Economia de dados"
+   },
+   "extdesc": {
+      "message": "Reduz o uso de dados usando os servidores do Google para otimizar as páginas visitadas."
+   },
+   "extname": {
+      "message": "Economia de dados"
+   },
+   "extnamebeta": {
+      "message": "Economia de dados (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Ajuda e feedback"
+   },
+   "incognitomessage": {
+      "message": "Não é possível usar esta extensão no modo de navegação anônima."
+   },
+   "info1": {
+      "message": "Gaste menos em dados usando o Google para otimizar as páginas que você visita."
+   },
+   "info2": {
+      "message": "Páginas acessadas com HTTPS ou no modo de navegação anônima não são otimizadas ou vistas pelo Google."
+   },
+   "learnmorelinktext": {
+      "message": "Saiba mais"
+   },
+   "originalsizeformat": {
+      "message": "Tamanho original: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Tamanho original: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Tamanho original: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Tamanho original: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reduzir uso de dados"
+   },
+   "reportissue": {
+      "message": "Informar um problema"
+   },
+   "versionnotcompatible": {
+      "message": "Esta versão do Google Chrome não é compatível com esta extensão. Atualize o Chrome para a versão mais recente. M41 Beta é a primeira versão compatível."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/pt_PT/messages.json b/chrome/test/data/chromeproxy/extension/_locales/pt_PT/messages.json
new file mode 100644
index 0000000..080b888
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/pt_PT/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Após a compressão: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Após a compressão: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Após a compressão: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Após a compressão: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Desativar Poupança de dados"
+   },
+   "enabledatasaverlabel": {
+      "message": "Ativar Poupança de dados"
+   },
+   "extdesc": {
+      "message": "Reduz a utilização de dados ao utilizar os servidores da Google para otimizar as páginas que visita."
+   },
+   "extname": {
+      "message": "Poupança de dados"
+   },
+   "extnamebeta": {
+      "message": "Poupança de dados (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Ajuda e comentários"
+   },
+   "incognitomessage": {
+      "message": "Não é possível utilizar esta extensão no modo de navegação anónima."
+   },
+   "info1": {
+      "message": "Gaste menos em dados ao utilizar o Google para otimizar as páginas que visita."
+   },
+   "info2": {
+      "message": "As páginas acedidas com HTTPS ou no modo de navegação anónima não são otimizadas ou vistas pelo Google."
+   },
+   "learnmorelinktext": {
+      "message": "Saiba mais"
+   },
+   "originalsizeformat": {
+      "message": "Tamanho original: \u003Cb>$1 bytes\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Tamanho original: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Tamanho original: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Tamanho original: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Reduzir utilização de dados"
+   },
+   "reportissue": {
+      "message": "Comunicar um problema"
+   },
+   "versionnotcompatible": {
+      "message": "Esta versão do Chrome não é compatível com esta extensão. Atualize o Chrome para a versão mais recente. A primeira versão suportada é a M41 Beta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ro/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ro/messages.json
new file mode 100644
index 0000000..788ffd0
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ro/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "După comprimare: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "După comprimare: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "După comprimare: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "După comprimare: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Dezactivează Economizorul de date"
+   },
+   "enabledatasaverlabel": {
+      "message": "Activează Economizorul de date"
+   },
+   "extdesc": {
+      "message": "Reduce utilizarea de date folosind serverele Google pentru a optimiza paginile pe care le accesezi."
+   },
+   "extname": {
+      "message": "Economizor de date"
+   },
+   "extnamebeta": {
+      "message": "Economizor de date (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Ajutor și feedback"
+   },
+   "incognitomessage": {
+      "message": "Extensia nu poate fi folosită în modul incognito."
+   },
+   "info1": {
+      "message": "Reduce volumul de date transferat optimizând cu Google paginile accesate."
+   },
+   "info2": {
+      "message": "Google nu va vedea și nu va optimiza paginile accesate prin HTTPS sau incognito."
+   },
+   "learnmorelinktext": {
+      "message": "Află mai multe"
+   },
+   "originalsizeformat": {
+      "message": "Dimensiune inițială: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Dimensiune inițială: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Dimensiune inițială: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Dimensiune inițială: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Redu utilizarea datelor"
+   },
+   "reportissue": {
+      "message": "Raportează o problemă"
+   },
+   "versionnotcompatible": {
+      "message": "Versiunea Chrome nu este compatibilă cu această extensie. Actualizează la cea mai recentă versiune Chrome. M41 Beta este prima versiune compatibilă."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ru/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ru/messages.json
new file mode 100644
index 0000000..e54ed72
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ru/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "После сжатия: \u003Cb>$1 Б\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "После сжатия: \u003Cb>$1 ГБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "После сжатия: \u003Cb>$1 КБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "После сжатия: \u003Cb>$1 МБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Отключить режим экономии трафика"
+   },
+   "enabledatasaverlabel": {
+      "message": "Включить режим экономии трафика"
+   },
+   "extdesc": {
+      "message": "Сокращает трафик, получаемый при загрузке страниц, с помощью серверов Google. Не работает с HTTPS-запросами и в режиме инкогнито."
+   },
+   "extname": {
+      "message": "Экономия трафика"
+   },
+   "extnamebeta": {
+      "message": "Экономия трафика (бета)"
+   },
+   "helpandfeedback": {
+      "message": "Прочитать справку или оставить отзыв"
+   },
+   "incognitomessage": {
+      "message": "Это расширение не работает в режиме инкогнито."
+   },
+   "info1": {
+      "message": "Экономьте на трафике, разрешая Google оптимизировать посещаемые страницы."
+   },
+   "info2": {
+      "message": "Нам недоступны страницы, открытые через HTTPS или в режиме инкогнито, поэтому их нельзя оптимизировать."
+   },
+   "learnmorelinktext": {
+      "message": "Подробнее..."
+   },
+   "originalsizeformat": {
+      "message": "Исходный размер: \u003Cb>$1 Б\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Исходный размер: \u003Cb>$1 ГБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Исходный размер: \u003Cb>$1 КБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Исходный размер: \u003Cb>$1 МБ\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Оптимизация трафика"
+   },
+   "reportissue": {
+      "message": "Сообщить о проблеме"
+   },
+   "versionnotcompatible": {
+      "message": "Установленная версия Chrome не совместима с этим расширением. Обновите браузер до версии M41 Beta или старше."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/sk/messages.json b/chrome/test/data/chromeproxy/extension/_locales/sk/messages.json
new file mode 100644
index 0000000..ab8ad81
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/sk/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Po kompresii: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Po kompresii: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Po kompresii: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Po kompresii: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Vypnúť Šetrič dát"
+   },
+   "enabledatasaverlabel": {
+      "message": "Zapnúť Šetrič dát"
+   },
+   "extdesc": {
+      "message": "Znižuje spotrebu dát tak, že pomocou severov Google optimalizuje stránky, ktoré navštívite."
+   },
+   "extname": {
+      "message": "Šetrič dát"
+   },
+   "extnamebeta": {
+      "message": "Šetrič dát (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Pomocník a spätná väzba"
+   },
+   "incognitomessage": {
+      "message": "Toto rozšírenie nie je možné použiť v režime inkognito."
+   },
+   "info1": {
+      "message": "Využite službu Google na optimalizáciu navštívených stránok a ušetrite za dátové pripojenie."
+   },
+   "info2": {
+      "message": "Google neoptimalizuje ani nerozpozná stránky, ku ktorým pristupujete prostredníctvom protokolu HTTPS alebo v režime inkognito."
+   },
+   "learnmorelinktext": {
+      "message": "Viac informácií"
+   },
+   "originalsizeformat": {
+      "message": "Pôvodná veľkosť: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Pôvodná veľkosť: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Pôvodná veľkosť: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Pôvodná veľkosť: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Znížiť využitie dát"
+   },
+   "reportissue": {
+      "message": "Nahlásiť problém"
+   },
+   "versionnotcompatible": {
+      "message": "Táto verzia prehliadača Chrome nie je kompatibilná s týmto rozšírením. Aktualizujte prehliadač Chrome na najnovšiu verziu. Najnižšia podporovaná verzia je M41 Beta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/sl/messages.json b/chrome/test/data/chromeproxy/extension/_locales/sl/messages.json
new file mode 100644
index 0000000..a07867ff
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/sl/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Po stiskanju: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Po stiskanju: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Po stiskanju: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Po stiskanju: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Izklop varčevanja s podatki"
+   },
+   "enabledatasaverlabel": {
+      "message": "Vklop varčevanja s podatki"
+   },
+   "extdesc": {
+      "message": "Zmanjša porabo podatkov z uporabo Googlovih strežnikov za optimizacijo strani, ki jih obiskujete."
+   },
+   "extname": {
+      "message": "Varčevanje s podatki"
+   },
+   "extnamebeta": {
+      "message": "Varčevanje s podatki (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Pomoč in povratne informacije"
+   },
+   "incognitomessage": {
+      "message": "To razširitve ni mogoče uporabiti v načinu brez beleženja zgodovine."
+   },
+   "info1": {
+      "message": "Uporabljajte Google za optimiziranje strani, ki jih obiščete, in tako porabite manj podatkov."
+   },
+   "info2": {
+      "message": "Google ne optimizira in ne vidi strani, odprtih prek protokola HTTPS ali v načinu brez beleženja zgodovine."
+   },
+   "learnmorelinktext": {
+      "message": "Več o tem"
+   },
+   "originalsizeformat": {
+      "message": "Prvotna velikost: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Prvotna velikost: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Prvotna velikost: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Prvotna velikost: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Manjša poraba podatkov"
+   },
+   "reportissue": {
+      "message": "Prijava težave"
+   },
+   "versionnotcompatible": {
+      "message": "Ta različica Chroma ni združljiva s to razširitvijo. Posodobite Chrome na najnovejšo različico. Prva podprta različica je M41 Beta."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/sr/messages.json b/chrome/test/data/chromeproxy/extension/_locales/sr/messages.json
new file mode 100644
index 0000000..53cdca3
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/sr/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "После компримовања: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "После компримовања: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "После компримовања: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "После компримовања: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Искључи Уштеду података"
+   },
+   "enabledatasaverlabel": {
+      "message": "Укључи Уштеду података"
+   },
+   "extdesc": {
+      "message": "Смањује потрошњу података помоћу Google сервера за оптимизацију страница које посећујете."
+   },
+   "extname": {
+      "message": "Уштеда података"
+   },
+   "extnamebeta": {
+      "message": "Уштеда података (бета)"
+   },
+   "helpandfeedback": {
+      "message": "Помоћ и повратне информације"
+   },
+   "incognitomessage": {
+      "message": "Овај додатак не може да се користи у режиму без архивирања."
+   },
+   "info1": {
+      "message": "Трошите мање на податке тако што ћете користити Google за оптимизацију страница које посећујете."
+   },
+   "info2": {
+      "message": "Google неће оптимизовати нити видети странице којима се приступа помоћу HTTPS-а или у режиму без архивирања."
+   },
+   "learnmorelinktext": {
+      "message": "Сазнајте више"
+   },
+   "originalsizeformat": {
+      "message": "Оригинална величина: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Оригинална величина: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Оригинална величина: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Оригинална величина: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Смањење потрошње података"
+   },
+   "reportissue": {
+      "message": "Пријави проблем"
+   },
+   "versionnotcompatible": {
+      "message": "Ова верзија Chrome-а није компатибилна са овим додатком. Ажурирајте Chrome на најновију верзију. M41 Beta је прва подржана верзија."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/sr_Latn/messages.json b/chrome/test/data/chromeproxy/extension/_locales/sr_Latn/messages.json
new file mode 100644
index 0000000..79b950f
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/sr_Latn/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Posle komprimovanja: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Posle komprimovanja: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Posle komprimovanja: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Posle komprimovanja: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Isključi Uštedu podataka"
+   },
+   "enabledatasaverlabel": {
+      "message": "Uključi Uštedu podataka"
+   },
+   "extdesc": {
+      "message": "Smanjuje potrošnju podataka pomoću Google servera za optimizaciju stranica koje posećujete."
+   },
+   "extname": {
+      "message": "Ušteda podataka"
+   },
+   "extnamebeta": {
+      "message": "Ušteda podataka (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Pomoć i povratne informacije"
+   },
+   "incognitomessage": {
+      "message": "Ovaj dodatak ne može da se koristi u režimu bez arhiviranja."
+   },
+   "info1": {
+      "message": "Trošite manje na podatke tako što ćete koristiti Google za optimizaciju stranica koje posećujete."
+   },
+   "info2": {
+      "message": "Google neće optimizovati niti videti stranice kojima se pristupa pomoću HTTPS-a ili u režimu bez arhiviranja."
+   },
+   "learnmorelinktext": {
+      "message": "Saznajte više"
+   },
+   "originalsizeformat": {
+      "message": "Originalna veličina: \u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Originalna veličina: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Originalna veličina: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Originalna veličina: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Smanjenje potrošnje podataka"
+   },
+   "reportissue": {
+      "message": "Prijavi problem"
+   },
+   "versionnotcompatible": {
+      "message": "Ova verzija Chrome-a nije kompatibilna sa ovim dodatkom. Ažurirajte Chrome na najnoviju verziju. M41 Beta je prva podržana verzija."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/sv/messages.json b/chrome/test/data/chromeproxy/extension/_locales/sv/messages.json
new file mode 100644
index 0000000..c31d1645
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/sv/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Efter komprimering: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Efter komprimering: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Efter komprimering: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Efter komprimering: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1 %",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Inaktivera Databesparing"
+   },
+   "enabledatasaverlabel": {
+      "message": "Aktivera Databesparing"
+   },
+   "extdesc": {
+      "message": "Minskar dataanvändningen genom att använda Googles servrar för att optimera sidorna som du besöker."
+   },
+   "extname": {
+      "message": "Databesparing"
+   },
+   "extnamebeta": {
+      "message": "Databesparing (beta)"
+   },
+   "helpandfeedback": {
+      "message": "Hjälp och feedback"
+   },
+   "incognitomessage": {
+      "message": "Det här tillägget kan inte användas i inkognitoläge."
+   },
+   "info1": {
+      "message": "Minska datakostnaderna genom att låta Google optimera sidorna du besöker."
+   },
+   "info2": {
+      "message": "Google varken optimerar eller ser sidor som öppnas med HTTPS eller i inkognitoläge."
+   },
+   "learnmorelinktext": {
+      "message": "Läs mer"
+   },
+   "originalsizeformat": {
+      "message": "Originalstorlek: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Originalstorlek: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Originalstorlek: \u003Cb>$1 kB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Originalstorlek: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Minska dataanvändning"
+   },
+   "reportissue": {
+      "message": "Rapportera ett problem"
+   },
+   "versionnotcompatible": {
+      "message": "Den här versionen av Chrome är inte kompatibel med tillägget. Uppdatera Chrome till den senaste versionen. M41 Beta är den första versionen som stöds."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/sw/messages.json b/chrome/test/data/chromeproxy/extension/_locales/sw/messages.json
new file mode 100644
index 0000000..808e0d8
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/sw/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Baada ya kushindiliwa: \u003Cb>baiti $1 \u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Baada ya kushindiliwa: \u003Cb>GB $1 \u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Baada ya kushindiliwa: \u003Cb>KB $1 \u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Baada ya kushindiliwa: \u003Cb>MB $1 \u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Zima Kiokoa Data"
+   },
+   "enabledatasaverlabel": {
+      "message": "Washa Kiokoa Data"
+   },
+   "extdesc": {
+      "message": "Hupunguza matumizi ya data kwa kutumia seva za Google kuboresha kurasa unazotembelea."
+   },
+   "extname": {
+      "message": "Kiokoa Data"
+   },
+   "extnamebeta": {
+      "message": "Kiokoa Data (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Usaidizi na Maoni"
+   },
+   "incognitomessage": {
+      "message": "Kiendelezi hiki hakiwezi kutumiwa katika hali fiche."
+   },
+   "info1": {
+      "message": "Tumia hela chache kununua data kwa kutumia Google ili kuboresha kurasa unazotembelea."
+   },
+   "info2": {
+      "message": "Kurasa zilizofikiwa kwa HTTPS au Hali Fiche hazitaboreshwa au kuonekana na Google."
+   },
+   "learnmorelinktext": {
+      "message": "Pata maelezo zaidi"
+   },
+   "originalsizeformat": {
+      "message": "Ukubwa asili: \u003Cb>baiti $1 \u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Ukubwa asili: \u003Cb>GB $1 \u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Ukubwa asili: \u003Cb>KB $1 \u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Ukubwa asili: \u003Cb>MB $1 \u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Punguza kiasi cha data unachotumia"
+   },
+   "reportissue": {
+      "message": "Ripoti tatizo"
+   },
+   "versionnotcompatible": {
+      "message": "Toleo hili la Chrome halitumiwi pamoja na kiendelezi hiki. Tafadhali pata toleo jipya la Chrome. M41 Beta ni toleo la kwanza linalotumika."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/ta/messages.json b/chrome/test/data/chromeproxy/extension/_locales/ta/messages.json
new file mode 100644
index 0000000..dbc6ccc
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/ta/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "சுருக்கிய பிறகு: \u003Cb>$1 பைட்டுகள்\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "சுருக்கிய பிறகு: \u003Cb>$1 ஜி.பை.\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "சுருக்கிய பிறகு: \u003Cb>$1 கி.பை.\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "சுருக்கிய பிறகு: \u003Cb>$1 மெ.பை.\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "தரவுச் சேமிப்பானை முடக்கு"
+   },
+   "enabledatasaverlabel": {
+      "message": "தரவுச் சேமிப்பானை இயக்கு"
+   },
+   "extdesc": {
+      "message": "நீங்கள் பார்வையிடும் பக்கங்களை Google சேவையகங்களைப் பயன்படுத்தி உகந்ததாக்குவதன் மூலம் தரவுப் பயன்பாட்டைக் குறைக்கும்."
+   },
+   "extname": {
+      "message": "தரவு சேமிப்பான்"
+   },
+   "extnamebeta": {
+      "message": "தரவு சேமிப்பான் (பீட்டா)"
+   },
+   "helpandfeedback": {
+      "message": "உதவி மற்றும் கருத்து"
+   },
+   "incognitomessage": {
+      "message": "இந்த நீட்டிப்பை மறைநிலையில் பயன்படுத்த முடியாது."
+   },
+   "info1": {
+      "message": "நீங்கள் பார்வையிடும் பக்கங்களை உகப்பாக்க Googleஐப் பயன்படுத்துவதன் மூலம், தரவைக் குறைவாகச் செலவழிக்கலாம்."
+   },
+   "info2": {
+      "message": "HTTPS அல்லது மறைநிலை மூலம் அணுகப்படும் பக்கங்களை Google ஆல் மேம்படுத்த அல்லது பார்க்க முடியாது."
+   },
+   "learnmorelinktext": {
+      "message": "மேலும் அறிக"
+   },
+   "originalsizeformat": {
+      "message": "அசல் அளவு: \u003Cb>$1 பைட்டுகள்\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "அசல் அளவு: \u003Cb>$1 ஜி.பை.\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "அசல் அளவு: \u003Cb>$1 கி.பை.\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "அசல் அளவு: \u003Cb>$1 மெ.பை.\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "தரவுப் பயன்பாட்டைக் குறை"
+   },
+   "reportissue": {
+      "message": "சிக்கலைப் புகாரளி"
+   },
+   "versionnotcompatible": {
+      "message": "இந்த நீட்டிப்புடன் Chrome இன் இந்தப் பதிப்பு இணக்கமற்றது. சமீபத்திய Chrome பதிப்பிற்குப் புதுப்பிக்கவும். M41 பீட்டா என்பதே இதை ஆதரிக்கும் முதல் பதிப்பாகும்."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/te/messages.json b/chrome/test/data/chromeproxy/extension/_locales/te/messages.json
new file mode 100644
index 0000000..9574f01
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/te/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "కుదింపు తర్వాత: \u003Cb>$1 బైట్‌లు\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "కుదింపు తర్వాత: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "కుదింపు తర్వాత: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "కుదింపు తర్వాత: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "డేటా సేవర్‌ని ఆఫ్ చేయి"
+   },
+   "enabledatasaverlabel": {
+      "message": "డేటా సేవర్‌ని ఆన్ చేయి"
+   },
+   "extdesc": {
+      "message": "మీరు సందర్శించే పేజీలను అనుకూలపరచడానికి Google సర్వర్‌లను ఉపయోగించడం ద్వారా డేటా వినియోగాన్ని తగ్గిస్తుంది."
+   },
+   "extname": {
+      "message": "డేటా సేవర్"
+   },
+   "extnamebeta": {
+      "message": "డేటా సేవర్ (బీటా)"
+   },
+   "helpandfeedback": {
+      "message": "సహాయం మరియు అభిప్రాయం"
+   },
+   "incognitomessage": {
+      "message": "ఈ పొడిగింపుని అజ్ఞాత మోడ్‌లో ఉపయోగించలేరు."
+   },
+   "info1": {
+      "message": "మీరు సందర్శించే పేజీలను అనుకూలీకరించడానికి Googleని ఉపయోగించడం ద్వారా డేటా వినియోగం తగ్గించండి."
+   },
+   "info2": {
+      "message": "HTTPSతో లేదా అజ్ఞాతంగా ప్రాప్యత చేసే పేజీలను Google అనుకూలీకరించలేదు లేదా చూడలేదు."
+   },
+   "learnmorelinktext": {
+      "message": "మరింత తెలుసుకోండి"
+   },
+   "originalsizeformat": {
+      "message": "అసలు పరిమాణం: \u003Cb>$1 బైట్‌లు\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "అసలు పరిమాణం: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "అసలు పరిమాణం: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "అసలు పరిమాణం: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "డేటా వినియోగాన్ని తగ్గించండి"
+   },
+   "reportissue": {
+      "message": "సమస్యను నివేదించండి"
+   },
+   "versionnotcompatible": {
+      "message": "ఈ Chrome సంస్కరణ ఈ పొడిగింపుకి అనుకూలంగా లేదు. దయచేసి Chromeని తాజా సంస్కరణకి నవీకరించండి. M41 బీటా మద్దతు గల మొదటి సంస్కరణ."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/th/messages.json b/chrome/test/data/chromeproxy/extension/_locales/th/messages.json
new file mode 100644
index 0000000..9b8157f3
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/th/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "หลังการบีบอัด: \u003Cb>$1 ไบต์\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "หลังการบีบอัด: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "หลังการบีบอัด: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "หลังการบีบอัด: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "ปิดโปรแกรมประหยัดอินเทอร์เน็ต"
+   },
+   "enabledatasaverlabel": {
+      "message": "เปิดโปรแกรมประหยัดอินเทอร์เน็ต"
+   },
+   "extdesc": {
+      "message": "ลดการใช้ข้อมูลโดยให้เซิร์ฟเวอร์ Google เพิ่มประสิทธิภาพให้กับหน้าที่คุณเข้าชม"
+   },
+   "extname": {
+      "message": "โปรแกรมประหยัดอินเทอร์เน็ต"
+   },
+   "extnamebeta": {
+      "message": "โปรแกรมประหยัดอินเทอร์เน็ต (เบต้า)"
+   },
+   "helpandfeedback": {
+      "message": "ความช่วยเหลือและความคิดเห็น"
+   },
+   "incognitomessage": {
+      "message": "ไม่สามารถใช้ส่วนขยายนี้ในโหมดไม่ระบุตัวตน"
+   },
+   "info1": {
+      "message": "ใช้ข้อมูลน้อยลงโดยใช้ Google เพื่อเพิ่มประสิทธิภาพหน้าที่คุณเข้าชม"
+   },
+   "info2": {
+      "message": "Google จะไม่เห็นและจะไม่มีการเพิ่มประสิทธิภาพหน้าที่เข้าถึงด้วย HTTPS หรือโหมดไม่ระบุตัวตน"
+   },
+   "learnmorelinktext": {
+      "message": "เรียนรู้เพิ่มเติม"
+   },
+   "originalsizeformat": {
+      "message": "ขนาดเดิม: \u003Cb>$1 ไบต์\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "ขนาดเดิม: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "ขนาดเดิม: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "ขนาดเดิม: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "ลดการใช้อินเทอร์เน็ต"
+   },
+   "reportissue": {
+      "message": "รายงานปัญหา"
+   },
+   "versionnotcompatible": {
+      "message": "Chrome เวอร์ชันนี้ไม่สามารถใช้ร่วมกับส่วนขยายนี้ โปรดอัปเดต Chrome ให้เป็นเวอร์ชันล่าสุด M41 เบต้าคือเวอร์ชันแรกที่ได้รับการสนับสนุน"
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/tr/messages.json b/chrome/test/data/chromeproxy/extension/_locales/tr/messages.json
new file mode 100644
index 0000000..92420f1
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/tr/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Sıkıştırmadan sonra: \u003Cb>$1 bayt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Sıkıştırmadan sonra: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Sıkıştırmadan sonra: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Sıkıştırmadan sonra: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "%$1",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Veri Tasarrufu'nu Kapat"
+   },
+   "enabledatasaverlabel": {
+      "message": "Veri Tasarrufu'nu Aç"
+   },
+   "extdesc": {
+      "message": "Ziyaret ettiğiniz sayfaları optimize etmek için Google sunucularını kullanarak veri kullanımını azaltır."
+   },
+   "extname": {
+      "message": "Veri Tasarrufu"
+   },
+   "extnamebeta": {
+      "message": "Veri Tasarrufu (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Yardım ve Geri Bildirim"
+   },
+   "incognitomessage": {
+      "message": "Bu uzantı, gizli modda kullanılamaz."
+   },
+   "info1": {
+      "message": "Ziyaret ettiğiniz sayfaları optimize etmek için Google'ı kullanarak daha az veri harcayın."
+   },
+   "info2": {
+      "message": "HTTPS veya gizli modla erişilen sayfalar Google tarafından optimize edilmez veya görülmez."
+   },
+   "learnmorelinktext": {
+      "message": "Daha fazla bilgi edinin"
+   },
+   "originalsizeformat": {
+      "message": "Orijinal boyut: \u003Cb>$1 bayt\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Orijinal boyut: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Orijinal boyut: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Orijinal boyut: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Veri kullanımını azalt"
+   },
+   "reportissue": {
+      "message": "Sorun bildir"
+   },
+   "versionnotcompatible": {
+      "message": "Chrome'un bu sürümü bu uzantıyla uyumlu değil. Lütfen Chrome'u son sürüme güncelleyin. M41 Beta, desteklenen ilk sürümdür."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/uk/messages.json b/chrome/test/data/chromeproxy/extension/_locales/uk/messages.json
new file mode 100644
index 0000000..f83d662
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/uk/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Після стиснення: \u003Cb>$1 б\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Після стиснення: \u003Cb>$1 Гб\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Після стиснення: \u003Cb>$1 Кб\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Після стиснення: \u003Cb>$1 Мб\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Вимкнути режим заощадження трафіку"
+   },
+   "enabledatasaverlabel": {
+      "message": "Увімкнути режим заощадження трафіку"
+   },
+   "extdesc": {
+      "message": "Оптимізує сторінки на серверах Google, щоб зменшити трафік."
+   },
+   "extname": {
+      "message": "Заощадження трафіку"
+   },
+   "extnamebeta": {
+      "message": "Заощадження трафіку (бета-версія)"
+   },
+   "helpandfeedback": {
+      "message": "Довідка й відгуки"
+   },
+   "incognitomessage": {
+      "message": "Це розширення не можна використовувати в режимі анонімного перегляду."
+   },
+   "info1": {
+      "message": "Google оптимізує сторінки, які ви відвідуєте, і ви економите трафік."
+   },
+   "info2": {
+      "message": "Google не зможе оптимізувати чи бачити сторінки, які відкриваються через HTTPS або в режимі анонімного перегляду."
+   },
+   "learnmorelinktext": {
+      "message": "Докладніше"
+   },
+   "originalsizeformat": {
+      "message": "Початковий розмір: \u003Cb>$1 б\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Початковий розмір: \u003Cb>$1 Гб\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Початковий розмір: \u003Cb>$1 Кб\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Початковий розмір: \u003Cb>$1 Мб\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Зменшення використання трафіку"
+   },
+   "reportissue": {
+      "message": "Повідомити про проблему"
+   },
+   "versionnotcompatible": {
+      "message": "Ваша версія Chrome несумісна з цим розширенням. Установіть останню версію Chrome. Перша сумісна версія – M41 (бета-версія)."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/vi/messages.json b/chrome/test/data/chromeproxy/extension/_locales/vi/messages.json
new file mode 100644
index 0000000..693d2a9
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/vi/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "Sau khi nén: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "Sau khi nén: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "Sau khi nén: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "Sau khi nén: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "Tắt Trình tiết kiệm dữ liệu"
+   },
+   "enabledatasaverlabel": {
+      "message": "Bật Trình tiết kiệm dữ liệu"
+   },
+   "extdesc": {
+      "message": "Giảm mức sử dụng dữ liệu bằng cách sử dụng máy chủ của Google để tối ưu hóa các trang bạn truy cập."
+   },
+   "extname": {
+      "message": "Trình tiết kiệm dữ liệu"
+   },
+   "extnamebeta": {
+      "message": "Trình tiết kiệm dữ liệu (Beta)"
+   },
+   "helpandfeedback": {
+      "message": "Trợ giúp và phản hồi"
+   },
+   "incognitomessage": {
+      "message": "Không sử dụng được tiện ích này trong chế độ ẩn danh."
+   },
+   "info1": {
+      "message": "Dùng ít dữ liệu hơn bằng cách dùng Google để tối ưu hóa các trang bạn truy cập."
+   },
+   "info2": {
+      "message": "Google sẽ không tối ưu hóa hoặc thấy các trang được truy cập bằng HTTPS hoặc Chế độ ẩn danh."
+   },
+   "learnmorelinktext": {
+      "message": "Tìm hiểu thêm"
+   },
+   "originalsizeformat": {
+      "message": "Kích thước ban đầu: \u003Cb>$1 byte\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "Kích thước ban đầu: \u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "Kích thước ban đầu: \u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "Kích thước ban đầu: \u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "Giảm mức sử dụng dữ liệu"
+   },
+   "reportissue": {
+      "message": "Báo cáo sự cố"
+   },
+   "versionnotcompatible": {
+      "message": "Phiên bản Chrome này không tương thích với tiện ích này. Vui lòng cập nhật Chrome lên phiên bản mới nhất. M41 Beta là phiên bản được hỗ trợ đầu tiên."
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/zh/messages.json b/chrome/test/data/chromeproxy/extension/_locales/zh/messages.json
new file mode 100644
index 0000000..db7c942
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/zh/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "压缩后:\u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "压缩后:\u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "压缩后:\u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "压缩后:\u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "关闭流量节省程序"
+   },
+   "enabledatasaverlabel": {
+      "message": "开启流量节省程序"
+   },
+   "extdesc": {
+      "message": "使用 Google 服务器优化您访问的网页,从而减少数据流量消耗。"
+   },
+   "extname": {
+      "message": "流量节省程序"
+   },
+   "extnamebeta": {
+      "message": "流量节省程序(测试版)"
+   },
+   "helpandfeedback": {
+      "message": "帮助和反馈"
+   },
+   "incognitomessage": {
+      "message": "在隐身模式下无法使用此扩展程序。"
+   },
+   "info1": {
+      "message": "让 Google 帮您优化所访问的网页,减少流量消耗。"
+   },
+   "info2": {
+      "message": "Google 不会优化(也看不到)采用 HTTPS 协议或以隐身模式访问的网页。"
+   },
+   "learnmorelinktext": {
+      "message": "了解详情"
+   },
+   "originalsizeformat": {
+      "message": "原始大小:\u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "原始大小:\u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "原始大小:\u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "原始大小:\u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "减少流量消耗"
+   },
+   "reportissue": {
+      "message": "报告问题"
+   },
+   "versionnotcompatible": {
+      "message": "该版本的 Chrome 与此扩展程序不兼容。请将 Chrome 更新至最新版本。受支持的最低版本是 M41 Beta 版。"
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/zh_CN/messages.json b/chrome/test/data/chromeproxy/extension/_locales/zh_CN/messages.json
new file mode 100644
index 0000000..db7c942
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/zh_CN/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "压缩后:\u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "压缩后:\u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "压缩后:\u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "压缩后:\u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "关闭流量节省程序"
+   },
+   "enabledatasaverlabel": {
+      "message": "开启流量节省程序"
+   },
+   "extdesc": {
+      "message": "使用 Google 服务器优化您访问的网页,从而减少数据流量消耗。"
+   },
+   "extname": {
+      "message": "流量节省程序"
+   },
+   "extnamebeta": {
+      "message": "流量节省程序(测试版)"
+   },
+   "helpandfeedback": {
+      "message": "帮助和反馈"
+   },
+   "incognitomessage": {
+      "message": "在隐身模式下无法使用此扩展程序。"
+   },
+   "info1": {
+      "message": "让 Google 帮您优化所访问的网页,减少流量消耗。"
+   },
+   "info2": {
+      "message": "Google 不会优化(也看不到)采用 HTTPS 协议或以隐身模式访问的网页。"
+   },
+   "learnmorelinktext": {
+      "message": "了解详情"
+   },
+   "originalsizeformat": {
+      "message": "原始大小:\u003Cb>$1 B\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "原始大小:\u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "原始大小:\u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "原始大小:\u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "减少流量消耗"
+   },
+   "reportissue": {
+      "message": "报告问题"
+   },
+   "versionnotcompatible": {
+      "message": "该版本的 Chrome 与此扩展程序不兼容。请将 Chrome 更新至最新版本。受支持的最低版本是 M41 Beta 版。"
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_locales/zh_TW/messages.json b/chrome/test/data/chromeproxy/extension/_locales/zh_TW/messages.json
new file mode 100644
index 0000000..48ccbb87
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_locales/zh_TW/messages.json
@@ -0,0 +1,113 @@
+{
+   "compressedsizeformat": {
+      "message": "壓縮後大小:\u003Cb>$1 個位元組\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatgb": {
+      "message": "壓縮後大小:\u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatkb": {
+      "message": "壓縮後大小:\u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "compressedsizeformatmb": {
+      "message": "壓縮後大小:\u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "datasavingspercentformat": {
+      "message": "$1%",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "disabledatasaverlabel": {
+      "message": "關閉 Data Saver"
+   },
+   "enabledatasaverlabel": {
+      "message": "開啟 Data Saver"
+   },
+   "extdesc": {
+      "message": "使用 Google 伺服器對您造訪的網頁進行最佳化處理,藉此減少數據用量。"
+   },
+   "extname": {
+      "message": "Data Saver"
+   },
+   "extnamebeta": {
+      "message": "Data Saver (測試版)\\"
+   },
+   "helpandfeedback": {
+      "message": "說明與意見回饋"
+   },
+   "incognitomessage": {
+      "message": "無法在無痕模式中使用這個擴充功能。"
+   },
+   "info1": {
+      "message": "使用 Google 的最佳化處理技術減少網頁瀏覽的頻寬用量"
+   },
+   "info2": {
+      "message": "透過 HTTPS 或無痕模式存取網頁時,Google 不會進行最佳化處理,也不會偵測到這些網頁。"
+   },
+   "learnmorelinktext": {
+      "message": "瞭解詳情"
+   },
+   "originalsizeformat": {
+      "message": "原始大小:\u003Cb>$1 個位元組\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatgb": {
+      "message": "原始大小:\u003Cb>$1 GB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatkb": {
+      "message": "原始大小:\u003Cb>$1 KB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "originalsizeformatmb": {
+      "message": "原始大小:\u003Cb>$1 MB\u003C/b>",
+      "placeholders": {
+         "1": {
+            "content": "$1"
+         }
+      }
+   },
+   "reducedatausagelabel": {
+      "message": "減少數據用量"
+   },
+   "reportissue": {
+      "message": "回報問題"
+   },
+   "versionnotcompatible": {
+      "message": "這個 Chrome 版本與這項擴充功能不相容。請將 Chrome 更新至最新版本。M41 測試版是第一個支援的版本。"
+   }
+}
diff --git a/chrome/test/data/chromeproxy/extension/_metadata/computed_hashes.json b/chrome/test/data/chromeproxy/extension/_metadata/computed_hashes.json
new file mode 100644
index 0000000..f5739179
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_metadata/computed_hashes.json
@@ -0,0 +1 @@
+{"file_hashes":[{"block_hashes":["VZXJdXcFjZC9d7R2AajaloZsRhf+fo+6CKyVNCCYbFc="],"block_size":4096,"path":"background_compiled.js"},{"block_hashes":["pc4qxA9FIymqhzDqgysTWlCa4ZkwsQdP7/CGR1jStyA="],"block_size":4096,"path":"images/alert.webp"},{"block_hashes":["Fmc/vfU8FYA18RLAK1Y7q6/X05oI2IDbPWY5hiQxiuE="],"block_size":4096,"path":"images/proxy-enabled19.webp"},{"block_hashes":["FwlfOrdL11588jCP6HgqAJVT0AFNbjLpx0ITyaznnOI="],"block_size":4096,"path":"images/proxy-enabled38.webp"},{"block_hashes":["EFqC7PadJwde7JJtWlgQglalpWAM0ZE8ioewL4iL1ow="],"block_size":4096,"path":"popup.css"},{"block_hashes":["xi8+eEffKYpB2pH+p5YLqTrB5DupRkgDDchlT9qZXqU="],"block_size":4096,"path":"popup.html"},{"block_hashes":["IA16ao6BtdPtDODbuQXRg9RaVnmiOMU9w+bR/9uLufk=","Wntb0i0HsW1kSZYo5PDJ3zX0YUqlrf/+tZ9u4/Bfd5o=","/fjO/GEpJdmpgczxmlWdqTrOT23uZkd0ijkCesjuSuU=","cXkIpgCtYOGxmEQQemiSLvEOhQvisAge85N7CxwcHVw=","AWSfNMPSN8hxwwU36rgAJrVkO5Mhi0EgII7Kn41QFlY=","nBYnfydUMwB6icmvc0vN6fx4WhomkdceQW4qDX45+hE=","wGQWURWDx71WasgHLtdzzvi/rIzkJPTX2Z8pLjjnN/s=","mOYYpAc1h5WxYdrzwIYmum91tT/Lt6AbURSe8+Fkozg=","0lZLQqEn46ObO46wjTStm8qbg5uGkKOLypBG1lJLS8o=","O8yqXKRj1Ow9RroEfQqL8RnAVWQDDvZRcLkShLh5HnQ=","PB+LGUXaPv9z02uh3Kv51PIVdjggrwgqqfBJgXAy518=","y2nqfwZ1NgehUC4KuZN7zSfHuA4EytodZSlDWDa/X98=","7A3+gas9I/LxN8DPJqCHC2C41EMxsKKFfqt2MiPlyZM=","8Kgsb8XvIYfkEygFTzRm9TnxNlfmEGN/P0xRJvMZSLQ=","J9lhyCyHr3u51xg/XF3hE1zf+bCKd4YtLXDZswaVONk=","DNVl0ZyNoW3tBYcg9qgojPFVJ99mLxr8PWP8nductMw=","WC3BTSvsTlXsC5ZYCd2wYEPSY0d6+MZj/pglTRSKvMU=","iMrlsXU1Wh8JAY5fzek03E5FCvnlMtifOcCa3LlbMz4=","HEZaa7tZnqL6Bk8vFcL6kXQcgUS9r9xPpa9RRDlNMhE=","YMdZ7TdQyJx3fmX31Jg8rIjHlbv92Oep/hAwyVgLv6c=","wrCujcL4kHD47FKiN4GIQaZgqnwIxOW7wMszksRKNys=","gg6IrjvoyW7uNgme0SM9/OZtdofvBd+tnD3Qc2S9h8s=","mhNXQzHmkf+uo0hVcs8mtetyoZsarrP1Rou5INsoTwo=","7A0XOhEN0Euos32RFVe8LOr7CpxmihUcuYnZYI9+3jw=","psKm+n3GkjqFNljsqUhVS7ws1KLaFyTQYgDWaLQ+3oc=","ETmfLfRqH471FWtNIaigBp37tX4cqmoDx4uhbfvgMKc=","8OhT+tN+pp9kkwseMHRBGOZY5/mpGgTduQZJSWjPSvM=","eNsR19bqmaSPDMLYr6+ih0suVHNWrcctylu/QvhD5kk=","pDrnns4Iop91cL4yFR5xkxycnLb5Z/xfqbadMU5H1CI=","KXl/Axw2WlDGGkNWKWv/tZr/AaeKNUT7xYvTvrLbqK8=","sNDCZMWRUhI64YmeW3e9fdWfFPYBL7BIx/Bxc37oP2M=","JzxHSmSPEaxDzUZeKnjkf2sNas32JlDJYT6ZxmPaDr0=","nOUspnCx1rSx7FdCoP9tSjdraKd7jVblcW72OYvsiL4=","RvO+MwT0fO41h0s7+AYqosraLkxUOy8iSMdxQq0Yz4E=","Ae2hgFpDgWWL8bCIUuTW1sudhL1FzP6FF9H++RfnsIU=","btoUU0/DobHHOQWyGQT3W3qAv1DV2VTfo5ZBeSr/Yr0=","B2b4BmIY2A2e/Hu0RpGJ8+RB5Wdn9zlVDOnIT8yJPLI="],"block_size":4096,"path":"popup_compiled.js"}],"version":2}
\ No newline at end of file
diff --git a/chrome/test/data/chromeproxy/extension/_metadata/verified_contents.json b/chrome/test/data/chromeproxy/extension/_metadata/verified_contents.json
new file mode 100644
index 0000000..f633ffd
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/_metadata/verified_contents.json
@@ -0,0 +1 @@
+[{"description":"treehash per file","signed_content":{"payload":"eyJjb250ZW50X2hhc2hlcyI6W3siYmxvY2tfc2l6ZSI6NDA5NiwiZGlnZXN0Ijoic2hhMjU2IiwiZmlsZXMiOlt7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6Il9yd1QwUkttSGZNbjlYZ3lWUUYwbDJCMVVNeVM4S2gxR2E2bFQ4WUhTQjgiLCJwYXRoIjoiX2xvY2FsZXMvYW0vbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6IkZsdTFUUTBQZEsyVktUbWdMbHhBa0NWSklxYzd2MWdqWFNNcWFTQk1QZ2sifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IjZDbEF5VkpIYkVYUFVxRTJMRnIyenlTc3o5VUxqY0Q3UzlWazd5VVBfMW8iLCJwYXRoIjoiX2xvY2FsZXMvYXIvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6IlA0YWFIa0lXVkNhM3NIOGtsZVoyT2pOb0pmZFZmTXcxNnNSUC03VVR6V3MifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6ImVGWWxmTTFyWHRuQk9hb0dqaHl1ck1MUEljUGtrcHJ4aVdYa21PWFY1WDgiLCJwYXRoIjoiX2xvY2FsZXMvYmcvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6IjBGSUU2WEg2WHp3ZkFja1NGLXBidUZ6RlFOMWhIV3Q4WGE2U2VaLWJvUncifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6InJRYzZjTUt3WHU4LWhEeUtjUHl0MjFTdG5CbTlaSVR6OGdpWWkzbk9Jc1kiLCJwYXRoIjoiX2xvY2FsZXMvYm4vbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6Ik1fRUN5Vk1NaFg5dlJTV2RLbExrSTZPU2NZbzh3ZmRHME1sQ2lZRVNnRFkifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IlZweWhwRmlEUU0xM2tjX3RrcWhNNE42ZlRrVWE5WWhScDhLQlE2alE5dFkiLCJwYXRoIjoiX2xvY2FsZXMvY2EvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6IlhMT0NYcG4wemkxbDFxN2hwTGNZRGhSdm5IWlRHdGFkRUg5RzBCSHRSekUifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6ImJsSV91eUJGZjVrMDNMOENPNDZXS2ZBQXczS051Zm5yR2VLRTU5bjNHOXciLCJwYXRoIjoiX2xvY2FsZXMvY3MvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6IlI3U0J0WE4wYmM0N25nSm8zMHA5aGJzT2dCVVZPdGR3bDAxX2E5Ul94RkkifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IlBwam5HNWs4eHlMQVRWd3RwVnh5bmF4NlgzUjlna1UxSGNDUFM1aGdqLVUiLCJwYXRoIjoiX2xvY2FsZXMvZGEvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6IlB1N1ctLWswZVlUdUFnWWJGOHFjclgwRktKMXNCWmgwaW1JM0NCaW5rSFkifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IkpMcnlFblNSUE9rYUFwV0pTdzhJb0VBZ1E5WWROUjhwOVVqYmRPenZhY3MiLCJwYXRoIjoiX2xvY2FsZXMvZGUvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6Img1b2IyNGtUY1hMVmhJN1c3Ul9pZjU4a1o5cGg3Q2VCWjhMZTQ0RnR0cjgifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IkFjcFRKSTJBQmgtYXBRckk2Q3JfN2lHNmFwN2FyNjhzX0dRNDhqLUxBVlUiLCJwYXRoIjoiX2xvY2FsZXMvZWwvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6IlMyUWhueDVMNWlVd25KZnE4SEFrNXVoejYwZ001MUVjeFAzWGdWbzRTQzQifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6Ilh6MUFVbmZzQnQ1Y2tIemJNZW9mSHhfaHhRTllmVW8zMWw1NV9oNW5pSzgiLCJwYXRoIjoiX2xvY2FsZXMvZW4vbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6InN5QTBFTF9Yd2xYYk5zUkRyN1oxY0NSQTZ0dHl6akhDZGw3djF0S05BRDAifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6InZzLTAybElqdEh3MHNqTkVxZDFxNVdOUDFsaE54dnFEaG4ybHZ0RmdNYjQiLCJwYXRoIjoiX2xvY2FsZXMvZW5fR0IvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6Im55LVktWnNMUUtLbFZLb0hFWGJ5THdhTjEwZ3pLUmFsaGdQMHlQbHpCWFkifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IkVrRWl1ODZLdElrYnIwR3AtYnVQS2FZcVhGVDdBSGdXNmp3NWEzcXkzZFUiLCJwYXRoIjoiX2xvY2FsZXMvZXMvbWVzc2FnZXMuanNvbiIsInJvb3RfaGFzaCI6IjVzU2lLZDdNb0xqUmdBRU9vbFd1eGhxNndRODB1QXpDdnZJand5bEFwWEkifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IlBvZm1sSWMzLTN4QkNFc3E0UFZ0V1lXU0FrLUhPLWJWaUJEY3JCR01fOGMiLCJwYXRoIjoiX2xvY2FsZXMvZXNfNDE5L21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJQNmhPUkt1VEdLelBjbWNTUjRPNGx4OTdpaGVaN2d3aHBTaWRZaWNFRFVNIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJSTWF1cngtNUxjUlpxZmFWN1ZtTGZ1WnhST01iZ1lwcVFDNUg0SER5cHhzIiwicGF0aCI6Il9sb2NhbGVzL2V0L21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJ0MW1FMmg4WHcxTTBnWnRMUk9ZY0V5VHFuTWVHamUwcHVVVlBUY2p0b2ljIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJKX2xJREdTSm1HTF9OTnlwUndYeHhhandaUmNycmtNcmJMeXlXbkpjOXJnIiwicGF0aCI6Il9sb2NhbGVzL2ZhL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJtM012YXF5ZXk3OU5RZTN3ak5XR1dsSTI3V1NFMjNQRDBtcFFtX3BQcEFzIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiItNW9vdUtlWHF4bWw5WEFyY2hlX2puYmdSdHljNWlTNS1nTGNNQVF0djFJIiwicGF0aCI6Il9sb2NhbGVzL2ZpL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJITGR0bkhSSFJvNHFyRzNHSEhJQ2RWbndkWUhQOVM2NEI4QXRCQzJwd0s0In0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJORXEwQlYzZFotMUxSLUhYbnVlcTEzR3dzTF95RG9PaVR5WG9JWTZMRE1rIiwicGF0aCI6Il9sb2NhbGVzL2ZpbC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoid3lvX0hHblpIdWpyYWtGZmQwZU12NWFpVUhiYXZHWlBLUU10TDNEOHpvcyJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiUW5hWVhTdW9tcjJkNE9EN0dkTFl5UzQ0b0ptTFJ0QzY4cDJWaFR6WGZWayIsInBhdGgiOiJfbG9jYWxlcy9mci9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiaVFNOVVuS05ZVkNHNklVbWZGOVZCMW9vbXBpdDRDbENzYmwxSm5OUmVOZyJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiX0VieWdWdjRCX1VCU2JsX0NRSVJGOWVVWDF1OE9FR2ZaUDZzem5ySUp0USIsInBhdGgiOiJfbG9jYWxlcy9ndS9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiNWwwdnJzX01XMi1nTzEwMURINDFqbjFyazJUcEx3RUdXLTVBellYaXZOMCJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoidEtjLUFBdHo1eS1kYnlqUG1UMFhRb3BOUXNZaVp6TVRlOWo1c1JJS2hlQSIsInBhdGgiOiJfbG9jYWxlcy9oZS9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiQS1QdDZfU0xpYmVuYjE5aXZLREhUcU13bUZwNWtwbFcyVjE5TGJLcHBqQSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiVTlOZlItakhERWVtMUxwSlRBdUVYcHFxOXBRNkphdWU2RW91dHRwaXdSYyIsInBhdGgiOiJfbG9jYWxlcy9oaS9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiaWZEMzhrSzNKS3NtbDNwV1hDVmNERU02QnRtX0k0elItUEV5Uzh4cUJjWSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiLWlNenBuaEt2LTd2VFdiMVJkUGFoSXVScVdZTEU3VWZVdlhjRTVRaG9jZyIsInBhdGgiOiJfbG9jYWxlcy9oci9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiQTk3ZmRsN242YzdBT2g5Z00yQVExS1ZGLTVjZllIU2dHZkJTMTBpUUhSdyJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiYzRnZEtyamZzS0xPZXBIVy1sMVJuSENLYzFqQVUwUWliTmNSa1hlemk4QSIsInBhdGgiOiJfbG9jYWxlcy9odS9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiUi05Z2Z1dUxDdWtpVy1adDRFc3RnTWZJMjg5MXhzQ2V6S3VGSDh4UUxubyJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiNk9OLVpxRnNKOTU0MzFUUGdHOGRqNjAtVGdKQnBJMUdxSzBuM1N1ZWQwQSIsInBhdGgiOiJfbG9jYWxlcy9pZC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiZjROS1BKSVhLbkl2XzZ3YVVmWFpCcWpGQ2JhVmJIX2o4QzlPc0RqT0dINCJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiQWhqcE1KTVRvaHI5Snd2UHpmVWxkUVN4Sml3T1JXejJuM1BmQ0lFa05ZdyIsInBhdGgiOiJfbG9jYWxlcy9pdC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiblBDM1F5aGFVNkpVbDV1QjgwMWdQSUJTTjMxNi1TM0tmTmpSOTFidGpXVSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoibF9EQk9vcGpfYjM2VFpjSE41Nk9mQmNzaXhCZ0xKWHFaamktM3JVZXo1WSIsInBhdGgiOiJfbG9jYWxlcy9qYS9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiU0Z3cDNUanNlMUhkT1JMTFdlRGFNd05tYnlWMTF1WVA1R2c3dGZsdnh4RSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiaTRWOVU0Q1FkQ3B3OW1jZDRxSU5pWWVNWThtdjZGM0M0WXEyZUVFam1jOCIsInBhdGgiOiJfbG9jYWxlcy9rbi9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiTmFTdjV0VDNXRy1tTjd6bGl0dWFsOVhCVkkxXy10UW9kWmg3SzlMNERfSSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiTDlMVV93QV9KTExxcmdRdmJ0dTEyMjJZTE40cTdhWTJxeWh5QUdEbm5tdyIsInBhdGgiOiJfbG9jYWxlcy9rby9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiQm9SQmw4bnItcm54WjFqbFJGc1YyTzNXNkIxc3ZIb1lNY2ZVX3BpUkFoSSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiY3pta0Q1dG5Ya0Z2SWFYc2tyWXdWbWxMMkpQX1FqQUVaX0RrdE5zMmtfRSIsInBhdGgiOiJfbG9jYWxlcy9sdC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiM3kzR0llSVVOZC1ka0dVUmlMMVpkY3dKZXdNTjJpYmhaX2FyRnpEWWk2RSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiY01kcWJsbnJxMkpZRVE2b0pDWjJLQzh3ZXRKdHlEX081Y2JtMWI0UGdnMCIsInBhdGgiOiJfbG9jYWxlcy9sdi9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiLU5scl9ZLTdLRm11WUZfeVdRbExRYUliUmNRM1draGNyd3pHTjJNM01sYyJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiLTFHbmJ5TXZ2UzZoOWFzTkcwN1pNeDdrM2Z0bm9wQzRRNHJhM0RnSi1aayIsInBhdGgiOiJfbG9jYWxlcy9tbC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiV0t5R2NHTTFqdFpPZjFWV0pNM05EdW54Z3ZjRlJZdjNIR0hxMEVNVVhJZyJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiekNuSlBJOUdOTXRjOHJpb1QzenhudkhhRXVNYklYaEJvLVdrMlMtSWFQVSIsInBhdGgiOiJfbG9jYWxlcy9tci9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiSGg3U2MxVDhnam03TWtYQ2xFcGgzOUh5YmlEZzdhNGllQm9aZS1mNE5GayJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiLVJxdXlSa3V4aW9yUWR6TUlkb0dRejk5UXFMcXUxXzhmTjZ5Z3h0aVZtRSIsInBhdGgiOiJfbG9jYWxlcy9tcy9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiTEtjZ2FiSWNfZW5EeHN5UUtnbTBhdHN0SGJuTmdNUW9EUmh2VGx1M19BdyJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoidzJ2MHJ6cDl3cXc2b1A2R3pyY3A4TFlQZkVmUzJiOVVERGduOGpwcmhHOCIsInBhdGgiOiJfbG9jYWxlcy9uYi9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiZ2xRT183dFVxY1VoRFQ0QVlvbzY2c2RnVmZqRGhkRk04cUdZby0wMldOSSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoidDRxU0hodFNBcWpTaUNaTjd1eXNwek0tWWJWOTRrdVJBWTNieGVONFNsQSIsInBhdGgiOiJfbG9jYWxlcy9ubC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoib2RtNG9HYV9udVpmNk5uMjl1MTV3akV5VTBralMyVW9SVXRSQ3NNSmlGNCJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiLVJYbXctVW9qaFpWV3ZmbWp4UDVoVnhCSWtXaE4wTVc0Z1VPaTFzVEZIbyIsInBhdGgiOiJfbG9jYWxlcy9wbC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiRVEwSWZxU2NTcVNTYmNJQkpkdER0NkxNUG5zSmNBRG5jV2dYSEJvcV92MCJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiTFJwY19DOTR6REVhMGN0QmRpX2psdWtnSkcxVHJvNzNBcVBXcm5MYTZGbyIsInBhdGgiOiJfbG9jYWxlcy9wdC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiVVM1cWlFLUstUHFZc3ZSM0ZYQWYxN0hFbE1uRW92RHk1VDllSjA0T3NLayJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiTFJwY19DOTR6REVhMGN0QmRpX2psdWtnSkcxVHJvNzNBcVBXcm5MYTZGbyIsInBhdGgiOiJfbG9jYWxlcy9wdF9CUi9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiVVM1cWlFLUstUHFZc3ZSM0ZYQWYxN0hFbE1uRW92RHk1VDllSjA0T3NLayJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiTDdZM2FiQnFvM0hfc19GYkxHQjJpakpsWjlqLWVvZHkyejhORW9HUkxtcyIsInBhdGgiOiJfbG9jYWxlcy9wdF9QVC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiY2NLazRNeWI3RnFYZ1dmdGM5cFA3TWRZTzBPSl9MdkMwdXh5M2NtcEl6ayJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoib0VnOTNOVHVHOWJIMW84U1QyemJlSThxQ1FRUnMzUTRiTXdTM0t6TEtfNCIsInBhdGgiOiJfbG9jYWxlcy9yby9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoieEhaVndxUXR3aktob3hIMnRjVDZjVG00alNsMzJmYXNjX09wZDcwakFFSSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiRFBiUEI1R01Yb0dxX1BnM1I4ZU1yaTloVXpWMm9iTFhELVVFdmpKZFFQRSIsInBhdGgiOiJfbG9jYWxlcy9ydS9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiV2ZJUWVwUzlxZ0w5dVpYZkE5U3FQX1J2THB4c1pHZnNFdFVudGRkQ1BOVSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiNmZzWkV0TVhzcy1USDIxRzNCakRudGswdkZfUGttM19tVWVGUnE0aDdFOCIsInBhdGgiOiJfbG9jYWxlcy9zay9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiMk5iTENEYUN3UEhFLUlrRVZLNW5iaVRHbjJ1S1p3OXlzXzBzZFpzZHVTSSJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiWW1qOFJkaVkyN1lyRnlGNDR5Z0hoRm0xa2NCemxsSWlWV1ZrYmQtUGRoOCIsInBhdGgiOiJfbG9jYWxlcy9zbC9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiN2o0VHJFbmpaQ2FoZklISU9ELVlQcVV2WC1KM0RMV1A2YW9PaHNYUWI5ayJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoicXJnMTVpb1otSVFkZ2dSSHNJbEZnZzYtc2xWTFNpUExvd2s2MzZHWmM5QSIsInBhdGgiOiJfbG9jYWxlcy9zci9tZXNzYWdlcy5qc29uIiwicm9vdF9oYXNoIjoiaW1IZnl3OWw5QWs0b0Y1Wm5UdEJJcWEyVndZVW8xci1PeUtBS3NhbjNBYyJ9LHsiY2Fub25pY2FsX2pzb25fcm9vdF9oYXNoIjoiNTk1R3A3RWs3S2ktaXhkT1JwZlF6Y0pnWElrRUtCb1dCM2JLem9CampsYyIsInBhdGgiOiJfbG9jYWxlcy9zcl9MYXRuL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiI2OExUNWJlWUZGS2I4WW1KNnBCX0V2cmM2c0FtY1A3cmJmMFNKSngtR0o4In0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJEZ1JQZnJJQTJLcmVXUmkzRzhLaGFpWC1XbnE3QlZvZGVfVnctc2dMOXl3IiwicGF0aCI6Il9sb2NhbGVzL3N2L21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJ2bGU2OWhIN0YweU95STEtc0VsczA4RkFzS20teWNkNTZ1VW1UVDE3Y2pjIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJsRW1Lc0FuQ3laS0hKRHZXc2E4ZHUxcU92dXl5QW1RZ2FYaVNTUnBZRURzIiwicGF0aCI6Il9sb2NhbGVzL3N3L21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJnWkc5Y05QaENCSE0wWFBwQmtZaUk4WTdZOFdqanlieXJENXY0S3BFaHMwIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJXalhzazJrd0Q1QmlDZzhZR2U4NEl5Njc2a05YTDJXWmQzbmNzZ2ZuZUEwIiwicGF0aCI6Il9sb2NhbGVzL3RhL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJiLVp3VzlDVXF1WjFMdlo3MFpZaXdBS3U2MUhTWmFZMmQwWVdBZlpoU1VNIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJtc0NFcWhtYm1MVnN5QU16SERESDZXUWs4VlJINGJWSWljM0ZYNGxqMUpNIiwicGF0aCI6Il9sb2NhbGVzL3RlL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJjdWxyRG5pTHp0RGRWVktOZmZ3LTZIa0t3MDFaczNUU0ZBVVpnQ2QwZjFBIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiI2TnppTFkwZW5tXzJrVGRoSTVYRVREY1dtVU1teXNQeVlnNVdXVE0ycnowIiwicGF0aCI6Il9sb2NhbGVzL3RoL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJBSWlJNkZnVmFZRkFKajZBU2pZNzVlSy0xT2VrMFlsY1NWUDlMZEFlTC0wIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJObGZpNXZvbXB3eTZOdmVDTWZtbFpjVG1NZENTNmR3Zm16d0R6WGp1WHNFIiwicGF0aCI6Il9sb2NhbGVzL3RyL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJWUTV6aHRTRTQzekJEOVE4ME5OZFAzNFM2dmlhYl9zNXRYTUstNEZ1b0cwIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJEQTFxbWJXQWJJMnczbWRzMzJvVnVnTnVRTjZJdnlXS2hoSTdjaWdYUF80IiwicGF0aCI6Il9sb2NhbGVzL3VrL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJ3dDJqaVdRLXpsTVplWjg1SGR3WjNROFI1VTZ0WktsT1BsSGtMU3huS1U4In0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJmLWFXZUhCTkhkeXBxcjc3b0I3RUxCSmt3Q0EtQTJlWWJPVHZXbkJ1WkNFIiwicGF0aCI6Il9sb2NhbGVzL3ZpL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJyRExwTzI0blpTMmE3SkxPUGtsMDl1eGNIWlhLUVB3VmJ4SmpwS0FqVTdRIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiI4X1psNGw2WUl1WDR1TXoyWGlPZktBeG5FMWtxSnFHa0VCeXQxaXZGdjg0IiwicGF0aCI6Il9sb2NhbGVzL3poL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJxbmx6WGN0SFpQLXpKZjlHMTlNVlAyZFpuTjNfT2dUblMwQTYxTklhNmJnIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiI4X1psNGw2WUl1WDR1TXoyWGlPZktBeG5FMWtxSnFHa0VCeXQxaXZGdjg0IiwicGF0aCI6Il9sb2NhbGVzL3poX0NOL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiJxbmx6WGN0SFpQLXpKZjlHMTlNVlAyZFpuTjNfT2dUblMwQTYxTklhNmJnIn0seyJjYW5vbmljYWxfanNvbl9yb290X2hhc2giOiJLQkVFZmNsZV8tZENpeEtWOTJoamdzY2dMN0JyTEdCVHl6NjdHempYSE00IiwicGF0aCI6Il9sb2NhbGVzL3poX1RXL21lc3NhZ2VzLmpzb24iLCJyb290X2hhc2giOiIyemY0eFFoY0pVUExvSzBlZHN5a3dIUUl3a0lDSE0zSlAxMjRXQWJUdnFnIn0seyJwYXRoIjoiYmFja2dyb3VuZF9jb21waWxlZC5qcyIsInJvb3RfaGFzaCI6IlZaWEpkWGNGalpDOWQ3UjJBYWphbG9ac1JoZi1mby02Q0t5Vk5DQ1liRmMifSx7InBhdGgiOiJpbWFnZXMvYWxlcnQud2VicCIsInJvb3RfaGFzaCI6InBjNHF4QTlGSXltcWh6RHFneXNUV2xDYTRaa3dzUWRQN19DR1IxalN0eUEifSx7InBhdGgiOiJpbWFnZXMvYXBwX2ljb24xMjgucG5nIiwicm9vdF9oYXNoIjoiSDBGbW1VMnNDSW5MeFM0UjFJOWM5bGRlR2ZwcW9tb0YzTFhkV244cmt4TSJ9LHsicGF0aCI6ImltYWdlcy9wcm94eS1kaXNhYmxlZDE5LnBuZyIsInJvb3RfaGFzaCI6ImZhVlVSeWxvenB0b0JVcDZCREhkM1BkSW1HR05qdmc5aXNXVjg5TzM0aE0ifSx7InBhdGgiOiJpbWFnZXMvcHJveHktZGlzYWJsZWQzOC5wbmciLCJyb290X2hhc2giOiJwMmw5aWx6NzlGTmRNQlVDbUVoTDIyUE9sOEJtdkdwV2s5UUt0Uk52cnpvIn0seyJwYXRoIjoiaW1hZ2VzL3Byb3h5LWVuYWJsZWQxOS53ZWJwIiwicm9vdF9oYXNoIjoiRm1jX3ZmVThGWUExOFJMQUsxWTdxNl9YMDVvSTJJRGJQV1k1aGlReGl1RSJ9LHsicGF0aCI6ImltYWdlcy9wcm94eS1lbmFibGVkMzgud2VicCIsInJvb3RfaGFzaCI6IkZ3bGZPcmRMMTE1ODhqQ1A2SGdxQUpWVDBBRk5iakxweDBJVHlhem5uT0kifSx7ImNhbm9uaWNhbF9qc29uX3Jvb3RfaGFzaCI6IkVVamVQUXR5b3FRLXJXcjRrNFpHNUVLZExwME02aGtQYU52X3Nrcy14WHMiLCJwYXRoIjoibWFuaWZlc3QuanNvbiIsInJvb3RfaGFzaCI6ImZtcl9raXBWa1dwV2txRHpPZEN5V0F6MUFVYWpUZloxNE95d2FxMjNudmsifSx7InBhdGgiOiJwb3B1cC5jc3MiLCJyb290X2hhc2giOiJFRnFDN1BhZEp3ZGU3Skp0V2xnUWdsYWxwV0FNMFpFOGlvZXdMNGlMMW93In0seyJwYXRoIjoicG9wdXAuaHRtbCIsInJvb3RfaGFzaCI6InhpOC1lRWZmS1lwQjJwSC1wNVlMcVRyQjVEdXBSa2dERGNobFQ5cVpYcVUifSx7InBhdGgiOiJwb3B1cF9jb21waWxlZC5qcyIsInJvb3RfaGFzaCI6IktVcC16QjBpWmlzTF85Z0N2TXUwU2ZNM0Q1WjBSLUxCX1diQkVzTWRPT1kifV0sImZvcm1hdCI6InRyZWVoYXNoIiwiaGFzaF9ibG9ja19zaXplIjo0MDk2fV0sIml0ZW1faWQiOiJwZm1nZmRsZ29tbmJna29mZW9qb2Rpb2RtZ3BnbWthYyIsIml0ZW1fdmVyc2lvbiI6IjEuOTQ1IiwicHJvdG9jb2xfdmVyc2lvbiI6MX0","signatures":[{"header":{"kid":"publisher"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"kOOf4zYhn5Y44GLpwstTo6zswwbZpj_97sZlOgIrZqc1Ipg_6ecyeAI73dfp-l2Pyh_AtZSxCeEplQeVo7uRYIuzRXTp5cwCXmrhFwLDSB2g3SjsyPwRh5C09TuQ0ochpuOAehRKP_rimkzKIWxIQ9WrYV7Vl3OunXvG1UXa6EGv81BrGz7M8SdM-wN4jLJ-bu2vH-ZK06N3JepqBEbX1OqRDI28TJMg33Fcg8zcjf2gQrX7Ap6e7xnmdG-ByFI8PgUqJz7T3brW2X8Xb5Z4juoJ3uxv_61-ou8jbNu9TmPoeJ2_jAoc-FNMCmok_w4JhNgLIh-e7ubmDjpeR-LKLQ"},{"header":{"kid":"webstore"},"protected":"eyJhbGciOiJSUzI1NiJ9","signature":"gqQ4YidWc_m0o54Y93--GpKP41fJhBuKXYqcBaBeRJ0f4beyDXOZrEGNSa13dsS5adhW_BE-7gYnOfRxsRNoagod_K8sC3gpyAVpbt2t0Cm-MHAlZR8tfyh4J4cPC5a-ZtCR7HwxSx4OR0xlq3RiSGuRjVKTtwWL7fmhb1FRq1be1cVaaKW8HM82vKHwthibrBKssq4nxiQhAUv6bFaoihOQ_EKSuiA7uvlWRnWHUXbNGlbTu38VCkDj99RV5vm-NB6LBWfaVsFuplCY671HsG5Gtx2FU3yQXEhvUVuwyTGxmbFho5mGHxYQsAYtq8G_KflAWTXjNhMrRPL2TGxJKQ"}]}}]
\ No newline at end of file
diff --git a/chrome/test/data/chromeproxy/extension/background_compiled.js b/chrome/test/data/chromeproxy/extension/background_compiled.js
new file mode 100644
index 0000000..da3a91cf
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/background_compiled.js
@@ -0,0 +1,43 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+chrome.runtime.onInstalled.addListener(
+  function(a){
+    console.log("chrome.runtime.onInstalled details: "+JSON.stringify(a));
+    console.log("typeof chrome.dataReductionProxy: "+
+                typeof chrome.dataReductionProxy);
+    if("undefined"!=typeof chrome.dataReductionProxy)
+      if("install"==a.reason)chrome.dataReductionProxy.spdyProxyEnabled.set(
+                               {value:!0}),
+      "clearDataSavings"in chrome.dataReductionProxy&&
+        chrome.dataReductionProxy.clearDataSavings(),
+      showEnabledIcon();
+      else if("update"==a.reason||"chrome_update"==a.reason)
+        showEnabledIconIfProxyOn(),
+        chrome.storage.local.get("user_enabled_proxy",
+        function(a){"user_enabled_proxy"in a&&(
+          chrome.dataReductionProxy.spdyProxyEnabled.set({value:!0}),
+          showEnabledIcon(),
+          chrome.storage.local.remove("user_enabled_proxy"))})});
+      chrome.runtime.onStartup.addListener(function(){
+      showEnabledIconIfProxyOn()});chrome.tabs.onCreated.addListener(
+      function(a){setTimeout(function(){a.incognito&&
+      chrome.browserAction.setIcon({tabId:a.id,path:{
+        19:"./images/proxy-disabled19.png",
+        38:"./images/proxy-disabled38.png"}})},500)});
+function showEnabledIconIfProxyOn(){
+  "undefined"!=typeof chrome.dataReductionProxy&&(
+    console.log("Calling spdyProxyEnabled.get"),
+    chrome.dataReductionProxy.spdyProxyEnabled.get({},
+      function(a){
+        console.log("chrome.dataReductionProxy.spdyProxyEnabled.get: "
+                    +JSON.stringify(a));
+        (a="value"in a&&a.value)&&showEnabledIcon()
+      })
+  )
+};
+function showEnabledIcon(){
+  console.log("Calling chrome.browserAction.setIcon");
+  chrome.browserAction.setIcon({path:{19:"./images/proxy-enabled19.webp",
+                                      38:"./images/proxy-enabled38.webp"}})
+};
diff --git a/chrome/test/data/chromeproxy/extension/images/alert.webp b/chrome/test/data/chromeproxy/extension/images/alert.webp
new file mode 100644
index 0000000..51a2d99
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/images/alert.webp
Binary files differ
diff --git a/chrome/test/data/chromeproxy/extension/images/app_icon128.png b/chrome/test/data/chromeproxy/extension/images/app_icon128.png
new file mode 100644
index 0000000..0710093
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/images/app_icon128.png
Binary files differ
diff --git a/chrome/test/data/chromeproxy/extension/images/proxy-disabled19.png b/chrome/test/data/chromeproxy/extension/images/proxy-disabled19.png
new file mode 100644
index 0000000..2e128b02
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/images/proxy-disabled19.png
Binary files differ
diff --git a/chrome/test/data/chromeproxy/extension/images/proxy-disabled38.png b/chrome/test/data/chromeproxy/extension/images/proxy-disabled38.png
new file mode 100644
index 0000000..24862a6
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/images/proxy-disabled38.png
Binary files differ
diff --git a/chrome/test/data/chromeproxy/extension/images/proxy-enabled19.webp b/chrome/test/data/chromeproxy/extension/images/proxy-enabled19.webp
new file mode 100644
index 0000000..04c3f14
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/images/proxy-enabled19.webp
Binary files differ
diff --git a/chrome/test/data/chromeproxy/extension/images/proxy-enabled38.webp b/chrome/test/data/chromeproxy/extension/images/proxy-enabled38.webp
new file mode 100644
index 0000000..94cef230
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/images/proxy-enabled38.webp
Binary files differ
diff --git a/chrome/test/data/chromeproxy/extension/manifest.json b/chrome/test/data/chromeproxy/extension/manifest.json
new file mode 100644
index 0000000..c5bf79e
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/manifest.json
@@ -0,0 +1,26 @@
+{
+   "background": {
+      "persistent": false,
+      "scripts": [ "background_compiled.js" ]
+   },
+   "browser_action": {
+      "default_icon": {
+         "19": "images/proxy-disabled19.png",
+         "38": "images/proxy-disabled38.png"
+      },
+      "default_popup": "popup.html"
+   },
+   "content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'",
+   "default_locale": "en",
+   "description": "__MSG_extDesc__",
+   "icons": {
+      "128": "images/app_icon128.png"
+   },
+   "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAldnSfuah+uUWJTF0r20TXNdpjRJIlThi/Ehi890TPFerwVfyOUzWIO1wXXnu5/vCMy+SpAYI4TeAWhqBhZKRTLfoDjhcl1VXFf4KSaIDdCQycYe/xIUksmdFBox22cRDMtdUOkV4yLsML/ObIEPUMVLUJoJ4DsiMQJ4KKviEQOdEbySmmB0IXrZfT3PD0tS3HcUUcBP5wrPN9AWhW0FMtwAlp7eT5Uu3US8lyNkJDcdPtdchi6fgQ62khn1mnMpY0YHnZyr5jMKJe8WLxFTf9YtDt1XVZYZKSFtdPE0c7p/06cRqHzXMHcvnM78+gtCXU0r5Ek/4+4emDNQ3HIeJRwIDAQAB",
+   "manifest_version": 2,
+   "minimum_chrome_version": "41",
+   "name": "__MSG_extNameBeta__",
+   "permissions": [ "dataReductionProxy", "preferencesPrivate", "storage" ],
+   "update_url": "https://clients2.google.com/service/update2/crx",
+   "version": "1.945"
+}
diff --git a/chrome/test/data/chromeproxy/extension/popup.css b/chrome/test/data/chromeproxy/extension/popup.css
new file mode 100644
index 0000000..26d9de0
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/popup.css
@@ -0,0 +1,121 @@
+/* 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. */
+
+body {
+  margin: 20px 20px 8px 20px;
+  width: 278px;
+  direction: __MSG_@@bidi_dir__;
+}
+
+#ext_name {
+  font-size: 14px;
+  font-weight: bold;
+}
+
+#data_savings_heading, #graph_start_date, #graph_end_date {
+  font-size: 14px;
+}
+
+#original_data_size, #compressed_data_size {
+  text-align: __MSG_@@bidi_end_edge__;
+  font-size: 12px;
+}
+
+#data_savings_graph {
+  margin-bottom: 8px;
+}
+
+#data_savings_percent {
+  font-size: 36px;
+  float: __MSG_@@bidi_start_edge__;
+  margin-__MSG_@@bidi_end_edge__: 10px;
+}
+
+#original_data_size {
+  margin: 4px 0 4px 0;
+}
+
+#learn_more, #help_feedback {
+  display: block;
+  padding: 8px 0;
+  outline: 0;
+  margin-top: 16px;
+}
+
+#proxy_off {
+  margin-top: 8px;
+}
+
+#proxy_on {
+  margin-top: 24px;
+}
+
+#graph_start_date {
+  float: left;
+}
+
+#graph_end_date {
+  float: right;
+}
+
+#info2 {
+  margin: 8px 0 24px 0;
+}
+
+.data_savings_sizes {
+  float: __MSG_@@bidi_end_edge__;
+}
+
+.data_savings_numbers {
+  margin: 20px 0 12px 0;
+}
+
+.alert {
+  margin-__MSG_@@bidi_end_edge__: 5px;
+}
+
+#enable_proxy{
+  font-size: 12px;
+  font-weight: bold;
+  color: #FFF;
+  border-radius: 2px;
+  padding: 8px;
+  display: inline-block;
+  margin-top: 9px;
+  outline: 0;
+  text-decoration: initial;
+}
+
+#chrome_incompatible_message, #incognito_message, #info1, #info2, #learn_more {
+  font-size: 12px;
+}
+
+a#enable_proxy:link, a#enable_proxy:visited, a#enable_proxy:hover {
+  background: #4285F4;
+}
+
+a#enable_proxy:hover {
+  box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
+}
+
+a#enable_proxy:active {
+  background: #3a7ce9;
+}
+
+#disable_proxy {
+  font-size: 12px;
+  padding: 8px 0;
+  display: inline-block;
+  margin-top: 9px;
+  outline: 0;
+}
+
+a#disable_proxy:link, a#disable_proxy:visited, a#disable_proxy:hover {
+  color: #0000EE;
+}
+
+a#disable_proxy:active {
+  color: #052577;
+}
+
diff --git a/chrome/test/data/chromeproxy/extension/popup.html b/chrome/test/data/chromeproxy/extension/popup.html
new file mode 100644
index 0000000..f012cbc
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/popup.html
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <link rel="stylesheet" type="text/css" href="popup.css">
+    <script src="popup_compiled.js"></script>
+  </head>
+  <body>
+    <div id="ext_name"></div>
+    <div id="chrome_incompatible" style="display: none;">
+      <table><tr><td>
+        <img class="alert" src="images/alert.webp">
+        </td><td>
+        <span id="chrome_incompatible_message"></span>
+      </td></tr></table>
+    </div>
+    <div id="incognito" style="display: none;">
+      <table><tr><td>
+        <img class="alert" src="images/alert.webp">
+        </td><td>
+        <span id="incognito_message"></span>
+      </td></tr></table>
+    </div>
+    <div id="main" style="display: none;">
+      <div id="proxy_off" style="display: none;">
+        <div id="info1"></div>
+        <div id="info2"></div>
+          <a id="enable_proxy" href="#" tabindex="-1"></a>
+          <a tabindex="-1" id="learn_more" target="_blank" href="https://support.google.com/chrome/?p=data_saver_off"></a>
+      </div>
+      <div id="proxy_on" style="display: none;">
+        <canvas id="data_savings_graph" width="278" height="132"></canvas>
+        <span id="graph_start_date"></span>
+        <span id="graph_end_date"></span>
+        <div style="clear: both;"></div>
+        <div class="data_savings_numbers">
+          <span id="data_savings_percent"></span>
+          <div class="data_savings_sizes">
+            <div id="original_data_size"></div>
+            <div id="compressed_data_size"></div>
+            <div style="clear: both;"></div>
+          </div>
+          <div style="clear: both;"></div>
+        </div>
+        <a id="disable_proxy" href="#" tabindex="-1"></a>
+        <a id="help_feedback" tabindex="-1" target="_blank" href="https://support.google.com/chrome/?p=data_saver_on"></a>
+      </div>
+    </div>
+  </body>
+</html>
diff --git a/chrome/test/data/chromeproxy/extension/popup_compiled.js b/chrome/test/data/chromeproxy/extension/popup_compiled.js
new file mode 100644
index 0000000..67f2653
--- /dev/null
+++ b/chrome/test/data/chromeproxy/extension/popup_compiled.js
@@ -0,0 +1,2160 @@
+// 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.
+/*
+ jQuery JavaScript Library v1.9.0
+ http://jquery.com/
+
+ Includes Sizzle.js
+ http://sizzlejs.com/
+
+ Copyright 2005, 2012 jQuery Foundation, Inc. and other contributors
+ Released under the MIT license
+ http://jquery.org/license
+
+ Date: 2013-1-14
+*/
+(function(v,p){function m(a){var f=a.length,k=c.type(a);
+return c.isWindow(a)?!1:1===a.nodeType&&f?!0:"array"===k||"function"
+!==k&&(0===f||"number"==typeof f&&0<f&&f-1 in a)}function d(a){
+var f=kb[a]={};return c.each(a.match(Z)||[],function(a,c){f[c]=!0}),f}
+function n(a,f,k,b){if(c.acceptData(a)){var g,l,u=c.expando,
+x="string"==typeof f,e=a.nodeType,d=e?c.cache:a,q=e?a[u]:a[u]&&u;
+if(q&&d[q]&&(b||d[q].data)||!x||k!==p)return q||(e?a[u]=q=I.pop()
+||c.guid++:q=u),d[q]||(d[q]={},e||(d[q].toJSON=c.noop)),
+("object"==typeof f||"function"==typeof f)&&(b?d[q]=c.extend(d[q],f)
+:d[q].data=c.extend(d[q].data,f)),g=d[q],b||(g.data||(g.data={}),g=g.data)
+,k!==p&&(g[c.camelCase(f)]=k),x?(l=g[f],null==l&&(l=g[c.camelCase(f)]))
+:l=g,l}}function h(a,f,k){if(c.acceptData(a)){var b,g,l,u=a.nodeType,x=u?
+c.cache:a,e=u?a[c.expando]:c.expando;if(x[e]){if(f&&(b=k?x[e]:x[e].data))
+{c.isArray(f)?f=f.concat(c.map(f,c.camelCase)):f in b?f=[f]:(
+f=c.camelCase(f),f=f in b?[f]:f.split(" "));g=0;for(l=f.length;l>g;g++)
+delete b[f[g]];
+if(!(k?B:c.isEmptyObject)(b))return}(k||(delete x[e].data,B(x[e])))&&(u?
+c.cleanData([a],!0):c.support.deleteExpando||x!=x.window?delete x[e]:x[e]=null
+)
+}}}function r(a,f,k){if(k===p&&1===a.nodeType){var b="data-"+f.replace(
+Jb,"-$1").toLowerCase();if(k=a.getAttribute(b),"string"==typeof k){try{
+k="true"===k?!0:"false"===k?!1:"null"===k?null:+k+""===k?+k:Kb.test(k)?
+c.parseJSON(k):k}catch(g){}c.data(a,f,k)}else k=p}return k}function B(
+a){for(var f in a)if(("data"!==f||!c.isEmptyObject(a[f]))&&"toJSON"!==
+f)return!1;return!0}function D(){return!0}function M(){return!1}
+function E(a,f){do a=a[f];while(a&&1!==a.nodeType);return a}function A(
+a,f,k){if(f=f||0,c.isFunction(f))return c.grep(a,function(a,c){var b=!!
+f.call(a,c,a);return b===k});if(f.nodeType)return c.grep(a,function(a){
+return a===f===k});if("string"==typeof f){var b=c.grep(a,function(a){
+return 1===a.nodeType});if(Lb.test(f))return c.filter(f,b,!k);f=c.filter(
+f,b)}return c.grep(a,function(a){return 0<=c.inArray(a,f)===k})}function V(
+a){var f=
+lb.split("|");a=a.createDocumentFragment();if(a.createElement)for(;f.length;)
+f.pop();return a}function ra(a,f){return a.getElementsByTagName(f)[0]||
+a.appendChild(a.ownerDocument.createElement(f))}function Q(a){
+var f=a.getAttributeNode("type");return a.type=(f&&f.specified)+"/"+a.type,a}
+function ea(a){var f=Mb.exec(a.type);return f?a.type=f[1]:
+a.removeAttribute("type"),a}function R(a,f){for(var k,b=0;null!=(k=a[b]);b++)
+c._data(k,"globalEval",!f||c._data(f[b],"globalEval"))}function sa(a,f){if
+(1===
+f.nodeType&&c.hasData(a)){var k,b,g;b=c._data(a);var l=c._data(f,b),u=b.events
+;
+if(u)for(k in delete l.handle,l.events={},u)for(b=0,g=u[k].length;g>b;b++)
+c.event.add(f,k,u[k][b]);l.data&&(l.data=c.extend({},l.data))}}function F(a,f)
+{var k,b,g=0,l=a.getElementsByTagName!==p?a.getElementsByTagName(f||"*"):
+a.querySelectorAll!==p?a.querySelectorAll(f||"*"):p;if(!l)for(l=[],
+k=a.childNodes||a;null!=(b=k[g]);g++)!f||c.nodeName(b,f)?l.push(b):
+c.merge(l,F(b,f));return f===p||f&&c.nodeName(a,f)?c.merge([a],
+l):l}function Da(a){Ua.test(a.type)&&(a.defaultChecked=a.checked)}
+function Ea(a,f){if(f in a)return f;for(
+var c=f.charAt(0).toUpperCase()+f.slice(1),b=f,g=mb.length;g--;)
+if(f=mb[g]+c,f in a)return f;return b}function S(a,f){return a=f||a,
+"none"===c.css(a,"display")||!c.contains(a.ownerDocument,a)}function X(a,f){
+for(var k,b=[],g=0,l=a.length;l>g;g++)k=a[g],k.style&&(b[g]=c._data(k,
+"olddisplay"),f?(b[g]||"none"!==k.style.display||(k.style.display=""),""===
+k.style.display&&S(k)&&(b[g]=c._data(k,"olddisplay",
+Fa(k.nodeName)))):b[g]||S(k)||c._data(k,"olddisplay",c.css(k,"display")));
+for(g=0;l>g;g++)k=a[g],k.style&&(f&&"none"!==k.style.display&&""!==
+k.style.display||(k.style.display=f?b[g]||"":"none"));return a}function va(
+a,f,c){return(a=Nb.exec(f))?Math.max(0,a[1]-(c||0))+(a[2]||"px"):f}
+function Ga(a,f,k,b,g){f=k===(b?"border":"content")?4:"width"===f?1:0;
+for(var l=0;4>f;f+=2)"margin"===k&&(l+=c.css(a,k+fa[f],!0,g)),b?(
+"content"===k&&(l-=c.css(a,"padding"+fa[f],!0,g)),"margin"!==k&&(l-=c.css(a,
+"border"+
+fa[f]+"Width",!0,g))):(l+=c.css(a,"padding"+fa[f],!0,g),"padding"!==k&&(
+l+=c.css(a,"border"+fa[f]+"Width",!0,g)));return l}function Ha(a,f,k){
+var b=!0,g="width"===f?a.offsetWidth:a.offsetHeight,l=ga(a),
+u=c.support.boxSizing&&"border-box"===c.css(a,"boxSizing",!1,l);if(0>=g||
+null==g){if(g=Y(a,f,l),(0>g||null==g)&&(g=a.style[f]),Ia.test(g))return g;
+b=u&&(c.support.boxSizingReliable||g===a.style[f]);g=parseFloat(g)||0}
+return g+Ga(a,f,k||(u?"border":"content"),b,l)+"px"}function Fa(a){
+var f=y,k=nb[a];
+return k||(k=Ja(a,f),"none"!==k&&k||(wa=(wa||c(
+"<iframe frameborder='0' width='0' height='0'/>").css(
+"cssText","display:block !important")).appendTo(f.documentElement),
+f=(wa[0].contentWindow||wa[0].contentDocument).document,f.write(
+"<!doctype html><html><body>"),f.close(),k=Ja(a,f),wa.detach()),nb[a]=k),
+k}function Ja(a,f){var k=c(f.createElement(a)).appendTo(f.body),
+b=c.css(k[0],"display");return k.remove(),b}function xa(a,f,k,b){
+var g;if(c.isArray(f))c.each(f,function(f,c){k||Ob.test(a)?b(a,c):xa(a+
+"["+("object"==typeof c?f:"")+"]",c,k,b)});else if(k||"object"!==c.type(
+f))b(a,f);else for(g in f)xa(a+"["+g+"]",f[g],k,b)}function Ka(a){
+return function(f,k){"string"!=typeof f&&(k=f,f="*");var b,g=0,l=
+f.toLowerCase().match(Z)||[];if(c.isFunction(k))for(;b=l[g++];)"+"===b[0]?
+(b=b.slice(1)||"*",(a[b]=a[b]||[]).unshift(k)):(a[b]=a[b]||[]).push(k)
+}}function La(a,f,k,b){function g(x){var e;return l[x]=!0,c.each(a[x]||[],
+function(a,c){var x=c(f,k,b);return"string"!=typeof x||u||l[x]?u?!(e=x):p:(
+f.dataTypes.unshift(x),
+g(x),!1)}),e}var l={},u=a===Wa;return g(f.dataTypes[0])||!l["*"]&&g("*")}
+function P(a,f){var k,b,g=c.ajaxSettings.flatOptions||{};for(k in f)
+f[k]!==p&&((g[k]?a:b||(b={}))[k]=f[k]);return b&&c.extend(!0,a,b),a}
+function ka(){try{return new v.XMLHttpRequest}catch(a){}}function ya()
+{return setTimeout(function(){la=p}),la=c.now()}function b(a,f){c.each(
+f,function(f,c){for(var b=(za[f]||[]).concat(za["*"]),l=0,u=b.length;
+u>l&&!b[l].call(a,f,c);l++);})}function e(a,f,k){var t,g=0,l=Ma.length,
+u=c.Deferred().always(function(){delete x.elem}),
+x=function(){if(t)return!1;for(var f=la||ya(),f=Math.max(
+0,e.startTime+e.duration-f),c=f/e.duration||0,c=1-c,k=0,b=e.tweens.length;
+b>k;k++)e.tweens[k].run(c);return u.notifyWith(a,[e,c,f]),1>c&&b?f:(
+u.resolveWith(a,[e]),!1)},e=u.promise({elem:a,props:c.extend({},f),
+opts:c.extend(!0,{specialEasing:{}},k),originalProperties:f,
+originalOptions:k,startTime:la||ya(),duration:k.duration,tweens:[],
+createTween:function(f,k){var b=c.Tween(a,e.opts,f,k,e.opts.specialEasing[f]
+||e.opts.easing);return e.tweens.push(b),
+b},stop:function(f){var c=0,k=f?e.tweens.length:0;if(t)return this;for(
+t=!0;k>c;c++)e.tweens[c].run(1);return f?u.resolveWith(a,[e,f]):
+u.rejectWith(a,[e,f]),this}});k=e.props;for(q(k,e.opts.specialEasing);
+l>g;g++)if(f=Ma[g].call(e,a,k,e.opts))return f;return b(e,k),c.isFunction(
+e.opts.start)&&e.opts.start.call(a,e),c.fx.timer(c.extend(x,{elem:a,
+anim:e,queue:e.opts.queue})),e.progress(e.opts.progress).done(
+e.opts.done,e.opts.complete).fail(e.opts.fail).always(e.opts.always)}
+function q(a,f){var k,b,
+g,l,u;for(k in a)if(b=c.camelCase(k),g=f[b],l=a[k],c.isArray(l)&&(
+g=l[1],l=a[k]=l[0]),k!==b&&(a[b]=l,delete a[k]),u=c.cssHooks[b],
+u&&"expand"in u)for(k in l=u.expand(l),delete a[b],l)k in a||(a[k]=l[k],
+f[k]=g);else f[b]=g}function w(a,f,k){var b,g,l,u,x,e,d=this,q=a.style,h={},
+m=[],n=a.nodeType&&S(a);k.queue||(x=c._queueHooks(a,"fx"),null==x.unqueued&&(x
+.unqueued=0,e=x.empty.fire,x.empty.fire=function(){x.unqueued||e()}),
+x.unqueued++,d.always(function(){d.always(function(){x.unqueued--;c.queue(a,
+"fx").length||x.empty.fire()})}));1===a.nodeType&&("height"in f||"width"in f)
+&&(k.overflow=[q.overflow,q.overflowX,q.overflowY],"inline"===c.css(a
+,"display")&&"none"===c.css(a,"float")&&(c.support.inlineBlockNeedsLayout&
+&"inline"!==Fa(a.nodeName)?q.zoom=1:q.display="inline-block"));k.overflow&&(q
+.overflow="hidden",c.support.shrinkWrapBlocks||d.done(function(){q.overflow=k
+.overflow[0];q.overflowX=k.overflow[1];q.overflowY=k.overflow[2]}));for(b in f
+)(l=f[b],Qb.exec(l))&&(delete f[b],g=g||"toggle"===
+l,l!==(n?"hide":"show"))&&m.push(b);if(f=m.length)for(l=c._data(a,"fxshow")||c
+._data(a,"fxshow",{}),("hidden"in l)&&(n=l.hidden),g&&(l.hidden=!n),n?c(a)
+.show():d.done(function(){c(a).hide()}),d.done(function(){var f;c._removeData
+(a,"fxshow");for(f in h)c.style(a,f,h[f])}),b=0;f>b;b++)g=m[b],u=d.createTween
+(g,n?l[g]:0),h[g]=l[g]||c.style(a,g),g in l||(l[g]=u.start,n&&(u.end=u.start,u
+.start="width"===g||"height"===g?1:0))}function z(a,f,c,b,g){return new z
+.prototype.init(a,f,c,b,g)}function J(a,f){var c,
+b={height:a},g=0;for(f=f?1:0;4>g;g+=2-f)c=fa[g],b["margin"+c]=b["padding"+c]=a
+;return f&&(b.opacity=b.width=a),b}function N(a){return c.isWindow(a)?a:9===a
+.nodeType?a.defaultView||a.parentWindow:!1}var O,G,y=v.document,Na=v.location
+,Aa=v.jQuery,Rb=v.$,ha={},I=[],Oa=I.concat,Xa=I.push,aa=I.slice,ob=I.indexOf
+,Sb=ha.toString,Ya=ha.hasOwnProperty,Za="1.9.0".trim,c=function(a,f){return
+ new c.fn.init(a,f,O)},Pa=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source
+,Z=/\S+/g,Tb=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,
+Ub=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,pb=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,Vb=/^[\]
+,:{}\s]*$/,Wb=/(?:^|:|,)(?:\s*\[)+/g,Xb=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g
+,Yb=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g
+,Zb=/^-ms-/,$b=/-([\da-z])/gi,ac=function(a,f){return f.toUpperCase()}
+,Qa=function(){y.addEventListener?(y.removeEventListener("DOMContentLoaded",Qa
+,!1),c.ready()):"complete"===y.readyState&&(y.detachEvent("onreadystatechange"
+,Qa),c.ready())};c.fn=c.prototype={jquery:"1.9.0",constructor:c,
+init:function(a,f,k){var b,g;if(!a)return this;if("string"==typeof a){if
+(b="<"===a.charAt(0)&&">"===a.charAt(a.length-1)&&3<=a.length?[null,a,null]:Ub
+.exec(a),!b||!b[1]&&f)return!f||f.jquery?(f||k).find(a):this.constructor(f)
+.find(a);if(b[1]){if(f=f instanceof c?f[0]:f,c.merge(this,c.parseHTML(b[1],f&
+&f.nodeType?f.ownerDocument||f:y,!0)),pb.test(b[1])&&c.isPlainObject(f))for(b
+ in f)c.isFunction(this[b])?this[b](f[b]):this.attr(b,f[b]);return this}if(g=y
+.getElementById(b[2]),g&&g.parentNode){if(g.id!==
+b[2])return k.find(a);this.length=1;this[0]=g}return this.context=y,this
+.selector=a,this}return a.nodeType?(this.context=this[0]=a,this.length=1,this
+):c.isFunction(a)?k.ready(a):(a.selector!==p&&(this.selector=a.selector,this
+.context=a.context),c.makeArray(a,this))},selector:"",length:0,size:function()
+{return this.length},toArray:function(){return aa.call(this)},get:function(a)
+{return null==a?this.toArray():0>a?this[this.length+a]:this[a]}
+,pushStack:function(a){a=c.merge(this.constructor(),a);return a.prevObject=
+this,a.context=this.context,a},each:function(a,f){return c.each(this,a,f)}
+,ready:function(a){return c.ready.promise().done(a),this},slice:function()
+{return this.pushStack(aa.apply(this,arguments))},first:function(){return this
+.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var f=this.length
+;a=+a+(0>a?f:0);return this.pushStack(0<=a&&f>a?[this[a]]:[])},map:function(a)
+{return this.pushStack(c.map(this,function(f,c){return a.call(f,c,f)}))}
+,end:function(){return this.prevObject||this.constructor(null)},
+push:Xa,sort:[].sort,splice:[].splice};c.fn.init.prototype=c.fn;c.extend=c.fn
+.extend=function(){var a,f,k,b,g,l,u=arguments[0]||{},x=1,e=arguments.length
+,d=!1;"boolean"==typeof u&&(d=u,u=arguments[1]||{},x=2);"object"==typeof u||c
+.isFunction(u)||(u={});for(e===x&&(u=this,--x);e>x;x++)if(null!=(a=arguments[x
+]))for(f in a)k=u[f],b=a[f],u!==b&&(d&&b&&(c.isPlainObject(b)||(g=c.isArray(b)
+))?(g?(g=!1,l=k&&c.isArray(k)?k:[]):l=k&&c.isPlainObject(k)?k:{},u[f]=c.extend
+(d,l,b)):b!==p&&(u[f]=b));return u};c.extend({noConflict:function(a){return v
+.$===
+c&&(v.$=Rb),a&&v.jQuery===c&&(v.jQuery=Aa),c},isReady:!1,readyWait:1
+,holdReady:function(a){a?c.readyWait++:c.ready(!0)},ready:function(a){if
+(!0===a?!--c.readyWait:!c.isReady){if(!y.body)return setTimeout(c.ready);c
+.isReady=!0;!0!==a&&0<--c.readyWait||(G.resolveWith(y,[c]),c.fn.trigger&&c(y)
+.trigger("ready").off("ready"))}},isFunction:function(a){return"function"===c
+.type(a)},isArray:Array.isArray||function(a){return"array"===c.type(a)}
+,isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a)
+{return!isNaN(parseFloat(a))&&
+isFinite(a)},type:function(a){return null==a?a+"":"object"==typeof a|
+|"function"==typeof a?ha[Sb.call(a)]||"object":typeof a}
+,isPlainObject:function(a){if(!a||"object"!==c.type(a)||a.nodeType||c.isWindow
+(a))return!1;try{if(a.constructor&&!Ya.call(a,"constructor")&&!Ya.call(a
+.constructor.prototype,"isPrototypeOf"))return!1}catch(f){return!1}for(var b
+ in a);return b===p||Ya.call(a,b)},isEmptyObject:function(a){for(var f in a
+)return!1;return!0},error:function(a){throw Error(a);},parseHTML:function(a,
+f,b){if(!a||"string"!=typeof a)return null;"boolean"==typeof f&&(b=f,f=!1);f=f
+||y;var t=pb.exec(a);b=!b&&[];return t?[f.createElement(t[1])]:(t=c
+.buildFragment([a],f,b),b&&c(b).remove(),c.merge([],t.childNodes))}
+,parseJSON:function(a){return v.JSON&&v.JSON.parse?v.JSON.parse(a
+):null===a?a:"string"==typeof a&&(a=c.trim(a),a&&Vb.test(a.replace(Xb,"@")
+.replace(Yb,"]").replace(Wb,"")))?Function("return "+a)():(c.error("Invalid
+ JSON: "+a),p)},parseXML:function(a){var f,b;if(!a||"string"!=typeof a)return
+ null;
+try{v.DOMParser?(b=new DOMParser,f=b.parseFromString(a,"text/xml")):(f=new
+ ActiveXObject("Microsoft.XMLDOM"),f.async="false",f.loadXML(a))}catch(t){f=p
+}return f&&f.documentElement&&!f.getElementsByTagName("parsererror").length||c
+.error("Invalid XML: "+a),f},noop:function(){},globalEval:function(a){a&&c
+.trim(a)&&(v.execScript||function(a){v.eval.call(v,a)})(a)},camelCase:function
+(a){return a.replace(Zb,"ms-").replace($b,ac)},nodeName:function(a,f){return a
+.nodeName&&a.nodeName.toLowerCase()===f.toLowerCase()},
+each:function(a,f,c){var b,g=0,l=a.length,u=m(a);if(c)if(u)for(;l>g&&(b=f
+.apply(a[g],c),!1!==b);g++);else for(g in a){if(b=f.apply(a[g],c),!1===b)break
+}else if(u)for(;l>g&&(b=f.call(a[g],g,a[g]),!1!==b);g++);else for(g in a)if
+(b=f.call(a[g],g,a[g]),!1===b)break;return a},trim:Za&&!Za.call("\ufeff\u00a0"
+)?function(a){return null==a?"":Za.call(a)}:function(a){return null==a?"":
+(a+"").replace(Tb,"")},makeArray:function(a,f){var b=f||[];return null!=a&&(m
+(Object(a))?c.merge(b,"string"==typeof a?[a]:a):
+Xa.call(b,a)),b},inArray:function(a,f,c){var b;if(f){if(ob)return ob.call(f,a
+,c);b=f.length;for(c=c?0>c?Math.max(0,b+c):c:0;b>c;c++)if(c in f&&f[c]===a
+)return c}return-1},merge:function(a,f){var c=f.length,b=a.length,g=0;if
+("number"==typeof c)for(;c>g;g++)a[b++]=f[g];else for(;f[g]!==p;)a[b++]=f[g++]
+;return a.length=b,a},grep:function(a,f,c){var b,g=[],l=0,u=a.length;for(c=!!c
+;u>l;l++)b=!!f(a[l],l),c!==b&&g.push(a[l]);return g},map:function(a,f,c){var b
+,g=0,l=a.length;b=m(a);var u=[];if(b)for(;l>
+g;g++)b=f(a[g],g,c),null!=b&&(u[u.length]=b);else for(g in a)b=f(a[g],g,c)
+,null!=b&&(u[u.length]=b);return Oa.apply([],u)},guid:1,proxy:function(a,f)
+{var b,t,g;return"string"==typeof f&&(b=a[f],f=a,a=b),c.isFunction(a)?(t=aa
+.call(arguments,2),g=function(){return a.apply(f||this,t.concat(aa.call
+(arguments)))},g.guid=a.guid=a.guid||c.guid++,g):p},access:function(a,f,b,t,g
+,l,u){var x=0,e=a.length,d=null==b;if("object"===c.type(b))for(x in g=!0,b)c
+.access(a,f,x,b[x],!0,l,u);else if(t!==p&&(g=!0,c.isFunction(t)||
+(u=!0),d&&(u?(f.call(a,t),f=null):(d=f,f=function(a,f,b){return d.call(c(a),b)
+})),f))for(;e>x;x++)f(a[x],b,u?t:t.call(a[x],x,f(a[x],b)));return g?a:d?f.call
+(a):e?f(a[0],b):l},now:function(){return(new Date).getTime()}});c.ready
+.promise=function(a){if(!G)if(G=c.Deferred(),"complete"===y.readyState
+)setTimeout(c.ready);else if(y.addEventListener)y.addEventListener
+("DOMContentLoaded",Qa,!1),v.addEventListener("load",c.ready,!1);else{y
+.attachEvent("onreadystatechange",Qa);v.attachEvent("onload",c.ready);
+var f=!1;try{f=null==v.frameElement&&y.documentElement}catch(b){}f&&f.doScroll
+&&function g(){if(!c.isReady){try{f.doScroll("left")}catch(a){return
+ setTimeout(g,50)}c.ready()}}()}return G.promise(a)};c.each("Boolean Number
+ String Function Array Date RegExp Object Error".split(" "),function(a,f){ha["
+[object "+f+"]"]=f.toLowerCase()});O=c(y);var kb={};c.Callbacks=function(a)
+{a="string"==typeof a?kb[a]||d(a):c.extend({},a);var f,b,t,g,l,u,x=[],e=!a
+.once&&[],q=function(c){f=a.memory&&c;b=!0;u=g||0;g=0;
+l=x.length;for(t=!0;x&&l>u;u++)if(!1===x[u].apply(c[0],c[1])&&a.stopOnFalse)
+{f=!1;break}t=!1;x&&(e?e.length&&q(e.shift()):f?x=[]:h.disable())},h=
+{add:function(){if(x){var b=x.length;(function Pb(f){c.each(f,function(f,b)
+{var k=c.type(b);"function"===k?a.unique&&h.has(b)||x.push(b):b&&b.length&
+&"string"!==k&&Pb(b)})})(arguments);t?l=x.length:f&&(g=b,q(f))}return this}
+,remove:function(){return x&&c.each(arguments,function(a,f){for(var b;-1<(b=c
+.inArray(f,x,b));)x.splice(b,1),t&&(l>=b&&l--,u>=b&&u--)}),
+this},has:function(a){return-1<c.inArray(a,x)},empty:function(){return x=[]
+,this},disable:function(){return x=e=f=p,this},disabled:function(){return!x}
+,lock:function(){return e=p,f||h.disable(),this},locked:function(){return!e}
+,fireWith:function(a,f){return f=f||[],f=[a,f.slice?f.slice():f],!x||b&&!e||
+(t?e.push(f):q(f)),this},fire:function(){return h.fireWith(this,arguments)
+,this},fired:function(){return!!b}};return h};c.extend({Deferred:function(a)
+{var f=[["resolve","done",c.Callbacks("once memory"),
+"resolved"],["reject","fail",c.Callbacks("once memory"),"rejected"],["notify"
+,"progress",c.Callbacks("memory")]],b="pending",t={state:function(){return b}
+,always:function(){return g.done(arguments).fail(arguments),this}
+,then:function(){var a=arguments;return c.Deferred(function(b){c.each(f
+,function(f,k){var e=k[0],d=c.isFunction(a[f])&&a[f];g[k[1]](function(){var
+ a=d&&d.apply(this,arguments);a&&c.isFunction(a.promise)?a.promise().done(b
+.resolve).fail(b.reject).progress(b.notify):b[e+"With"](this===
+t?b.promise():this,d?[a]:arguments)})});a=null}).promise()},promise:function(a
+){return null!=a?c.extend(a,t):t}},g={};return t.pipe=t.then,c.each(f,function
+(a,c){var e=c[2],d=c[3];t[c[1]]=e.add;d&&e.add(function(){b=d},f[1^a][2]
+.disable,f[2][2].lock);g[c[0]]=function(){return g[c[0]+"With"]
+(this===g?t:this,arguments),this};g[c[0]+"With"]=e.fireWith}),t.promise(g),a&
+&a.call(g,g),g},when:function(a){var f,b,t,g=0,l=aa.call(arguments),u=l.length
+,e=1!==u||a&&c.isFunction(a.promise)?u:0,d=1===e?a:c.Deferred(),
+q=function(a,c,b){return function(k){c[a]=this;b[a]=1<arguments.length?aa.call
+(arguments):k;b===f?d.notifyWith(c,b):--e||d.resolveWith(c,b)}};if(1<u)for
+(f=Array(u),b=Array(u),t=Array(u);u>g;g++)l[g]&&c.isFunction(l[g].promise)?l[g
+].promise().done(q(g,t,l)).fail(d.reject).progress(q(g,b,f)):--e;return e||d
+.resolveWith(t,l),d.promise()}});c.support=function(){var a,f,b,t,g,l,u,e=y
+.createElement("div");if(e.setAttribute("className","t"),e.innerHTML=
+" <link/><table></table><a href='/a'>a</a><input type='checkbox'/>",
+f=e.getElementsByTagName("*"),b=e.getElementsByTagName("a")[0],!f||!b||!f
+.length)return{};t=y.createElement("select");g=t.appendChild(y.createElement
+("option"));f=e.getElementsByTagName("input")[0];b.style.cssText="top:1px
+;float:left;opacity:.5";a={getSetAttribute:"t"!==e.className
+,leadingWhitespace:3===e.firstChild.nodeType,tbody:!e.getElementsByTagName
+("tbody").length,htmlSerialize:!!e.getElementsByTagName("link").length
+,style:/top/.test(b.getAttribute("style")),hrefNormalized:"/a"===b
+.getAttribute("href"),
+opacity:/^0.5/.test(b.style.opacity),cssFloat:!!b.style.cssFloat,checkOn:!!f
+.value,optSelected:g.selected,enctype:!!y.createElement("form").enctype
+,html5Clone:"<:nav></:nav>"!==y.createElement("nav").cloneNode(!0).outerHTML
+,boxModel:"CSS1Compat"===y.compatMode,deleteExpando:!0,noCloneEvent:!0
+,inlineBlockNeedsLayout:!1,shrinkWrapBlocks:!1,reliableMarginRight:!0
+,boxSizingReliable:!0,pixelPosition:!1};f.checked=!0;a.noCloneChecked=f
+.cloneNode(!0).checked;t.disabled=!0;a.optDisabled=!g.disabled;try{delete e
+.test}catch(d){a.deleteExpando=
+!1}f=y.createElement("input");f.setAttribute("value","");a.input=""===f
+.getAttribute("value");f.value="t";f.setAttribute("type","radio");a
+.radioValue="t"===f.value;f.setAttribute("checked","t");f.setAttribute("name"
+,"t");b=y.createDocumentFragment();b.appendChild(f);a.appendChecked=f.checked
+;a.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked;e.attachEvent&&
+(e.attachEvent("onclick",function(){a.noCloneEvent=!1}),e.cloneNode(!0).click(
+));for(u in{submit:!0,change:!0,focusin:!0})e.setAttribute(b=
+"on"+u,"t"),a[u+"Bubbles"]=b in v||!1===e.attributes[b].expando;return e.style
+.backgroundClip="content-box",e.cloneNode(!0).style.backgroundClip="",a
+.clearCloneStyle="content-box"===e.style.backgroundClip,c(function(){var f,b,c
+,k=y.getElementsByTagName("body")[0];k&&(f=y.createElement("div"),f.style
+.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px
+;margin-top:1px",k.appendChild(f).appendChild(e),e
+.innerHTML="<table><tr><td></td><td>t</td></tr></table>",c=e
+.getElementsByTagName("td"),
+c[0].style.cssText="padding:0;margin:0;border:0;display:none",l=0===c[0]
+.offsetHeight,c[0].style.display="",c[1].style.display="none",a
+.reliableHiddenOffsets=l&&0===c[0].offsetHeight,e.innerHTML="",e.style
+.cssText="box-sizing:border-box;-moz-box-sizing:border-box
+;-webkit-box-sizing:border-box;padding:1px;border:1px;display:block;width:4px
+;margin-top:1%;position:absolute;top:1%;",a.boxSizing=4===e.offsetWidth,a
+.doesNotIncludeMarginInBodyOffset=1!==k.offsetTop,v.getComputedStyle&&(a
+.pixelPosition="1%"!==
+(v.getComputedStyle(e,null)||{}).top,a.boxSizingReliable="4px"===(v
+.getComputedStyle(e,null)||{width:"4px"}).width,b=e.appendChild(y
+.createElement("div")),b.style.cssText=e.style.cssText="padding:0;margin:0
+;border:0;display:block;box-sizing:content-box;-moz-box-sizing:content-box
+;-webkit-box-sizing:content-box;",b.style.marginRight=b.style.width="0",e
+.style.width="1px",a.reliableMarginRight=!parseFloat((v.getComputedStyle(b
+,null)||{}).marginRight)),e.style.zoom!==p&&(e.innerHTML="",e.style.cssText=
+"padding:0;margin:0;border:0;display:block;box-sizing:content-box
+;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;width:1px
+;padding:1px;display:inline;zoom:1",a.inlineBlockNeedsLayout=3===e.offsetWidth
+,e.style.display="block",e.innerHTML="<div></div>",e.firstChild.style
+.width="5px",a.shrinkWrapBlocks=3!==e.offsetWidth,k.style.zoom=1),k
+.removeChild(f),e=null)}),f=t=b=g=b=f=null,a}();var Kb=/(?:\{[\s\S]*\}|\[[\s\S
+]*\])$/,Jb=/([A-Z])/g;c.extend({cache:{},expando:"jQuery"+("1.9.0"+Math.random
+()).replace(/\D/g,
+""),noData:{embed:!0,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"
+,applet:!0},hasData:function(a){return a=a.nodeType?c.cache[a[c.expando]]:a[c
+.expando],!!a&&!B(a)},data:function(a,f,b){return n(a,f,b,!1)}
+,removeData:function(a,f){return h(a,f,!1)},_data:function(a,f,b){return n(a,f
+,b,!0)},_removeData:function(a,f){return h(a,f,!0)},acceptData:function(a){var
+ f=a.nodeName&&c.noData[a.nodeName.toLowerCase()];return!f||!0!==f&&a
+.getAttribute("classid")===f}});c.fn.extend({data:function(a,f){var b,
+t,g=this[0],l=0,e=null;if(a===p){if(this.length&&(e=c.data(g),1===g.nodeType&
+&!c._data(g,"parsedAttrs"))){for(b=g.attributes;b.length>l;l++)t=b[l].name,t
+.indexOf("data-")||(t=c.camelCase(t.substring(5)),r(g,t,e[t]));c._data(g
+,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){c
+.data(this,a)}):c.access(this,function(f){return f===p?g?r(g,a,c.data(g,a)
+):null:(this.each(function(){c.data(this,a,f)}),p)},null,f,1<arguments.length
+,null,!0)},removeData:function(a){return this.each(function(){c.removeData
+(this,
+a)})}});c.extend({queue:function(a,f,b){var t;return a?(f=(f||"fx")+"queue"
+,t=c._data(a,f),b&&(!t||c.isArray(b)?t=c._data(a,f,c.makeArray(b)):t.push(b))
+,t||[]):p},dequeue:function(a,f){f=f||"fx";var b=c.queue(a,f),t=b.length,g=b
+.shift(),l=c._queueHooks(a,f),e=function(){c.dequeue(a,f)};"inprogress"===g&&
+(g=b.shift(),t--);(l.cur=g)&&("fx"===f&&b.unshift("inprogress"),delete l.stop
+,g.call(a,e,l));!t&&l&&l.empty.fire()},_queueHooks:function(a,f){var
+ b=f+"queueHooks";return c._data(a,b)||c._data(a,b,
+{empty:c.Callbacks("once memory").add(function(){c._removeData(a,f+"queue");c
+._removeData(a,b)})})}});c.fn.extend({queue:function(a,f){var b=2
+;return"string"!=typeof a&&(f=a,a="fx",b--),b>arguments.length?c.queue(this[0]
+,a):f===p?this:this.each(function(){var b=c.queue(this,a,f);c._queueHooks(this
+,a);"fx"===a&&"inprogress"!==b[0]&&c.dequeue(this,a)})},dequeue:function(a)
+{return this.each(function(){c.dequeue(this,a)})},delay:function(a,f){return
+ a=c.fx?c.fx.speeds[a]||a:a,f=f||"fx",this.queue(f,function(f,
+b){var c=setTimeout(f,a);b.stop=function(){clearTimeout(c)}})}
+,clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,f)
+{var b,t=1,g=c.Deferred(),l=this,e=this.length,d=function(){--t||g.resolveWith
+(l,[l])};"string"!=typeof a&&(f=a,a=p);for(a=a||"fx";e--;)(b=c._data(l[e]
+,a+"queueHooks"))&&b.empty&&(t++,b.empty.add(d));return d(),g.promise(f)}})
+;var ma,qb,$a=/[\t\r\n]/g,bc=/\r/g,cc=/^(?:input|select|textarea|button|object
+)$/i,dc=/^(?:a|area)$/i,rb=/^(?:checked|selected|autofocus|autoplay|async
+|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped
+)$/i,
+ab=/^(?:checked|selected)$/i,ia=c.support.getSetAttribute,bb=c.support.input;c
+.fn.extend({attr:function(a,f){return c.access(this,c.attr,a,f,1<arguments
+.length)},removeAttr:function(a){return this.each(function(){c.removeAttr(this
+,a)})},prop:function(a,f){return c.access(this,c.prop,a,f,1<arguments.length)}
+,removeProp:function(a){return a=c.propFix[a]||a,this.each(function(){try{this
+[a]=p,delete this[a]}catch(f){}})},addClass:function(a){var f,b,t,g,l,e=0
+,d=this.length;f="string"==typeof a&&a;if(c.isFunction(a))return this.each
+(function(f){c(this).addClass(a.call(this,
+f,this.className))});if(f)for(f=(a||"").match(Z)||[];d>e;e++)if(b=this[e]
+,t=1===b.nodeType&&(b.className?(" "+b.className+" ").replace($a," "):" "))
+{for(l=0;g=f[l++];)0>t.indexOf(" "+g+" ")&&(t+=g+" ");b.className=c.trim(t)
+}return this},removeClass:function(a){var f,b,t,g,l,e=0,d=this.length
+;f=0===arguments.length||"string"==typeof a&&a;if(c.isFunction(a))return this
+.each(function(f){c(this).removeClass(a.call(this,f,this.className))});if(f
+)for(f=(a||"").match(Z)||[];d>e;e++)if(b=this[e],t=1===b.nodeType&&
+(b.className?(" "+b.className+" ").replace($a," "):"")){for(l=0;g=f[l++];)for(
+;0<=t.indexOf(" "+g+" ");)t=t.replace(" "+g+" "," ");b.className=a?c.trim(t
+):""}return this},toggleClass:function(a,f){var b=typeof a,t="boolean"==typeof
+ f;return c.isFunction(a)?this.each(function(b){c(this).toggleClass(a.call
+(this,b,this.className,f),f)}):this.each(function(){if("string"===b)for(var g
+,l=0,e=c(this),d=f,q=a.match(Z)||[];g=q[l++];)d=t?d:!e.hasClass(g),e
+[d?"addClass":"removeClass"](g);else("undefined"===
+b||"boolean"===b)&&(this.className&&c._data(this,"__className__",this
+.className),this.className=this.className||!1===a?"":c._data(this
+,"__className__")||"")})},hasClass:function(a){a=" "+a+" ";for(var f=0,b=this
+.length;b>f;f++)if(1===this[f].nodeType&&0<=(" "+this[f].className+" ")
+.replace($a," ").indexOf(a))return!0;return!1},val:function(a){var f,b,t
+,g=this[0];if(arguments.length)return t=c.isFunction(a),this.each(function(b)
+{var k,g=c(this);1===this.nodeType&&(k=t?a.call(this,b,g.val()):a,null==
+k?k="":"number"==typeof k?k+="":c.isArray(k)&&(k=c.map(k,function(a){return
+ null==a?"":a+""})),f=c.valHooks[this.type]||c.valHooks[this.nodeName
+.toLowerCase()],f&&"set"in f&&f.set(this,k,"value")!==p||(this.value=k))});if
+(g)return f=c.valHooks[g.type]||c.valHooks[g.nodeName.toLowerCase()],f&
+&"get"in f&&(b=f.get(g,"value"))!==p?b:(b=g.value,"string"==typeof b?b.replace
+(bc,""):null==b?"":b)}});c.extend({valHooks:{option:{get:function(a){var f=a
+.attributes.value;return!f||f.specified?a.value:a.text}},
+select:{get:function(a){for(var f,b=a.options,t=a.selectedIndex
+,g="select-one"===a.type||0>t,l=g?null:[],e=g?t+1:b.length,d=0>t?e:g?t:0;e>d
+;d++)if(f=b[d],!(!f.selected&&d!==t||(c.support.optDisabled?f
+.disabled:null!==f.getAttribute("disabled"))||f.parentNode.disabled&&c
+.nodeName(f.parentNode,"optgroup"))){if(a=c(f).val(),g)return a;l.push(a)
+}return l},set:function(a,f){var b=c.makeArray(f);return c(a).find("option")
+.each(function(){this.selected=0<=c.inArray(c(this).val(),b)}),b.length||(a
+.selectedIndex=
+-1),b}}},attr:function(a,f,b){var t,g,l,e=a.nodeType;if(a&&3!==e&&8!==e&&2!==e
+)return a.getAttribute===p?c.prop(a,f,b):(l=1!==e||!c.isXMLDoc(a),l&&(f=f
+.toLowerCase(),g=c.attrHooks[f]||(rb.test(f)?qb:ma)),b===p?g&&l&&"get"in g&
+&null!==(t=g.get(a,f))?t:(a.getAttribute!==p&&(t=a.getAttribute(f))
+,null==t?p:t):null!==b?g&&l&&"set"in g&&(t=g.set(a,b,f))!==p?t:(a.setAttribute
+(f,b+""),b):(c.removeAttr(a,f),p))},removeAttr:function(a,f){var b,t,g=0,e=f&
+&f.match(Z);if(e&&1===a.nodeType)for(;b=e[g++];)t=c.propFix[b]||
+b,rb.test(b)?!ia&&ab.test(b)?a[c.camelCase("default-"+b)]=a[t]=!1:a[t]=!1:c
+.attr(a,b,""),a.removeAttribute(ia?b:t)},attrHooks:{type:{set:function(a,f){if
+(!c.support.radioValue&&"radio"===f&&c.nodeName(a,"input")){var b=a.value
+;return a.setAttribute("type",f),b&&(a.value=b),f}}}},propFix:
+{tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className"
+,maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding"
+,rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder"
+,
+contenteditable:"contentEditable"},prop:function(a,f,b){var t,g,e,u=a.nodeType
+;if(a&&3!==u&&8!==u&&2!==u)return e=1!==u||!c.isXMLDoc(a),e&&(f=c.propFix[f]|
+|f,g=c.propHooks[f]),b!==p?g&&"set"in g&&(t=g.set(a,b,f))!==p?t:a[f]=b:g&
+&"get"in g&&null!==(t=g.get(a,f))?t:a[f]},propHooks:{tabIndex:{get:function(a)
+{var f=a.getAttributeNode("tabindex");return f&&f.specified?parseInt(f.value
+,10):cc.test(a.nodeName)||dc.test(a.nodeName)&&a.href?0:p}}}});qb=
+{get:function(a,f){var b=c.prop(a,f),t="boolean"==typeof b&&
+a.getAttribute(f);return(b="boolean"==typeof b?bb&&ia?null!=t:ab.test(f)?a[c
+.camelCase("default-"+f)]:!!t:a.getAttributeNode(f))&&!1!==b.value?f
+.toLowerCase():p},set:function(a,f,b){return!1===f?c.removeAttr(a,b):bb&&ia|
+|!ab.test(b)?a.setAttribute(!ia&&c.propFix[b]||b,b):a[c.camelCase("default-"+b
+)]=a[b]=!0,b}};bb&&ia||(c.attrHooks.value={get:function(a,f){var b=a
+.getAttributeNode(f);return c.nodeName(a,"input")?a.defaultValue:b&&b
+.specified?b.value:p},set:function(a,f,b){return c.nodeName(a,"input")?
+(a.defaultValue=f,p):ma&&ma.set(a,f,b)}});ia||(ma=c.valHooks.button=
+{get:function(a,f){var b=a.getAttributeNode(f);return b&&("id"===f||"name"===f
+||"coords"===f?""!==b.value:b.specified)?b.value:p},set:function(a,f,b){var
+ c=a.getAttributeNode(b);return c||a.setAttributeNode(c=a.ownerDocument
+.createAttribute(b)),c.value=f+="","value"===b||f===a.getAttribute(b)?f:p}},c
+.attrHooks.contenteditable={get:ma.get,set:function(a,b,c){ma.set(a
+,""===b?!1:b,c)}},c.each(["width","height"],function(a,b){c.attrHooks[b]=
+c.extend(c.attrHooks[b],{set:function(a,c){return""===c?(a.setAttribute(b
+,"auto"),c):p}})}));c.support.hrefNormalized||(c.each(["href","src","width"
+,"height"],function(a,b){c.attrHooks[b]=c.extend(c.attrHooks[b],{get:function
+(a){a=a.getAttribute(b,2);return null==a?p:a}})}),c.each(["href","src"]
+,function(a,b){c.propHooks[b]={get:function(a){return a.getAttribute(b,4)}}}))
+;c.support.style||(c.attrHooks.style={get:function(a){return a.style.cssText|
+|p},set:function(a,b){return a.style.cssText=b+""}});
+c.support.optSelected||(c.propHooks.selected=c.extend(c.propHooks.selected,
+{get:function(a){a=a.parentNode;return a&&(a.selectedIndex,a.parentNode&&a
+.parentNode.selectedIndex),null}}));c.support.enctype||(c.propFix
+.enctype="encoding");c.support.checkOn||c.each(["radio","checkbox"],function()
+{c.valHooks[this]={get:function(a){return null===a.getAttribute("value"
+)?"on":a.value}}});c.each(["radio","checkbox"],function(){c.valHooks[this]=c
+.extend(c.valHooks[this],{set:function(a,b){return c.isArray(b)?
+a.checked=0<=c.inArray(c(a).val(),b):p}})});var cb=/^(?:input|select|textarea
+)$/i,ec=/^key/,fc=/^(?:mouse|contextmenu)|click/,sb=/^(?:focusinfocus
+|focusoutblur)$/,tb=/^([^.]*)(?:\.(.+)|)$/;c.event={global:{},add:function(a,b
+,k,t,g){var e,u,d,q,h,m,n,w,r;if(h=3!==a.nodeType&&8!==a.nodeType&&c._data(a))
+{k.handler&&(e=k,k=e.handler,g=e.selector);k.guid||(k.guid=c.guid++);(q=h
+.events)||(q=h.events={});(u=h.handle)||(u=h.handle=function(a){return c===p|
+|a&&c.event.triggered===a.type?p:c.event.dispatch.apply(u.elem,
+arguments)},u.elem=a);b=(b||"").match(Z)||[""];for(h=b.length;h--;)d=tb.exec(b
+[h])||[],w=m=d[1],r=(d[2]||"").split(".").sort(),d=c.event.special[w]||{},w=
+(g?d.delegateType:d.bindType)||w,d=c.event.special[w]||{},m=c.extend({type:w
+,origType:m,data:t,handler:k,guid:k.guid,selector:g,needsContext:g&&c.expr
+.match.needsContext.test(g),namespace:r.join(".")},e),(n=q[w])||(n=q[w]=[],n
+.delegateCount=0,d.setup&&!1!==d.setup.call(a,t,r,u)||(a.addEventListener?a
+.addEventListener(w,u,!1):a.attachEvent&&a.attachEvent("on"+
+w,u))),d.add&&(d.add.call(a,m),m.handler.guid||(m.handler.guid=k.guid)),g?n
+.splice(n.delegateCount++,0,m):n.push(m),c.event.global[w]=!0;a=null}}
+,remove:function(a,b,k,e,g){var l,u,d,q,h,m,n,w,p,r,z,v=c.hasData(a)&&c._data
+(a);if(v&&(q=v.events)){b=(b||"").match(Z)||[""];for(h=b.length;h--;)if(d=tb
+.exec(b[h])||[],p=z=d[1],r=(d[2]||"").split(".").sort(),p){n=c.event.special[p
+]||{};p=(e?n.delegateType:n.bindType)||p;w=q[p]||[];d=d[2]&&RegExp("(^|\\.)"+r
+.join("\\.(?:.*\\.|)")+"(\\.|$)");for(u=l=w.length;l--;)m=
+w[l],!g&&z!==m.origType||k&&k.guid!==m.guid||d&&!d.test(m.namespace)||e&&e!==m
+.selector&&("**"!==e||!m.selector)||(w.splice(l,1),m.selector&&w
+.delegateCount--,n.remove&&n.remove.call(a,m));u&&!w.length&&(n.teardown&
+&!1!==n.teardown.call(a,r,v.handle)||c.removeEvent(a,p,v.handle),delete q[p])
+}else for(p in q)c.event.remove(a,p+b[h],k,e,!0);c.isEmptyObject(q)&&(delete v
+.handle,c._removeData(a,"events"))}},trigger:function(a,b,k,e){var g,l,d,q,h,m
+,n=[k||y],w=a.type||a;h=a.namespace?a.namespace.split("."):
+[];if(l=g=k=k||y,3!==k.nodeType&&8!==k.nodeType&&!sb.test(w+c.event.triggered)
+&&(0<=w.indexOf(".")&&(h=w.split("."),w=h.shift(),h.sort()),q=0>w.indexOf(":")
+&&"on"+w,a=a[c.expando]?a:new c.Event(w,"object"==typeof a&&a),a.isTrigger=!0
+,a.namespace=h.join("."),a.namespace_re=a.namespace?RegExp("(^|\\.)"+h.join
+("\\.(?:.*\\.|)")+"(\\.|$)"):null,a.result=p,a.target||(a.target=k),b=null==b?
+[a]:c.makeArray(b,[a]),m=c.event.special[w]||{},e||!m.trigger||!1!==m.trigger
+.apply(k,b))){if(!e&&!m.noBubble&&!c.isWindow(k)){d=
+m.delegateType||w;for(sb.test(d+w)||(l=l.parentNode);l;l=l.parentNode)n.push(l
+),g=l;g===(k.ownerDocument||y)&&n.push(g.defaultView||g.parentWindow||v)}for
+(g=0;(l=n[g++])&&!a.isPropagationStopped();)a.type=1<g?d:m.bindType||w,(h=(c
+._data(l,"events")||{})[a.type]&&c._data(l,"handle"))&&h.apply(l,b),(h=q&&l[q]
+)&&c.acceptData(l)&&h.apply&&!1===h.apply(l,b)&&a.preventDefault();if(a.type=w
+,!(e||a.isDefaultPrevented()||m._default&&!1!==m._default.apply(k
+.ownerDocument,b)||"click"===w&&c.nodeName(k,"a"))&&
+c.acceptData(k)&&q&&k[w]&&!c.isWindow(k)){(g=k[q])&&(k[q]=null);c.event
+.triggered=w;try{k[w]()}catch(r){}c.event.triggered=p;g&&(k[q]=g)}return a
+.result}},dispatch:function(a){a=c.event.fix(a);var b,k,e,g,l,d=[],q=aa.call
+(arguments);b=(c._data(this,"events")||{})[a.type]||[];var h=c.event.special[a
+.type]||{};if(q[0]=a,a.delegateTarget=this,!h.preDispatch||!1!==h.preDispatch
+.call(this,a)){d=c.event.handlers.call(this,a,b);for(b=0;(g=d[b++])&&!a
+.isPropagationStopped();)for(a.currentTarget=g.elem,k=
+0;(l=g.handlers[k++])&&!a.isImmediatePropagationStopped();)a.namespace_re&&!a
+.namespace_re.test(l.namespace)||(a.handleObj=l,a.data=l.data,e=((c.event
+.special[l.origType]||{}).handle||l.handler).apply(g.elem,q),e===p||!1!==(a
+.result=e)||(a.preventDefault(),a.stopPropagation()));return h.postDispatch&&h
+.postDispatch.call(this,a),a.result}},handlers:function(a,b){var k,e,g,l,d=[]
+,q=b.delegateCount,h=a.target;if(q&&h.nodeType&&(!a.button||"click"!==a.type)
+)for(;h!=this;h=h.parentNode||this)if(!0!==h.disabled||
+"click"!==a.type){e=[];for(k=0;q>k;k++)l=b[k],g=l.selector+" ",e[g]===p&&(e[g
+]=l.needsContext?0<=c(g,this).index(h):c.find(g,this,null,[h]).length),e[g]&&e
+.push(l);e.length&&d.push({elem:h,handlers:e})}return b.length>q&&d.push(
+{elem:this,handlers:b.slice(q)}),d},fix:function(a){if(a[c.expando])return a
+;var b,k,e=a,g=c.event.fixHooks[a.type]||{},l=g.props?this.props.concat(g
+.props):this.props;a=new c.Event(e);for(b=l.length;b--;)k=l[b],a[k]=e[k]
+;return a.target||(a.target=e.srcElement||y),3===a.target.nodeType&&
+(a.target=a.target.parentNode),a.metaKey=!!a.metaKey,g.filter?g.filter(a,e):a}
+,props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey
+ relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{}
+,keyHooks:{props:["char","charCode","key","keyCode"],filter:function(a,b)
+{return null==a.which&&(a.which=null!=b.charCode?b.charCode:b.keyCode),a}}
+,mouseHooks:{props:"button buttons clientX clientY fromElement offsetX offsetY
+ pageX pageY screenX screenY toElement".split(" "),
+filter:function(a,b){var c,e,g,l=b.button,d=b.fromElement;return null==a.pageX
+&&null!=b.clientX&&(c=a.target.ownerDocument||y,e=c.documentElement,g=c.body,a
+.pageX=b.clientX+(e&&e.scrollLeft||g&&g.scrollLeft||0)-(e&&e.clientLeft||g&&g
+.clientLeft||0),a.pageY=b.clientY+(e&&e.scrollTop||g&&g.scrollTop||0)-(e&&e
+.clientTop||g&&g.clientTop||0)),!a.relatedTarget&&d&&(a.relatedTarget=d===a
+.target?b.toElement:d),a.which||l===p||(a.which=1&l?1:2&l?3:4&l?2:0),a}}
+,special:{load:{noBubble:!0},click:{trigger:function(){return c.nodeName(this,
+"input")&&"checkbox"===this.type&&this.click?(this.click(),!1):p}},focus:
+{trigger:function(){if(this!==y.activeElement&&this.focus)try{return this
+.focus(),!1}catch(a){}},delegateType:"focusin"},blur:{trigger:function()
+{return this===y.activeElement&&this.blur?(this.blur(),!1):p}
+,delegateType:"focusout"},beforeunload:{postDispatch:function(a){a.result!==p&
+&(a.originalEvent.returnValue=a.result)}}},simulate:function(a,b,k,e){a=c
+.extend(new c.Event,k,{type:a,isSimulated:!0,originalEvent:{}});e?c.event
+.trigger(a,
+null,b):c.event.dispatch.call(b,a);a.isDefaultPrevented()&&k.preventDefault()}
+};c.removeEvent=y.removeEventListener?function(a,b,c){a.removeEventListener&&a
+.removeEventListener(b,c,!1)}:function(a,b,c){b="on"+b;a.detachEvent&&(a[b
+]===p&&(a[b]=null),a.detachEvent(b,c))};c.Event=function(a,b){return this
+ instanceof c.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this
+.isDefaultPrevented=a.defaultPrevented||!1===a.returnValue||a
+.getPreventDefault&&a.getPreventDefault()?D:M):this.type=a,b&&c.extend(this,
+b),this.timeStamp=a&&a.timeStamp||c.now(),this[c.expando]=!0,p):new c.Event(a
+,b)};c.Event.prototype={isDefaultPrevented:M,isPropagationStopped:M
+,isImmediatePropagationStopped:M,preventDefault:function(){var a=this
+.originalEvent;this.isDefaultPrevented=D;a&&(a.preventDefault?a.preventDefault
+():a.returnValue=!1)},stopPropagation:function(){var a=this.originalEvent;this
+.isPropagationStopped=D;a&&(a.stopPropagation&&a.stopPropagation(),a
+.cancelBubble=!0)},stopImmediatePropagation:function(){this
+.isImmediatePropagationStopped=
+D;this.stopPropagation()}};c.each({mouseenter:"mouseover"
+,mouseleave:"mouseout"},function(a,b){c.event.special[a]={delegateType:b
+,bindType:b,handle:function(a){var e,g=this,l=a.relatedTarget,d=a.handleObj
+;return(!l||l!==g&&!c.contains(g,l))&&(a.type=d.origType,e=d.handler.apply
+(this,arguments),a.type=b),e}}});c.support.submitBubbles||(c.event.special
+.submit={setup:function(){return c.nodeName(this,"form")?!1:(c.event.add(this
+,"click._submit keypress._submit",function(a){a=a.target;(a=c.nodeName(a,
+"input")||c.nodeName(a,"button")?a.form:p)&&!c._data(a,"submitBubbles")&&(c
+.event.add(a,"submit._submit",function(a){a._submit_bubble=!0}),c._data(a
+,"submitBubbles",!0))}),p)},postDispatch:function(a){a._submit_bubble&&(delete
+ a._submit_bubble,this.parentNode&&!a.isTrigger&&c.event.simulate("submit"
+,this.parentNode,a,!0))},teardown:function(){return c.nodeName(this,"form"
+)?!1:(c.event.remove(this,"._submit"),p)}});c.support.changeBubbles||(c.event
+.special.change={setup:function(){return cb.test(this.nodeName)?
+(("checkbox"===this.type||"radio"===this.type)&&(c.event.add(this
+,"propertychange._change",function(a){"checked"===a.originalEvent.propertyName
+&&(this._just_changed=!0)}),c.event.add(this,"click._change",function(a){this
+._just_changed&&!a.isTrigger&&(this._just_changed=!1);c.event.simulate
+("change",this,a,!0)})),!1):(c.event.add(this,"beforeactivate._change"
+,function(a){a=a.target;cb.test(a.nodeName)&&!c._data(a,"changeBubbles")&&(c
+.event.add(a,"change._change",function(a){!this.parentNode||a.isSimulated||
+a.isTrigger||c.event.simulate("change",this.parentNode,a,!0)}),c._data(a
+,"changeBubbles",!0))}),p)},handle:function(a){var b=a.target;return this!==b|
+|a.isSimulated||a.isTrigger||"radio"!==b.type&&"checkbox"!==b.type?a.handleObj
+.handler.apply(this,arguments):p},teardown:function(){return c.event.remove
+(this,"._change"),!cb.test(this.nodeName)}});c.support.focusinBubbles||c.each(
+{focus:"focusin",blur:"focusout"},function(a,b){var k=0,e=function(a){c.event
+.simulate(b,a.target,c.event.fix(a),!0)};c.event.special[b]=
+{setup:function(){0===k++&&y.addEventListener(a,e,!0)},teardown:function()
+{0===--k&&y.removeEventListener(a,e,!0)}}});c.fn.extend({on:function(a,b,k,e,g
+){var l,d;if("object"==typeof a){"string"!=typeof b&&(k=k||b,b=p);for(d in a
+)this.on(d,b,k,a[d],g);return this}if(null==k&&null==e?(e=b,k=b=p):null==e&&
+("string"==typeof b?(e=k,k=p):(e=k,k=b,b=p)),!1===e)e=M;else if(!e)return this
+;return 1===g&&(l=e,e=function(a){return c().off(a),l.apply(this,arguments)},e
+.guid=l.guid||(l.guid=c.guid++)),this.each(function(){c.event.add(this,
+a,e,k,b)})},one:function(a,b,c,e){return this.on(a,b,c,e,1)},off:function(a,b
+,k){var e,g;if(a&&a.preventDefault&&a.handleObj)return e=a.handleObj,c(a
+.delegateTarget).off(e.namespace?e.origType+"."+e.namespace:e.origType,e
+.selector,e.handler),this;if("object"==typeof a){for(g in a)this.off(g,b,a[g])
+;return this}return(!1===b||"function"==typeof b)&&(k=b,b=p),!1===k&&(k=M)
+,this.each(function(){c.event.remove(this,a,k,b)})},bind:function(a,b,c)
+{return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,
+null,b)},delegate:function(a,b,c,e){return this.on(b,a,c,e)}
+,undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this
+.off(b,a||"**",c)},trigger:function(a,b){return this.each(function(){c.event
+.trigger(a,b,this)})},triggerHandler:function(a,b){var k=this[0];return k?c
+.event.trigger(a,b,k,!0):p},hover:function(a,b){return this.mouseenter(a)
+.mouseleave(b||a)}});c.each("blur focus focusin focusout load resize scroll
+ unload click dblclick mousedown mouseup mousemove mouseover mouseout
+ mouseenter mouseleave change select submit keydown keypress keyup error
+ contextmenu".split(" "),
+function(a,b){c.fn[b]=function(a,c){return 0<arguments.length?this.on(b,null,a
+,c):this.trigger(b)};ec.test(b)&&(c.event.fixHooks[b]=c.event.keyHooks);fc
+.test(b)&&(c.event.fixHooks[b]=c.event.mouseHooks)});(function(a,b){function k
+(a){return ia.test(a+"")}function e(){var a,b=[];return a=function(c,f){return
+ b.push(c+=" ")>A.cacheLength&&delete a[b.shift()],a[c]=f}}function g(a)
+{return a[K]=!0,a}function l(a){var b=T.createElement("div");try{return a(b)
+}catch(c){return!1}finally{}}function d(a,b,c,
+f){var k,g,e,l,t;if((b?b.ownerDocument||b:qa)!==T&&F(b),b=b||T,c=c||[],!a|
+|"string"!=typeof a)return c;if(1!==(l=b.nodeType)&&9!==l)return[];if(!ba&&!f)
+{if(k=ja.exec(a))if(e=k[1])if(9===l){if(g=b.getElementById(e),!g||!g
+.parentNode)return c;if(g.id===e)return c.push(g),c}else{if(b.ownerDocument&&
+(g=b.ownerDocument.getElementById(e))&&ta(b,g)&&g.id===e)return c.push(g),c
+}else{if(k[2])return Q.apply(c,R.call(b.getElementsByTagName(a),0)),c;if((e=k
+[3])&&L.getByClassName&&b.getElementsByClassName)return Q.apply(c,
+R.call(b.getElementsByClassName(e),0)),c}if(L.qsa&&!ca.test(a)){if(k=!0,g=K
+,e=b,t=9===l&&a,1===l&&"object"!==b.nodeName.toLowerCase()){l=w(a);(k=b
+.getAttribute("id"))?g=k.replace(ma,"\\$&"):b.setAttribute("id",g);g="
+[id='"+g+"'] ";for(e=l.length;e--;)l[e]=g+p(l[e]);e=aa.test(a)&&b.parentNode|
+|b;t=l.join(",")}if(t)try{return Q.apply(c,R.call(e.querySelectorAll(t),0)),c
+}catch(q){}finally{k||b.removeAttribute("id")}}}var u;a:{a=a.replace(ha,"$1")
+;var h,m,n;k=w(a);if(!f&&1===k.length){if(u=k[0]=k[0].slice(0),
+2<u.length&&"ID"===(h=u[0]).type&&9===b.nodeType&&!ba&&A.relative[u[1].type])
+{if(b=A.find.ID(h.matches[0].replace(na,oa),b)[0],!b){u=c;break a}a=a.slice(u
+.shift().value.length)}for(l=Y.needsContext.test(a)?-1:u.length-1;0<=l&&(h=u[l
+],!A.relative[m=h.type]);l--)if((n=A.find[m])&&(f=n(h.matches[0].replace(na,oa
+),aa.test(u[0].type)&&b.parentNode||b))){if(u.splice(l,1),a=f.length&&p(u),!a)
+{u=(Q.apply(c,R.call(f,0)),c);break a}break}}u=(M(a,k)(f,b,ba,c,aa.test(a)),c)
+}return u}function q(a,b){for(var c=
+a&&b&&a.nextSibling;c;c=c.nextSibling)if(c===b)return-1;return a?1:-1}function
+ h(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b
+.type===a}}function m(a){return function(b){var c=b.nodeName.toLowerCase()
+;return("input"===c||"button"===c)&&b.type===a}}function n(a){return g
+(function(b){return b=+b,g(function(c,f){for(var k,g=a([],c.length,b),e=g
+.length;e--;)c[k=g[e]]&&(c[k]=!(f[k]=c[k]))})})}function w(a,b){var c,f,k,g,e
+,l,t;if(e=S[a+" "])return b?0:e.slice(0);e=a;l=[];for(t=
+A.preFilter;e;){c&&!(f=da.exec(e))||(f&&(e=e.slice(f[0].length)||e),l.push(k=[
+]));c=!1;(f=ea.exec(e))&&(c=f.shift(),k.push({value:c,type:f[0].replace(ha," "
+)}),e=e.slice(c.length));for(g in A.filter)!(f=Y[g].exec(e))||t[g]&&!(f=t[g](f
+))||(c=f.shift(),k.push({value:c,type:g,matches:f}),e=e.slice(c.length));if(!c
+)break}return b?e.length:e?d.error(a):S(a,l).slice(0)}function p(a){for(var
+ b=0,c=a.length,f="";c>b;b++)f+=a[b].value;return f}function r(a,b,c){var f=b
+.dir,k=c&&"parentNode"===b.dir,g=Oa++;
+return b.first?function(b,c,g){for(;b=b[f];)if(1===b.nodeType||k)return a(b,c
+,g)}:function(b,c,e){var l,d,t,q=H+" "+g;if(e)for(;b=b[f];){if((1===b.nodeType
+||k)&&a(b,c,e))return!0}else for(;b=b[f];)if(1===b.nodeType||k)if(t=b[K]||(b[K
+]={}),(d=t[f])&&d[0]===q){if(!0===(l=d[1])||l===C)return!0===l}else if(d=t[f]=
+[q],d[1]=a(b,c,e)||C,!0===d[1])return!0}}function z(a){return 1<a
+.length?function(b,c,f){for(var k=a.length;k--;)if(!a[k](b,c,f))return!1
+;return!0}:a[0]}function v(a,b,c,f,k){for(var g,e=[],
+l=0,d=a.length,t=null!=b;d>l;l++)(g=a[l])&&(!c||c(g,f,k))&&(e.push(g),t&&b
+.push(l));return e}function B(a,b,c,f,k,e){return f&&!f[K]&&(f=B(f)),k&&!k[K]&
+&(k=B(k,e)),g(function(g,e,l,t){var q,h,m=[],n=[],x=e.length,w;if(!(w=g)){w=b|
+|"*";for(var p=l.nodeType?[l]:l,r=[],z=0,Va=p.length;Va>z;z++)d(w,p[z],r);w=r
+}w=!a||!g&&b?w:v(w,m,a,l,t);p=c?k||(g?a:x||f)?[]:e:w;if(c&&c(w,p,l,t),f)for
+(q=v(p,n),f(q,[],l,t),l=q.length;l--;)(h=q[l])&&(p[n[l]]=!(w[n[l]]=h));if(g)
+{if(k||a){if(k){q=[];for(l=p.length;l--;)(h=
+p[l])&&q.push(w[l]=h);k(null,p=[],q,t)}for(l=p.length;l--;)(h=p[l])&&-1<
+(q=k?Aa.call(g,h):m[l])&&(g[q]=!(e[q]=h))}}else p=v(p===e?p.splice(x,p.length
+):p),k?k(null,e,p,t):Q.apply(e,p)})}function y(a){var b,c,f,k=a.length,g=A
+.relative[a[0].type];c=g||A.relative[" "];for(var e=g?1:0,l=r(function(a)
+{return a===b},c,!0),d=r(function(a){return-1<Aa.call(b,a)},c,!0),t=[function
+(a,c,f){return!g&&(f||c!==Ra)||((b=c).nodeType?l(a,c,f):d(a,c,f))}];k>e;e++)if
+(c=A.relative[a[e].type])t=[r(z(t),c)];else{if(c=A.filter[a[e].type].apply
+(null,
+a[e].matches),c[K]){for(f=++e;k>f&&!A.relative[a[f].type];f++);return B(1<e&&z
+(t),1<e&&p(a.slice(0,e-1)).replace(ha,"$1"),c,f>e&&y(a.slice(e,f)),k>f&&y(a=a
+.slice(f)),k>f&&p(a))}t.push(c)}return z(t)}function J(a,b){var c=0,f=0<b
+.length,k=0<a.length,e=function(g,e,l,t,q){var h,m,n=[],w=0,p="0",x=g&&[]
+,r=null!=q,z=Ra,Va=g||k&&A.find.TAG("*",q&&e.parentNode||e)
+,B=H+=null==z?1:Math.E;for(r&&(Ra=e!==T&&e,C=c);null!=(q=Va[p]);p++){if(k&&q)
+{for(h=0;m=a[h];h++)if(m(q,e,l)){t.push(q);break}r&&(H=B,C=++c)}f&&
+((q=!m&&q)&&w--,g&&x.push(q))}if(w+=p,f&&p!==w){for(h=0;m=b[h];h++)m(x,n,e,l)
+;if(g){if(0<w)for(;p--;)x[p]||n[p]||(n[p]=Z.call(t));n=v(n)}Q.apply(t,n);r&&!g
+&&0<n.length&&1<w+b.length&&d.uniqueSort(t)}return r&&(H=B,Ra=z),x};return f?g
+(e):e}function N(){}var O,C,A,D,G,M,E,Ra,F,T,W,ba,ca,ua,Sa,ta,V
+,K="sizzle"+-new Date,qa=a.document,L={},H=0,Oa=0,Na=e(),S=e(),U=e(),I=typeof
+ b,P=[],Z=P.pop,Q=P.push,R=P.slice,Aa=P.indexOf||function(a){for(var b=0
+,c=this.length;c>b;b++)if(this[b]===a)return b;return-1},
+P="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+".replace("w","w#"),ra="\\[
+[\\x20\\t\\r\\n\\f]*((?:\\\\.|[\\w-]|[^\\x00-\\xa0])+)[\\x20\\t\\r\\n\\f]*(?:(
+[*^$|!~]?=)[\\x20\\t\\r\\n\\f]*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+P+")|)|)
+[\\x20\\t\\r\\n\\f]*\\]",X=":((?:\\\\.|[\\w-]|[^\\x00-\\xa0])+)(?:\\(((['\"])(
+(?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+ra.replace(3,8)+")*)|.*)\\)|
+)",ha=RegExp("^[\\x20\\t\\r\\n\\f]+|((?:^|[^\\\\])(?:\\\\.)*)
+[\\x20\\t\\r\\n\\f]+$","g"),da=/^[\x20\t\r\n\f]*,[\x20\t\r\n\f]*/,ea=
+/^[\x20\t\r\n\f]*([\x20\t\r\n\f>+~])[\x20\t\r\n\f]*/,fa=RegExp(X),ga=RegExp
+("^"+P+"$"),Y={ID:/^#((?:\\.|[\w-]|[^\x00-\xa0])+)/,CLASS:/^\.((?:\\.|[\w-]|
+[^\x00-\xa0])+)/,NAME:/^\[name=['"]?((?:\\.|[\w-]|[^\x00-\xa0])+)['"]?\]/
+,TAG:RegExp("^("+"(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+".replace("w","w*")+")")
+,ATTR:RegExp("^"+ra),PSEUDO:RegExp("^"+X),CHILD:/^:(only|first|last|nth
+|nth-last)-(child|of-type)(?:\([\x20\t\r\n\f]*(even|odd|(([+-]|)(\d*)n|)
+[\x20\t\r\n\f]*(?:([+-]|)[\x20\t\r\n\f]*(\d+)|))[\x20\t\r\n\f]*\)|)/i,
+needsContext:/^[\x20\t\r\n\f]*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\(
+[\x20\t\r\n\f]*((?:-\d)?\d*)[\x20\t\r\n\f]*\)|)(?=[^-]|$)/i},aa=/[\x20\t\r\n\f
+]*[+~]/,ia=/\{\s*\[native code\]\s*\}/,ja=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/
+,ka=/^(?:input|select|textarea|button)$/i,la=/^h\d$/i,ma=/'|\\/g,pa=/\=
+[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,na=/\\([\da-fA-F]{1,6}
+[\x20\t\r\n\f]?|.)/g,oa=function(a,b){var c="0x"+b-65536;return
+ c!==c?b:0>c?String.fromCharCode(c+65536):String.fromCharCode(55296|c>>
+10,56320|1023&c)};try{R.call(W.childNodes,0)[0].nodeType}catch(sa){R=function
+(a){for(var b,c=[];b=this[a];a++)c.push(b);return c}}G=d.isXML=function(a)
+{return(a=a&&(a.ownerDocument||a).documentElement)?"HTML"!==a.nodeName:!1};F=d
+.setDocument=function(a){var c=a?a.ownerDocument||a:qa;return c!==T&&9===c
+.nodeType&&c.documentElement?(T=c,W=c.documentElement,ba=G(c),L
+.tagNameNoComments=l(function(a){return a.appendChild(c.createComment("")),!a
+.getElementsByTagName("*").length}),L.attributes=l(function(a){a.innerHTML=
+"<select></select>";a=typeof a.lastChild.getAttribute("multiple")
+;return"boolean"!==a&&"string"!==a}),L.getByClassName=l(function(a){return a
+.innerHTML="<div class='hidden e'></div><div class='hidden'></div>",a
+.getElementsByClassName&&a.getElementsByClassName("e").length?(a.lastChild
+.className="e",2===a.getElementsByClassName("e").length):!1}),L.getByName=l
+(function(a){a.id=K+0;a.innerHTML="<a name='"+K+"'></a><div
+ name='"+K+"'></div>";W.insertBefore(a,W.firstChild);var b=c.getElementsByName
+&&c.getElementsByName(K).length===
+2+c.getElementsByName(K+0).length;return L.getIdNotName=!c.getElementById(K),W
+.removeChild(a),b}),A.attrHandle=l(function(a){return a.innerHTML="<a
+ href='#'></a>",a.firstChild&&typeof a.firstChild.getAttribute!==I&&"#"===a
+.firstChild.getAttribute("href")})?{}:{href:function(a){return a.getAttribute
+("href",2)},type:function(a){return a.getAttribute("type")}},L.getIdNotName?(A
+.find.ID=function(a,b){if(typeof b.getElementById!==I&&!ba){var c=b
+.getElementById(a);return c&&c.parentNode?[c]:[]}},A.filter.ID=
+function(a){var b=a.replace(na,oa);return function(a){return a.getAttribute
+("id")===b}}):(A.find.ID=function(a,c){if(typeof c.getElementById!==I&&!ba)
+{var k=c.getElementById(a);return k?k.id===a||typeof k.getAttributeNode!==I&&k
+.getAttributeNode("id").value===a?[k]:b:[]}},A.filter.ID=function(a){var b=a
+.replace(na,oa);return function(a){return(a=typeof a.getAttributeNode!==I&&a
+.getAttributeNode("id"))&&a.value===b}}),A.find.TAG=L
+.tagNameNoComments?function(a,c){return typeof c.getElementsByTagName!==
+I?c.getElementsByTagName(a):b}:function(a,b){var c,f=[],k=0,g=b
+.getElementsByTagName(a);if("*"===a){for(;c=g[k];k++)1===c.nodeType&&f.push(c)
+;return f}return g},A.find.NAME=L.getByName&&function(a,c){return typeof c
+.getElementsByName!==I?c.getElementsByName(name):b},A.find.CLASS=L
+.getByClassName&&function(a,c){return typeof c.getElementsByClassName===I|
+|ba?b:c.getElementsByClassName(a)},ua=[],ca=[":focus"],(L.qsa=k(c
+.querySelectorAll))&&(l(function(a){a.innerHTML="<select><option
+ selected=''></option></select>";
+a.querySelectorAll("[selected]").length||ca.push("\\[[\\x20\\t\\r\\n\\f]*
+(?:checked|disabled|ismap|multiple|readonly|selected|value)");a
+.querySelectorAll(":checked").length||ca.push(":checked")}),l(function(a){a
+.innerHTML="<input type='hidden' i=''/>";a.querySelectorAll("[i^='']").length&
+&ca.push("[*^$]=[\\x20\\t\\r\\n\\f]*(?:\"\"|'')");a.querySelectorAll
+(":enabled").length||ca.push(":enabled",":disabled");a.querySelectorAll("*,:x"
+);ca.push(",.*:")})),(L.matchesSelector=k(Sa=W.matchesSelector||W
+.mozMatchesSelector||
+W.webkitMatchesSelector||W.oMatchesSelector||W.msMatchesSelector))&&l(function
+(a){L.disconnectedMatch=Sa.call(a,"div");Sa.call(a,"[s!='']:x");ua.push("!=",X
+)}),ca=RegExp(ca.join("|")),ua=RegExp(ua.join("|")),ta=k(W.contains)||W
+.compareDocumentPosition?function(a,b){var c=9===a.nodeType?a
+.documentElement:a,f=b&&b.parentNode;return a===f||!(!f||1!==f.nodeType||!(c
+.contains?c.contains(f):a.compareDocumentPosition&&16&a
+.compareDocumentPosition(f)))}:function(a,b){if(b)for(;b=b.parentNode;)if
+(b===a)return!0;
+return!1},V=W.compareDocumentPosition?function(a,b){var f;return a===b?(E=!0,0
+):(f=b.compareDocumentPosition&&a.compareDocumentPosition&&a
+.compareDocumentPosition(b))?1&f||a.parentNode&&11===a.parentNode
+.nodeType?a===c||ta(qa,a)?-1:b===c||ta(qa,b)?1:0:4&f?-1:1:a
+.compareDocumentPosition?-1:1}:function(a,b){var f,k=0;f=a.parentNode;var g=b
+.parentNode,e=[a],l=[b];if(a===b)return E=!0,0;if(a.sourceIndex&&b.sourceIndex
+)return(~b.sourceIndex||-2147483648)-(ta(qa,a)&&~a.sourceIndex||-2147483648)
+;if(!f||
+!g)return a===c?-1:b===c?1:f?-1:g?1:0;if(f===g)return q(a,b);for(f=a;f=f
+.parentNode;)e.unshift(f);for(f=b;f=f.parentNode;)l.unshift(f);for(;e[k]===l[k
+];)k++;return k?q(e[k],l[k]):e[k]===qa?-1:l[k]===qa?1:0},E=!1,[0,0].sort(V),L
+.detectDuplicates=E,T):T};d.matches=function(a,b){return d(a,null,null,b)};d
+.matchesSelector=function(a,b){if((a.ownerDocument||a)!==T&&F(a),b=b.replace
+(pa,"='$1']"),!(!L.matchesSelector||ba||ua&&ua.test(b)||ca.test(b)))try{var
+ c=Sa.call(a,b);if(c||L.disconnectedMatch||a.document&&
+11!==a.document.nodeType)return c}catch(f){}return 0<d(b,T,null,[a]).length};d
+.contains=function(a,b){return(a.ownerDocument||a)!==T&&F(a),ta(a,b)};d
+.attr=function(a,b){var c;return(a.ownerDocument||a)!==T&&F(a),ba||(b=b
+.toLowerCase()),(c=A.attrHandle[b])?c(a):ba||L.attributes?a.getAttribute(b):(
+(c=a.getAttributeNode(b))||a.getAttribute(b))&&!0===a[b]?b:c&&c.specified?c
+.value:null};d.error=function(a){throw Error("Syntax error, unrecognized
+ expression: "+a);};d.uniqueSort=function(a){var b,c=[],f=
+1,k=0;if(E=!L.detectDuplicates,a.sort(V),E){for(;b=a[f];f++)b===a[f-1]&&(k=c
+.push(f));for(;k--;)a.splice(c[k],1)}return a};D=d.getText=function(a){var b
+,c="",f=0;if(b=a.nodeType)if(1===b||9===b||11===b){if("string"==typeof a
+.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=D(a)
+}else{if(3===b||4===b)return a.nodeValue}else for(;b=a[f];f++)c+=D(b);return c
+};A=d.selectors={cacheLength:50,createPseudo:g,match:Y,find:{},relative:{">":
+{dir:"parentNode",first:!0}," ":{dir:"parentNode"},
+"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:
+{ATTR:function(a){return a[1]=a[1].replace(na,oa),a[3]=(a[4]||a[5]||"")
+.replace(na,oa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function
+(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||d.error(a[0]
+),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]
+||"odd"===a[3])):a[3]&&d.error(a[0]),a},PSEUDO:function(a){var b,c=!a[5]&&a[2]
+;return Y.CHILD.test(a[0])?null:(a[4]?a[2]=
+a[4]:c&&fa.test(c)&&(b=w(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0
+]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a)
+{return"*"===a?function(){return!0}:(a=a.replace(na,oa).toLowerCase(),function
+(b){return b.nodeName&&b.nodeName.toLowerCase()===a})},CLASS:function(a){var
+ b=Na[a+" "];return b||(b=RegExp("(^|[\\x20\\t\\r\\n\\f])"+a+"(
+[\\x20\\t\\r\\n\\f]|$)"))&&Na(a,function(a){return b.test(a.className||typeof
+ a.getAttribute!==I&&a.getAttribute("class")||"")})},ATTR:function(a,
+b,c){return function(f){f=d.attr(f,a);return null==f?"!="===b:b?(f+=""
+,"="===b?f===c:"!="===b?f!==c:"^="===b?c&&0===f.indexOf(c):"*="===b?c&&-1<f
+.indexOf(c):"$="===b?c&&f.substr(f.length-c.length)===c:"~="===b?-1<(" "+f+" "
+).indexOf(c):"|="===b?f===c||f.substr(0,c.length+1)===c+"-":!1):!0}}
+,CHILD:function(a,b,c,f,k){var g="nth"!==a.slice(0,3),e="last"!==a.slice(-4)
+,l="of-type"===b;return 1===f&&0===k?function(a){return!!a.parentNode
+}:function(b,c,d){var t,q,u,h,m;c=g!==e?"nextSibling":"previousSibling";
+var n=b.parentNode,w=l&&b.nodeName.toLowerCase();d=!d&&!l;if(n){if(g){for(;c;)
+{for(q=b;q=q[c];)if(l?q.nodeName.toLowerCase()===w:1===q.nodeType)return!1
+;m=c="only"===a&&!m&&"nextSibling"}return!0}if(m=[e?n.firstChild:n.lastChild]
+,e&&d)for(d=n[K]||(n[K]={}),t=d[a]||[],h=t[0]===H&&t[1],u=t[0]===H&&t[2],q=h&
+&n.childNodes[h];q=++h&&q&&q[c]||(u=h=0)||m.pop();){if(1===q.nodeType&&++u&
+&q===b){d[a]=[H,h,u];break}}else if(d&&(t=(b[K]||(b[K]={}))[a])&&t[0]===H)u=t
+[1];else for(;(q=++h&&q&&q[c]||(u=h=0)||m.pop())&&
+((l?q.nodeName.toLowerCase()!==w:1!==q.nodeType)||!++u||(d&&((q[K]||(q[K]={}))
+[a]=[H,u]),q!==b)););return u-=k,u===f||0===u%f&&0<=u/f}}},PSEUDO:function(a,b
+){var c,f=A.pseudos[a]||A.setFilters[a.toLowerCase()]||d.error("unsupported
+ pseudo: "+a);return f[K]?f(b):1<f.length?(c=[a,a,"",b],A.setFilters
+.hasOwnProperty(a.toLowerCase())?g(function(a,c){for(var k,g=f(a,b),e=g.length
+;e--;)k=Aa.call(a,g[e]),a[k]=!(c[k]=g[e])}):function(a){return f(a,0,c)}):f}}
+,pseudos:{not:g(function(a){var b=[],c=[],f=M(a.replace(ha,
+"$1"));return f[K]?g(function(a,b,c,k){var g;c=f(a,null,k,[]);for(k=a.length
+;k--;)(g=c[k])&&(a[k]=!(b[k]=g))}):function(a,k,g){return b[0]=a,f(b,null,g,c)
+,!c.pop()}}),has:g(function(a){return function(b){return 0<d(a,b).length}})
+,contains:g(function(a){return function(b){return-1<(b.textContent||b
+.innerText||D(b)).indexOf(a)}}),lang:g(function(a){return ga.test(a||"")||d
+.error("unsupported lang: "+a),a=a.replace(na,oa).toLowerCase(),function(b)
+{var c;do if(c=ba?b.getAttribute("xml:lang")||b.getAttribute("lang"):
+b.lang)return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b
+.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&
+&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===W}
+,focus:function(a){return a===T.activeElement&&(!T.hasFocus||T.hasFocus())&&!!
+(a.type||a.href||~a.tabIndex)},enabled:function(a){return!1===a.disabled}
+,disabled:function(a){return!0===a.disabled},checked:function(a){var b=a
+.nodeName.toLowerCase();return"input"===b&&!!a.checked||
+"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a
+.parentNode.selectedIndex,!0===a.selected},empty:function(a){for(a=a
+.firstChild;a;a=a.nextSibling)if("@"<a.nodeName||3===a.nodeType||4===a
+.nodeType)return!1;return!0},parent:function(a){return!A.pseudos.empty(a)}
+,header:function(a){return la.test(a.nodeName)},input:function(a){return ka
+.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase()
+;return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;
+return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a
+.getAttribute("type"))||b.toLowerCase()===a.type)},first:n(function(){return[0
+]}),last:n(function(a,b){return[b-1]}),eq:n(function(a,b,c){return[0>c?c+b:c]}
+),even:n(function(a,b){for(var c=0;b>c;c+=2)a.push(c);return a}),odd:n
+(function(a,b){for(var c=1;b>c;c+=2)a.push(c);return a}),lt:n(function(a,b,c)
+{for(b=0>c?c+b:c;0<=--b;)a.push(b);return a}),gt:n(function(a,b,c){for
+(c=0>c?c+b:c;b>++c;)a.push(c);return a})}};for(O in{radio:!0,
+checkbox:!0,file:!0,password:!0,image:!0})A.pseudos[O]=h(O);for(O in{submit:!0
+,reset:!0})A.pseudos[O]=m(O);M=d.compile=function(a,b){var c,f=[],k=[],g=U[a+"
+ "];if(!g){b||(b=w(a));for(c=b.length;c--;)g=y(b[c]),g[K]?f.push(g):k.push(g)
+;g=U(a,J(k,f))}return g};A.pseudos.nth=A.pseudos.eq;A.filters=N.prototype=A
+.pseudos;A.setFilters=new N;F();d.attr=c.attr;c.find=d;c.expr=d.selectors;c
+.expr[":"]=c.expr.pseudos;c.unique=d.uniqueSort;c.text=d.getText;c.isXMLDoc=d
+.isXML;c.contains=d.contains})(v);var gc=
+/Until$/,hc=/^(?:parents|prev(?:Until|All))/,Lb=/^.[^:#\[\.,]*$/,ub=c.expr
+.match.needsContext,ic={children:!0,contents:!0,next:!0,prev:!0};c.fn.extend(
+{find:function(a){var b,k,e;if("string"!=typeof a)return e=this,this.pushStack
+(c(a).filter(function(){for(b=0;e.length>b;b++)if(c.contains(e[b],this)
+)return!0}));k=[];for(b=0;this.length>b;b++)c.find(a,this[b],k);return k=this
+.pushStack(c.unique(k)),k.selector=(this.selector?this.selector+" ":"")+a,k}
+,has:function(a){var b,k=c(a,this),e=k.length;return this.filter(function()
+{for(b=
+0;e>b;b++)if(c.contains(this,k[b]))return!0})},not:function(a){return this
+.pushStack(A(this,a,!1))},filter:function(a){return this.pushStack(A(this,a,!0
+))},is:function(a){return!!a&&("string"==typeof a?ub.test(a)?0<=c(a,this
+.context).index(this[0]):0<c.filter(a,this).length:0<this.filter(a).length)}
+,closest:function(a,b){for(var k,e=0,g=this.length,l=[],d=ub.test(a)|
+|"string"!=typeof a?c(a,b||this.context):0;g>e;e++)for(k=this[e];k&&k
+.ownerDocument&&k!==b&&11!==k.nodeType;){if(d?-1<d.index(k):c.find
+.matchesSelector(k,
+a)){l.push(k);break}k=k.parentNode}return this.pushStack(1<l.length?c.unique(l
+):l)},index:function(a){return a?"string"==typeof a?c.inArray(this[0],c(a)):c
+.inArray(a.jquery?a[0]:a,this):this[0]&&this[0].parentNode?this.first()
+.prevAll().length:-1},add:function(a,b){var k="string"==typeof a?c(a,b):c
+.makeArray(a&&a.nodeType?[a]:a),k=c.merge(this.get(),k);return this.pushStack
+(c.unique(k))},addBack:function(a){return this.add(null==a?this
+.prevObject:this.prevObject.filter(a))}});c.fn.andSelf=c.fn.addBack;
+c.each({parent:function(a){return(a=a.parentNode)&&11!==a.nodeType?a:null}
+,parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,k
+){return c.dir(a,"parentNode",k)},next:function(a){return E(a,"nextSibling")}
+,prev:function(a){return E(a,"previousSibling")},nextAll:function(a){return c
+.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")}
+,nextUntil:function(a,b,k){return c.dir(a,"nextSibling",k)},prevUntil:function
+(a,b,k){return c.dir(a,"previousSibling",
+k)},siblings:function(a){return c.sibling((a.parentNode||{}).firstChild,a)}
+,children:function(a){return c.sibling(a.firstChild)},contents:function(a)
+{return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c
+.merge([],a.childNodes)}},function(a,b){c.fn[a]=function(k,e){var g=c.map(this
+,b,k);return gc.test(a)||(e=k),e&&"string"==typeof e&&(g=c.filter(e,g))
+,g=1<this.length&&!ic[a]?c.unique(g):g,1<this.length&&hc.test(a)&&(g=g.reverse
+()),this.pushStack(g)}});c.extend({filter:function(a,
+b,k){return k&&(a=":not("+a+")"),1===b.length?c.find.matchesSelector(b[0],a)?
+[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,k){var e=[];for(a=a[b];a&
+&9!==a.nodeType&&(k===p||1!==a.nodeType||!c(a).is(k));)1===a.nodeType&&e.push
+(a),a=a[b];return e},sibling:function(a,b){for(var c=[];a;a=a.nextSibling
+)1===a.nodeType&&a!==b&&c.push(a);return c}});var lb="abbr|article|aside|audio
+|bdi|canvas|data|datalist|details|figcaption|figure|footer|header|hgroup|mark
+|meter|nav|output|progress|section|summary|time|video",
+jc=/ jQuery\d+="(?:null|\d+)"/g,vb=RegExp("<(?:"+lb+")[\\s/>]","i"),db=/^\s+/
+,wb=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi
+,xb=/<([\w:]+)/,yb=/<tbody/i,kc=/<|&#?\w+;/,lc=/<(?:script|style|link)/i,Ua=/^
+(?:checkbox|radio)$/i,mc=/checked\s*(?:[^=]|=\s*.checked.)/i,zb=/^$|\/(?:java
+|ecma)script/i,Mb=/^true\/(.*)/,nc=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g
+,U={option:[1,"<select multiple='multiple'>","</select>"],legend:[1
+,"<fieldset>","</fieldset>"],area:[1,"<map>","</map>"],
+param:[1,"<object>","</object>"],thead:[1,"<table>","</table>"],tr:[2
+,"<table><tbody>","</tbody></table>"],col:[2
+,"<table><tbody></tbody><colgroup>","</colgroup></table>"],td:[3
+,"<table><tbody><tr>","</tr></tbody></table>"],_default:c.support
+.htmlSerialize?[0,"",""]:[1,"X<div>","</div>"]},oc=V(y),eb=oc.appendChild(y
+.createElement("div"));U.optgroup=U.option;U.tbody=U.tfoot=U.colgroup=U
+.caption=U.thead;U.th=U.td;c.fn.extend({text:function(a){return c.access(this
+,function(a){return a===p?c.text(this):
+this.empty().append((this[0]&&this[0].ownerDocument||y).createTextNode(a))}
+,null,a,arguments.length)},wrapAll:function(a){if(c.isFunction(a))return this
+.each(function(b){c(this).wrapAll(a.call(this,b))});if(this[0]){var b=c(a,this
+[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&b.insertBefore(this[0])
+;b.map(function(){for(var a=this;a.firstChild&&1===a.firstChild.nodeType;)a=a
+.firstChild;return a}).append(this)}return this},wrapInner:function(a){return
+ c.isFunction(a)?this.each(function(b){c(this).wrapInner(a.call(this,
+b))}):this.each(function(){var b=c(this),k=b.contents();k.length?k.wrapAll(a
+):b.append(a)})},wrap:function(a){var b=c.isFunction(a);return this.each
+(function(k){c(this).wrapAll(b?a.call(this,k):a)})},unwrap:function(){return
+ this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith
+(this.childNodes)}).end()},append:function(){return this.domManip(arguments,!0
+,function(a){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||this
+.appendChild(a)})},prepend:function(){return this.domManip(arguments,
+!0,function(a){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||this
+.insertBefore(a,this.firstChild)})},before:function(){return this.domManip
+(arguments,!1,function(a){this.parentNode&&this.parentNode.insertBefore(a,this
+)})},after:function(){return this.domManip(arguments,!1,function(a){this
+.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})}
+,remove:function(a,b){for(var k,e=0;null!=(k=this[e]);e++)(!a||0<c.filter(a,[k
+]).length)&&(b||1!==k.nodeType||c.cleanData(F(k)),k.parentNode&&
+(b&&c.contains(k.ownerDocument,k)&&R(F(k,"script")),k.parentNode.removeChild(k
+)));return this},empty:function(){for(var a,b=0;null!=(a=this[b]);b++){for
+(1===a.nodeType&&c.cleanData(F(a,!1));a.firstChild;)a.removeChild(a.firstChild
+);a.options&&c.nodeName(a,"select")&&(a.options.length=0)}return this}
+,clone:function(a,b){return a=null==a?!1:a,b=null==b?a:b,this.map(function()
+{return c.clone(this,a,b)})},html:function(a){return c.access(this,function(a)
+{var b=this[0]||{},e=0,g=this.length;if(a===p)return 1===
+b.nodeType?b.innerHTML.replace(jc,""):p;if(!("string"!=typeof a||lc.test(a)|
+|!c.support.htmlSerialize&&vb.test(a)||!c.support.leadingWhitespace&&db.test(a
+)||U[(xb.exec(a)||["",""])[1].toLowerCase()])){a=a.replace(wb,"<$1></$2>");try
+{for(;g>e;e++)b=this[e]||{},1===b.nodeType&&(c.cleanData(F(b,!1)),b
+.innerHTML=a);b=0}catch(l){}}b&&this.empty().append(a)},null,a,arguments
+.length)},replaceWith:function(a){var b=c.isFunction(a);return b|
+|"string"==typeof a||(a=c(a).not(this).detach()),this.domManip([a],
+!0,function(a){var b=this.nextSibling,f=this.parentNode;(f&&1===this.nodeType|
+|11===this.nodeType)&&(c(this).remove(),b?b.parentNode.insertBefore(a,b):f
+.appendChild(a))})},detach:function(a){return this.remove(a,!0)}
+,domManip:function(a,b,k){a=Oa.apply([],a);var e,g,l,d,q=0,h=this.length
+,m=this,n=h-1,w=a[0],r=c.isFunction(w);if(r||!(1>=h||"string"!=typeof w||c
+.support.checkClone)&&mc.test(w))return this.each(function(c){var e=m.eq(c);r&
+&(a[0]=w.call(this,c,b?e.html():p));e.domManip(a,b,k)});if(h&&
+(e=c.buildFragment(a,this[0].ownerDocument,!1,this),g=e.firstChild,1===e
+.childNodes.length&&(e=g),g)){b=b&&c.nodeName(g,"tr");g=c.map(F(e,"script"),Q)
+;for(l=g.length;h>q;q++)d=e,q!==n&&(d=c.clone(d,!0,!0),l&&c.merge(g,F(d
+,"script"))),k.call(b&&c.nodeName(this[q],"table")?ra(this[q],"tbody"):this[q]
+,d,q);if(l)for(e=g[g.length-1].ownerDocument,c.map(g,ea),q=0;l>q;q++)d=g[q],zb
+.test(d.type||"")&&!c._data(d,"globalEval")&&c.contains(e,d)&&(d.src?c.ajax(
+{url:d.src,type:"GET",dataType:"script",async:!1,
+global:!1,"throws":!0}):c.globalEval((d.text||d.textContent||d.innerHTML||"")
+.replace(nc,"")));e=g=null}return this}});c.each({appendTo:"append"
+,prependTo:"prepend",insertBefore:"before",insertAfter:"after"
+,replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(a){for(var e=0,g=[]
+,l=c(a),d=l.length-1;d>=e;e++)a=e===d?this:this.clone(!0),c(l[e])[b](a),Xa
+.apply(g,a.get());return this.pushStack(g)}});c.extend({clone:function(a,b,e)
+{var d,g,l,q,h,m=c.contains(a.ownerDocument,a);if(c.support.html5Clone||
+c.isXMLDoc(a)||!vb.test("<"+a.nodeName+">")?h=a.cloneNode(!0):(eb.innerHTML=a
+.outerHTML,eb.removeChild(h=eb.firstChild)),!(c.support.noCloneEvent&&c
+.support.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||c.isXMLDoc(a)))for
+(d=F(h),g=F(a),q=0;null!=(l=g[q]);++q)if(d[q]){var n=d[q],w=void 0,p=void 0
+,r=void 0;if(1===n.nodeType){if(w=n.nodeName.toLowerCase(),!c.support
+.noCloneEvent&&n[c.expando]){p=c._data(n);for(r in p.events)c.removeEvent(n,r
+,p.handle);n.removeAttribute(c.expando)}"script"===w&&n.text!==
+l.text?(Q(n).text=l.text,ea(n)):"object"===w?(n.parentNode&&(n.outerHTML=l
+.outerHTML),c.support.html5Clone&&l.innerHTML&&!c.trim(n.innerHTML)&&(n
+.innerHTML=l.innerHTML)):"input"===w&&Ua.test(l.type)?(n.defaultChecked=n
+.checked=l.checked,n.value!==l.value&&(n.value=l.value)):"option"===w?n
+.defaultSelected=n.selected=l.defaultSelected:("input"===w||"textarea"===w)&&
+(n.defaultValue=l.defaultValue)}}if(b)if(e)for(g=g||F(a),d=d||F(h),q=0;null!=
+(l=g[q]);q++)sa(l,d[q]);else sa(a,h);return d=F(h,"script"),
+0<d.length&&R(d,!m&&F(a,"script")),h},buildFragment:function(a,b,e,d){for(var
+ g,l,q,h,n,m,w,p=a.length,r=V(b),z=[],v=0;p>v;v++)if(l=a[v],l||0===l)if
+("object"===c.type(l))c.merge(z,l.nodeType?[l]:l);else if(kc.test(l)){h=h||r
+.appendChild(b.createElement("div"));q=(xb.exec(l)||["",""])[1].toLowerCase()
+;n=U[q]||U._default;h.innerHTML=n[1]+l.replace(wb,"<$1></$2>")+n[2];for(w=n[0]
+;w--;)h=h.lastChild;if(!c.support.leadingWhitespace&&db.test(l)&&z.push(b
+.createTextNode(db.exec(l)[0])),!c.support.tbody)for(w=
+(l="table"!==q||yb.test(l)?"<table>"!==n[1]||yb.test(l)?0:h:h.firstChild)&&l
+.childNodes.length;w--;)c.nodeName(m=l.childNodes[w],"tbody")&&!m.childNodes
+.length&&l.removeChild(m);c.merge(z,h.childNodes);for(h.textContent="";h
+.firstChild;)h.removeChild(h.firstChild);h=r.lastChild}else z.push(b
+.createTextNode(l));h&&r.removeChild(h);c.support.appendChecked||c.grep(F(z
+,"input"),Da);for(v=0;l=z[v++];)if((!d||-1===c.inArray(l,d))&&(g=c.contains(l
+.ownerDocument,l),h=F(r.appendChild(l),"script"),g&&R(h),
+e))for(w=0;l=h[w++];)zb.test(l.type||"")&&e.push(l);return r}
+,cleanData:function(a,b){for(var e,d,g,l,q=0,h=c.expando,n=c.cache,m=c.support
+.deleteExpando,w=c.event.special;null!=(g=a[q]);q++)if((b||c.acceptData(g))&&
+(d=g[h],e=d&&n[d])){if(e.events)for(l in e.events)w[l]?c.event.remove(g,l):c
+.removeEvent(g,l,e.handle);n[d]&&(delete n[d],m?delete g[h]:g
+.removeAttribute!==p?g.removeAttribute(h):g[h]=null,I.push(d))}}});var Y,ga,wa
+,fb=/alpha\([^)]*\)/i,pc=/opacity\s*=\s*([^)]*)/,qc=/^(top|right|bottom|left
+)$/,
+rc=/^(none|table(?!-c[ea]).+)/,Ab=/^margin/,Nb=RegExp("^("+Pa+")(.*)$","i")
+,Ia=RegExp("^("+Pa+")(?!px)[a-z%]+$","i"),sc=RegExp("^([+-])=("+Pa+")","i")
+,nb={BODY:"block"},tc={position:"absolute",visibility:"hidden",display:"block"
+},Bb={letterSpacing:0,fontWeight:400},fa=["Top","Right","Bottom","Left"],mb=
+["Webkit","O","Moz","ms"];c.fn.extend({css:function(a,b){return c.access(this
+,function(a,b,f){var e,d={},q=0;if(c.isArray(b)){f=ga(a);for(e=b.length;e>q
+;q++)d[b[q]]=c.css(a,b[q],!1,f);return d}return f!==
+p?c.style(a,b,f):c.css(a,b)},a,b,1<arguments.length)},show:function(){return X
+(this,!0)},hide:function(){return X(this)},toggle:function(a){var
+ b="boolean"==typeof a;return this.each(function(){(b?a:S(this))?c(this).show(
+):c(this).hide()})}});c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var
+ c=Y(a,"opacity");return""===c?"1":c}}}},cssNumber:{columnCount:!0
+,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0
+,zIndex:!0,zoom:!0},cssProps:{"float":c.support.cssFloat?"cssFloat":
+"styleFloat"},style:function(a,b,e,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a
+.style){var g,l,q,h=c.camelCase(b),n=a.style;if(b=c.cssProps[h]||(c.cssProps[h
+]=Ea(n,h)),q=c.cssHooks[b]||c.cssHooks[h],e===p)return q&&"get"in q&&(g=q.get
+(a,!1,d))!==p?g:n[b];if(l=typeof e,"string"===l&&(g=sc.exec(e))&&(e=(g[1]+1)*g
+[2]+parseFloat(c.css(a,b)),l="number"),!(null==e||"number"===l&&isNaN(e)||
+("number"!==l||c.cssNumber[h]||(e+="px"),c.support.clearCloneStyle||""!==e|
+|0!==b.indexOf("background")||(n[b]="inherit"),
+q&&"set"in q&&(e=q.set(a,e,d))===p)))try{n[b]=e}catch(m){}}},css:function(a,b
+,e,d){var g,l,q,h=c.camelCase(b);return b=c.cssProps[h]||(c.cssProps[h]=Ea(a
+.style,h)),q=c.cssHooks[b]||c.cssHooks[h],q&&"get"in q&&(g=q.get(a,!0,e))
+,g===p&&(g=Y(a,b,d)),"normal"===g&&b in Bb&&(g=Bb[b]),e?(l=parseFloat(g)
+,!0===e||c.isNumeric(l)?l||0:g):g},swap:function(a,b,c,e){var g,l={};for(g in
+ b)l[g]=a.style[g],a.style[g]=b[g];c=c.apply(a,e||[]);for(g in b)a.style[g]=l
+[g];return c}});v.getComputedStyle?(ga=function(a){return v.getComputedStyle(a
+,
+null)},Y=function(a,b,e){var d,g,l,q=(e=e||ga(a))?e.getPropertyValue(b)||e[b
+]:p,h=a.style;return e&&(""!==q||c.contains(a.ownerDocument,a)||(q=c.style(a,b
+)),Ia.test(q)&&Ab.test(b)&&(d=h.width,g=h.minWidth,l=h.maxWidth,h.minWidth=h
+.maxWidth=h.width=q,q=e.width,h.width=d,h.minWidth=g,h.maxWidth=l)),q}):y
+.documentElement.currentStyle&&(ga=function(a){return a.currentStyle}
+,Y=function(a,b,c){var e,g,l;c=(c=c||ga(a))?c[b]:p;var d=a.style;return
+ null==c&&d&&d[b]&&(c=d[b]),Ia.test(c)&&!qc.test(b)&&(e=d.left,
+g=a.runtimeStyle,l=g&&g.left,l&&(g.left=a.currentStyle.left),d
+.left="fontSize"===b?"1em":c,c=d.pixelLeft+"px",d.left=e,l&&(g.left=l))
+,""===c?"auto":c});c.each(["height","width"],function(a,b){c.cssHooks[b]=
+{get:function(a,e,g){return e?0===a.offsetWidth&&rc.test(c.css(a,"display"))?c
+.swap(a,tc,function(){return Ha(a,b,g)}):Ha(a,b,g):p},set:function(a,e,g){var
+ d=g&&ga(a);return va(a,e,g?Ga(a,b,g,c.support.boxSizing&&"border-box"===c.css
+(a,"boxSizing",!1,d),d):0)}}});c.support.opacity||(c.cssHooks.opacity=
+{get:function(a,b){return pc.test((b&&a.currentStyle?a.currentStyle.filter:a
+.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":b?"1":""},set:function(a,b)
+{var e=a.style,d=a.currentStyle,g=c.isNumeric(b)?"alpha(opacity="+100*b+")":""
+,l=d&&d.filter||e.filter||"";e.zoom=1;(1<=b||""===b)&&""===c.trim(l.replace(fb
+,""))&&e.removeAttribute&&(e.removeAttribute("filter"),""===b||d&&!d.filter)||
+(e.filter=fb.test(l)?l.replace(fb,g):l+" "+g)}});c(function(){c.support
+.reliableMarginRight||(c.cssHooks.marginRight=
+{get:function(a,b){return b?c.swap(a,{display:"inline-block"},Y,[a
+,"marginRight"]):p}});!c.support.pixelPosition&&c.fn.position&&c.each(["top"
+,"left"],function(a,b){c.cssHooks[b]={get:function(a,e){return e?(e=Y(a,b),Ia
+.test(e)?c(a).position()[b]+"px":e):p}}})});c.expr&&c.expr.filters&&(c.expr
+.filters.hidden=function(a){return 0===a.offsetWidth&&0===a.offsetHeight||!c
+.support.reliableHiddenOffsets&&"none"===(a.style&&a.style.display||c.css(a
+,"display"))},c.expr.filters.visible=function(a){return!c.expr.filters.hidden
+(a)});
+c.each({margin:"",padding:"",border:"Width"},function(a,b){c.cssHooks[a+b]=
+{expand:function(c){var e=0,g={};for(c="string"==typeof c?c.split(" "):[c];4>e
+;e++)g[a+fa[e]+b]=c[e]||c[e-2]||c[0];return g}};Ab.test(a)||(c.cssHooks[a+b]
+.set=va)});var uc=/%20/g,Ob=/\[\]$/,Cb=/\r?\n/g,vc=/^(?:submit|button|image
+|reset)$/i,wc=/^(?:input|select|textarea|keygen)/i;c.fn.extend(
+{serialize:function(){return c.param(this.serializeArray())}
+,serializeArray:function(){return this.map(function(){var a=c.prop(this
+,"elements");
+return a?c.makeArray(a):this}).filter(function(){var a=this.type;return this
+.name&&!c(this).is(":disabled")&&wc.test(this.nodeName)&&!vc.test(a)&&(this
+.checked||!Ua.test(a))}).map(function(a,b){var e=c(this).val();return
+ null==e?null:c.isArray(e)?c.map(e,function(a){return{name:b.name,value:a
+.replace(Cb,"\r\n")}}):{name:b.name,value:e.replace(Cb,"\r\n")}}).get()}});c
+.param=function(a,b){var e,d=[],g=function(a,b){b=c.isFunction(b)?b(
+):null==b?"":b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(b)};
+if(b===p&&(b=c.ajaxSettings&&c.ajaxSettings.traditional),c.isArray(a)||a
+.jquery&&!c.isPlainObject(a))c.each(a,function(){g(this.name,this.value)})
+;else for(e in a)xa(e,a[e],b,g);return d.join("&").replace(uc,"+")};var ja,da
+,gb=c.now(),hb=/\?/,xc=/#.*$/,Db=/([?&])_=[^&]*/,yc=/^(.*?):[ \t]*([^\r\n]*
+)\r?$/gm,zc=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Ac=/^
+(?:GET|HEAD)$/,Bc=/^\/\//,Eb=/^([\w.+-]+:)(?:\/\/([^\/?#:]*)(?::(\d+)|)|)/
+,Fb=c.fn.load,Gb={},Wa={},Hb="*/".concat("*");try{da=
+Na.href}catch(Fc){da=y.createElement("a"),da.href="",da=da.href}ja=Eb.exec(da
+.toLowerCase())||[];c.fn.load=function(a,b,e){if("string"!=typeof a&&Fb)return
+ Fb.apply(this,arguments);var d,g,l,q=this,h=a.indexOf(" ");return 0<=h&&(d=a
+.slice(h,a.length),a=a.slice(0,h)),c.isFunction(b)?(e=b,b=p):b&
+&"object"==typeof b&&(g="POST"),0<q.length&&c.ajax({url:a,type:g
+,dataType:"html",data:b}).done(function(a){l=arguments;q.html(d?c("<div>")
+.append(c.parseHTML(a)).find(d):a)}).complete(e&&function(a,b){q.each(e,
+l||[a.responseText,b,a])}),this};c.each("ajaxStart ajaxStop ajaxComplete
+ ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(a)
+{return this.on(b,a)}});c.each(["get","post"],function(a,b){c[b]=function(a,e
+,g,d){return c.isFunction(e)&&(d=d||g,g=e,e=p),c.ajax({url:a,type:b,dataType:d
+,data:e,success:g})}});c.extend({active:0,lastModified:{},etag:{}
+,ajaxSettings:{url:da,type:"GET",isLocal:zc.test(ja[1]),global:!0
+,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded;
+ charset=UTF-8",
+accepts:{"*":Hb,text:"text/plain",html:"text/html",xml:"application/xml,
+ text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/
+,html:/html/,json:/json/},responseFields:{xml:"responseXML"
+,text:"responseText"},converters:{"* text":v.String,"text html":!0,"text
+ json":c.parseJSON,"text xml":c.parseXML},flatOptions:{url:!0,context:!0}}
+,ajaxSetup:function(a,b){return b?P(P(a,c.ajaxSettings),b):P(c.ajaxSettings,a)
+},ajaxPrefilter:Ka(Gb),ajaxTransport:Ka(Wa),ajax:function(a,b){function e(a,
+b,f,k){var q,n,w,u,J,N=b;if(2!==O){O=2;h&&clearTimeout(h);d=p;l=k||"";C
+.readyState=0<a?4:0;if(f){var D;u=r;k=C;var G,E,M,F=u.contents,I=u.dataTypes
+,L=u.responseFields;for(G in L)G in f&&(k[L[G]]=f[G]);for(;"*"===I[0];)I.shift
+(),D===p&&(D=u.mimeType||k.getResponseHeader("Content-Type"));if(D)for(G in F
+)if(F[G]&&F[G].test(D)){I.unshift(G);break}if(I[0]in f)E=I[0];else{for(G in f)
+{if(!I[0]||u.converters[G+" "+I[0]]){E=G;break}M||(M=G)}E=E||M}u=D=E?(E!==I[0]
+&&I.unshift(E),f[E]):p}if(200<=a&&300>a||304===
+a)if(r.ifModified&&(J=C.getResponseHeader("Last-Modified"),J&&(c.lastModified
+[g]=J),J=C.getResponseHeader("etag"),J&&(c.etag[g]=J)),304===a)q=!0
+,N="notmodified";else{var H;a:{q=r;n=u;var Ca,V;J={};N=0;D=q.dataTypes.slice()
+;G=D[0];if(q.dataFilter&&(n=q.dataFilter(n,q.dataType)),D[1])for(H in q
+.converters)J[H.toLowerCase()]=q.converters[H];for(;w=D[++N];)if("*"!==w){if
+("*"!==G&&G!==w){if(H=J[G+" "+w]||J["* "+w],!H)for(Ca in J)if(V=Ca.split(" ")
+,V[1]===w&&(H=J[G+" "+V[0]]||J["* "+V[0]])){!0===H?H=J[Ca]:
+!0!==J[Ca]&&(w=V[0],D.splice(N--,0,w));break}if(!0!==H)if(H&&q["throws"])n=H(n
+);else try{n=H(n)}catch(P){H={state:"parsererror",error:H?P:"No conversion
+ from "+G+" to "+w};break a}}G=w}H={state:"success",data:n}}q=H;N=q.state;n=q
+.data;w=q.error;q=!w}else w=N,(a||!N)&&(N="error",0>a&&(a=0));C.status=a;C
+.statusText=(b||N)+"";q?B.resolveWith(z,[n,N,C]):B.rejectWith(z,[C,N,w]);C
+.statusCode(A);A=p;m&&v.trigger(q?"ajaxSuccess":"ajaxError",[C,r,q?n:w]);y
+.fireWith(z,[C,N]);m&&(v.trigger("ajaxComplete",[C,
+r]),--c.active||c.event.trigger("ajaxStop"))}}"object"==typeof a&&(b=a,a=p)
+;b=b||{};var d,g,l,q,h,n,m,w,r=c.ajaxSetup({},b),z=r.context||r,v=r.context&&
+(z.nodeType||z.jquery)?c(z):c.event,B=c.Deferred(),y=c.Callbacks("once memory"
+),A=r.statusCode||{},J={},N={},O=0,D="canceled",C={readyState:0
+,getResponseHeader:function(a){var b;if(2===O){if(!q)for(q={};b=yc.exec(l);)q
+[b[1].toLowerCase()]=b[2];b=q[a.toLowerCase()]}return null==b?null:b}
+,getAllResponseHeaders:function(){return 2===O?l:null}
+,setRequestHeader:function(a,
+b){var c=a.toLowerCase();return O||(a=N[c]=N[c]||a,J[a]=b),this}
+,overrideMimeType:function(a){return O||(r.mimeType=a),this}
+,statusCode:function(a){var b;if(a)if(2>O)for(b in a)A[b]=[A[b],a[b]];else C
+.always(a[C.status]);return this},abort:function(a){a=a||D;return d&&d.abort(a
+),e(0,a),this}};if(B.promise(C).complete=y.add,C.success=C.done,C.error=C.fail
+,r.url=((a||r.url||da)+"").replace(xc,"").replace(Bc,ja[1]+"//"),r.type=b
+.method||b.type||r.method||r.type,r.dataTypes=c.trim(r.dataType||"*")
+.toLowerCase().match(Z)||
+[""],null==r.crossDomain&&(n=Eb.exec(r.url.toLowerCase()),r.crossDomain=!(!n|
+|n[1]===ja[1]&&n[2]===ja[2]&&(n[3]||("http:"===n[1]?80:443))==(ja[3]||
+("http:"===ja[1]?80:443)))),r.data&&r.processData&&"string"!=typeof r.data&&(r
+.data=c.param(r.data,r.traditional)),La(Gb,r,b,C),2===O)return C;(m=r.global)&
+&0===c.active++&&c.event.trigger("ajaxStart");r.type=r.type.toUpperCase();r
+.hasContent=!Ac.test(r.type);g=r.url;r.hasContent||(r.data&&(g=r.url+=(hb.test
+(g)?"&":"?")+r.data,delete r.data),!1===r.cache&&
+(r.url=Db.test(g)?g.replace(Db,"$1_="+gb++):g+(hb.test(g)?"&":"?")+"_="+gb++))
+;r.ifModified&&(c.lastModified[g]&&C.setRequestHeader("If-Modified-Since",c
+.lastModified[g]),c.etag[g]&&C.setRequestHeader("If-None-Match",c.etag[g]));(r
+.data&&r.hasContent&&!1!==r.contentType||b.contentType)&&C.setRequestHeader
+("Content-Type",r.contentType);C.setRequestHeader("Accept",r.dataTypes[0]&&r
+.accepts[r.dataTypes[0]]?r.accepts[r.dataTypes[0]]+("*"!==r.dataTypes[0]?",
+ "+Hb+"; q=0.01":""):r.accepts["*"]);for(w in r.headers)C.setRequestHeader(w,
+r.headers[w]);if(r.beforeSend&&(!1===r.beforeSend.call(z,C,r)||2===O))return C
+.abort();D="abort";for(w in{success:1,error:1,complete:1})C[w](r[w]);if(d=La
+(Wa,r,b,C)){C.readyState=1;m&&v.trigger("ajaxSend",[C,r]);r.async&&0<r.timeout
+&&(h=setTimeout(function(){C.abort("timeout")},r.timeout));try{O=1,d.send(J,e)
+}catch(G){if(!(2>O))throw G;e(-1,G)}}else e(-1,"No Transport");return C}
+,getScript:function(a,b){return c.get(a,p,b,"script")},getJSON:function(a,b,e)
+{return c.get(a,b,e,"json")}});c.ajaxSetup({accepts:{script:"text/javascript,
+ application/javascript, application/ecmascript, application/x-ecmascript"},
+contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a)
+{return c.globalEval(a),a}}});c.ajaxPrefilter("script",function(a){a.cache===p
+&&(a.cache=!1);a.crossDomain&&(a.type="GET",a.global=!1)});c.ajaxTransport
+("script",function(a){if(a.crossDomain){var b,e=y.head||c("head")[0]||y
+.documentElement;return{send:function(c,g){b=y.createElement("script");b
+.async=!0;a.scriptCharset&&(b.charset=a.scriptCharset);b.src=a.url;b.onload=b
+.onreadystatechange=function(a,c){(c||!b.readyState||
+/loaded|complete/.test(b.readyState))&&(b.onload=b.onreadystatechange=null,b
+.parentNode&&b.parentNode.removeChild(b),b=null,c||g(200,"success"))};e
+.insertBefore(b,e.firstChild)},abort:function(){b&&b.onload(p,!0)}}}});var Ib=
+[],ib=/(=)\?(?=&|$)|\?\?/;c.ajaxSetup({jsonp:"callback",jsonpCallback:function
+(){var a=Ib.pop()||c.expando+"_"+gb++;return this[a]=!0,a}});c.ajaxPrefilter
+("json jsonp",function(a,b,e){var d,g,l,q=!1!==a.jsonp&&(ib.test(a.url
+)?"url":"string"==typeof a.data&&!(a.contentType||"").indexOf
+("application/x-www-form-urlencoded")&&
+ib.test(a.data)&&"data");return q||"jsonp"===a.dataTypes[0]?(d=a
+.jsonpCallback=c.isFunction(a.jsonpCallback)?a.jsonpCallback():a.jsonpCallback
+,q?a[q]=a[q].replace(ib,"$1"+d):!1!==a.jsonp&&(a.url+=(hb.test(a.url)?"&":"?"
+)+a.jsonp+"="+d),a.converters["script json"]=function(){return l||c.error(d+"
+ was not called"),l[0]},a.dataTypes[0]="json",g=v[d],v[d]=function()
+{l=arguments},e.always(function(){v[d]=g;a[d]&&(a.jsonpCallback=b
+.jsonpCallback,Ib.push(d));l&&c.isFunction(g)&&g(l[0]);l=g=p}),"script"):
+p});var pa,Ba,Cc=0,jb=v.ActiveXObject&&function(){for(var a in pa)pa[a](p,!0)}
+;c.ajaxSettings.xhr=v.ActiveXObject?function(){var a;if(!(a=!this.isLocal&&ka(
+)))a:{try{a=new v.ActiveXObject("Microsoft.XMLHTTP");break a}catch(b){}a=void
+ 0}return a}:ka;Ba=c.ajaxSettings.xhr();c.support.cors=!!Ba&
+&"withCredentials"in Ba;(Ba=c.support.ajax=!!Ba)&&c.ajaxTransport(function(a)
+{if(!a.crossDomain||c.support.cors){var b;return{send:function(e,d){var g,l
+,q=a.xhr();if(a.username?q.open(a.type,a.url,a.async,a.username,
+a.password):q.open(a.type,a.url,a.async),a.xhrFields)for(l in a.xhrFields)q[l
+]=a.xhrFields[l];a.mimeType&&q.overrideMimeType&&q.overrideMimeType(a.mimeType
+);a.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"
+]="XMLHttpRequest");try{for(l in e)q.setRequestHeader(l,e[l])}catch(h){}q.send
+(a.hasContent&&a.data||null);b=function(e,k){var l,h,n,w,m;try{if(b&&(k||4===q
+.readyState))if(b=p,g&&(q.onreadystatechange=c.noop,jb&&delete pa[g]),k)4!==q
+.readyState&&q.abort();else{w={};l=q.status;m=q.responseXML;
+n=q.getAllResponseHeaders();m&&m.documentElement&&(w.xml=m);"string"==typeof q
+.responseText&&(w.text=q.responseText);try{h=q.statusText}catch(r){h=""}l||!a
+.isLocal||a.crossDomain?1223===l&&(l=204):l=w.text?200:404}}catch(z){k||d(-1,z
+)}w&&d(l,h,w,n)};a.async?4===q.readyState?setTimeout(b):(g=++Cc,jb&&(pa||(pa={
+},c(v).unload(jb)),pa[g]=b),q.onreadystatechange=b):b()},abort:function(){b&&b
+(p,!0)}}}});var la,Ta,Qb=/^(?:toggle|show|hide)$/,Dc=RegExp("^(?:([+-])=|)
+("+Pa+")([a-z%]*)$","i"),Ec=/queueHooks$/,
+Ma=[w],za={"*":[function(a,b){var e,d,g=this.createTween(a,b),l=Dc.exec(b),q=g
+.cur(),h=+q||0,n=1,w=20;if(l){if(e=+l[2],d=l[3]||(c.cssNumber[a]?"":"px")
+,"px"!==d&&h){h=c.css(g.elem,a,!0)||e||1;do n=n||".5",h/=n,c.style(g.elem,a
+,h+d);while(n!==(n=g.cur()/q)&&1!==n&&--w)}g.unit=d;g.start=h;g.end=l[1]?h+(l
+[1]+1)*e:e}return g}]};c.Animation=c.extend(e,{tweener:function(a,b){c
+.isFunction(a)?(b=a,a=["*"]):a=a.split(" ");for(var e,d=0,g=a.length;g>d;d++
+)e=a[d],za[e]=za[e]||[],za[e].unshift(b)},prefilter:function(a,
+b){b?Ma.unshift(a):Ma.push(a)}});c.Tween=z;z.prototype={constructor:z
+,init:function(a,b,e,d,g,l){this.elem=a;this.prop=e;this.easing=g||"swing"
+;this.options=b;this.start=this.now=this.cur();this.end=d;this.unit=l||(c
+.cssNumber[e]?"":"px")},cur:function(){var a=z.propHooks[this.prop];return a&
+&a.get?a.get(this):z.propHooks._default.get(this)},run:function(a){var b,e=z
+.propHooks[this.prop];return b=this.options.duration?c.easing[this.easing](a
+,this.options.duration*a,0,1,this.options.duration):a,this.now=
+(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call
+(this.elem,this.now,this),e&&e.set?e.set(this):z.propHooks._default.set(this)
+,this}};z.prototype.init.prototype=z.prototype;z.propHooks={_default:
+{get:function(a){var b;return null==a.elem[a.prop]||a.elem.style&&null!=a.elem
+.style[a.prop]?(b=c.css(a.elem,a.prop,"auto"),b&&"auto"!==b?b:0):a.elem[a.prop
+]},set:function(a){c.fx.step[a.prop]?c.fx.step[a.prop](a):a.elem.style&&
+(null!=a.elem.style[c.cssProps[a.prop]]||c.cssHooks[a.prop])?
+c.style(a.elem,a.prop,a.now+a.unit):a.elem[a.prop]=a.now}}};z.propHooks
+.scrollTop=z.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem
+.parentNode&&(a.elem[a.prop]=a.now)}};c.each(["toggle","show","hide"],function
+(a,b){var e=c.fn[b];c.fn[b]=function(a,c,d){return null==a||"boolean"==typeof
+ a?e.apply(this,arguments):this.animate(J(b,!0),a,c,d)}});c.fn.extend(
+{fadeTo:function(a,b,c,e){return this.filter(S).css("opacity",0).show().end()
+.animate({opacity:b},a,c,e)},animate:function(a,b,d,q){var g=
+c.isEmptyObject(a),l=c.speed(b,d,q),h=function(){var b=e(this,c.extend({},a),l
+);h.finish=function(){b.stop(!0)};(g||c._data(this,"finish"))&&b.stop(!0)}
+;return h.finish=h,g||!1===l.queue?this.each(h):this.queue(l.queue,h)}
+,stop:function(a,b,e){var d=function(a){var b=a.stop;delete a.stop;b(e)}
+;return"string"!=typeof a&&(e=b,b=a,a=p),b&&!1!==a&&this.queue(a||"fx",[])
+,this.each(function(){var b=!0,f=null!=a&&a+"queueHooks",q=c.timers,h=c._data
+(this);if(f)h[f]&&h[f].stop&&d(h[f]);else for(f in h)h[f]&&
+h[f].stop&&Ec.test(f)&&d(h[f]);for(f=q.length;f--;)q[f].elem!==this||null!=a&
+&q[f].queue!==a||(q[f].anim.stop(e),b=!1,q.splice(f,1));!b&&e||c.dequeue(this
+,a)})},finish:function(a){return!1!==a&&(a=a||"fx"),this.each(function(){var b
+,e=c._data(this),d=e[a+"queue"];b=e[a+"queueHooks"];var g=c.timers,q=d?d
+.length:0;e.finish=!0;c.queue(this,a,[]);b&&b.cur&&b.cur.finish&&b.cur.finish
+.call(this);for(b=g.length;b--;)g[b].elem===this&&g[b].queue===a&&(g[b].anim
+.stop(!0),g.splice(b,1));for(b=0;q>b;b++)d[b]&&
+d[b].finish&&d[b].finish.call(this);delete e.finish})}});c.each({slideDown:J
+("show"),slideUp:J("hide"),slideToggle:J("toggle"),fadeIn:{opacity:"show"}
+,fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a
+]=function(a,c,e){return this.animate(b,a,c,e)}});c.speed=function(a,b,e){var
+ d=a&&"object"==typeof a?c.extend({},a):{complete:e||!e&&b||c.isFunction(a)&&a
+,duration:a,easing:e&&b||b&&!c.isFunction(b)&&b};return d.duration=c.fx
+.off?0:"number"==typeof d.duration?d.duration:d.duration in
+c.fx.speeds?c.fx.speeds[d.duration]:c.fx.speeds._default,(null==d.queue|
+|!0===d.queue)&&(d.queue="fx"),d.old=d.complete,d.complete=function(){c
+.isFunction(d.old)&&d.old.call(this);d.queue&&c.dequeue(this,d.queue)},d};c
+.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos
+(a*Math.PI)/2}};c.timers=[];c.fx=z.prototype.init;c.fx.tick=function(){var a
+,b=c.timers,e=0;for(la=c.now();b.length>e;e++)a=b[e],a()||b[e]!==a||b.splice
+(e--,1);b.length||c.fx.stop();la=p};c.fx.timer=function(a){a()&&
+c.timers.push(a)&&c.fx.start()};c.fx.interval=13;c.fx.start=function(){Ta||
+(Ta=setInterval(c.fx.tick,c.fx.interval))};c.fx.stop=function(){clearInterval
+(Ta);Ta=null};c.fx.speeds={slow:600,fast:200,_default:400};c.fx.step={};c.expr
+&&c.expr.filters&&(c.expr.filters.animated=function(a){return c.grep(c.timers
+,function(b){return a===b.elem}).length});c.fn.offset=function(a){if(arguments
+.length)return a===p?this:this.each(function(b){c.offset.setOffset(this,a,b)})
+;var b,e,d={top:0,left:0},g=this[0],q=
+g&&g.ownerDocument;if(q)return b=q.documentElement,c.contains(b,g)?(g
+.getBoundingClientRect!==p&&(d=g.getBoundingClientRect()),e=N(q),{top:d.top+(e
+.pageYOffset||b.scrollTop)-(b.clientTop||0),left:d.left+(e.pageXOffset||b
+.scrollLeft)-(b.clientLeft||0)}):d};c.offset={setOffset:function(a,b,e){var
+ d=c.css(a,"position");"static"===d&&(a.style.position="relative");var g,q,h=c
+(a),n=h.offset(),w=c.css(a,"top"),m=c.css(a,"left"),d=("absolute"===d|
+|"fixed"===d)&&-1<c.inArray("auto",[w,m]),r={},p={};d?(p=h.position(),
+g=p.top,q=p.left):(g=parseFloat(w)||0,q=parseFloat(m)||0);c.isFunction(b)&&
+(b=b.call(a,e,n));null!=b.top&&(r.top=b.top-n.top+g);null!=b.left&&(r.left=b
+.left-n.left+q);"using"in b?b.using.call(a,r):h.css(r)}};c.fn.extend(
+{position:function(){if(this[0]){var a,b,e={top:0,left:0},d=this[0]
+;return"fixed"===c.css(d,"position")?b=d.getBoundingClientRect():(a=this
+.offsetParent(),b=this.offset(),c.nodeName(a[0],"html")||(e=a.offset()),e
+.top+=c.css(a[0],"borderTopWidth",!0),e.left+=c.css(a[0],"borderLeftWidth",
+!0)),{top:b.top-e.top-c.css(d,"marginTop",!0),left:b.left-e.left-c.css(d
+,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){for
+(var a=this.offsetParent||y.documentElement;a&&!c.nodeName(a,"html")&
+&"static"===c.css(a,"position");)a=a.offsetParent;return a||y.documentElement}
+)}});c.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b)
+{var e=/Y/.test(b);c.fn[a]=function(d){return c.access(this,function(a,d,q)
+{var h=N(a);return q===p?h?b in h?h[b]:h.document.documentElement[d]:
+a[d]:(h?h.scrollTo(e?c(h).scrollLeft():q,e?q:c(h).scrollTop()):a[d]=q,p)},a,d
+,arguments.length,null)}});c.each({Height:"height",Width:"width"},function(a,b
+){c.each({padding:"inner"+a,content:b,"":"outer"+a},function(e,d){c.fn[d
+]=function(g,d){var q=arguments.length&&(e||"boolean"!=typeof g),h=e||(!0===g|
+|!0===d?"margin":"border");return c.access(this,function(b,e,f){var g;return c
+.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(g=b
+.documentElement,Math.max(b.body["scroll"+a],g["scroll"+
+a],b.body["offset"+a],g["offset"+a],g["client"+a])):f===p?c.css(b,e,h):c.style
+(b,e,f,h)},b,q?g:p,q,null)}})});v.jQuery=v.$=c;"function"==typeof define&
+&define.amd&&define.amd.jQuery&&define("jquery",[],function(){return c})})
+(window);function updateUI(v){document.body.style.opacity=0;(v="value"in v&&v
+.value)?(document.getElementById("proxy_on").style.display="block",document
+.getElementById("proxy_off").style.display="none",chrome.browserAction.setIcon
+({path:{19:"./images/proxy-enabled19.webp",38:"./images/proxy-enabled38.webp"}
+}),chrome.preferencesPrivate.dataReductionUpdateDailyLengths.onChange
+.addListener(onSavingsDataChanged),chrome.preferencesPrivate
+.dataReductionUpdateDailyLengths.set({value:!0})):(document.getElementById
+("proxy_off").style.display=
+"block",document.getElementById("proxy_on").style.display="none",chrome
+.browserAction.setIcon({path:{19:"./images/proxy-disabled19.png",38:"
+./images/proxy-disabled38.png"}}),chrome.preferencesPrivate
+.dataReductionUpdateDailyLengths.onChange.removeListener(onSavingsDataChanged)
+);$("body").fadeTo(400,1)}
+function onSavingsDataChanged(v){var p=null,m=null;"value"in v&&!v.value&&
+(chrome.dataReductionProxy.dataReductionDailyContentLength.get({},function(d)
+{"value"in d&&(p=d.value);drawDataSavingsChart(p,m)}),chrome
+.dataReductionProxy.dataReductionDailyReceivedLength.get({},function(d)
+{"value"in d&&(m=d.value);drawDataSavingsChart(p,m)}))}var
+ isGraphAnimationInProgress=!1,chart=null;
+function drawDataSavingsChart(v,p){if(v&&p&&!isGraphAnimationInProgress)
+{isGraphAnimationInProgress=!0;var m=Array(30),d=v.length-30;v.splice(0,d);p
+.splice(0,d);for(var d=Array(30),n=Array(30),h=0,r=0,B=0;30>B;B++){m[B]="";var
+ D=v[B]?parseInt(v[B],10):0,M=p[B]?parseInt(p[B],10):0;if(0>D||0>M)M=D=0;d[B
+]=h+D;n[B]=r+M;h=d[B];r=n[B]}r=d[29];h=n[29];B=0==r?0:100*(r-h)/r;0>B&&(B=0
+,n=d,h=r);B=B.toFixed(1)+"";document.getElementById("data_savings_percent")
+.innerText=chrome.i18n.getMessage("dataSavingsPercentFormat",
+B);B=chrome.i18n.getMessage("originalSizeFormat",""+r);D=chrome.i18n
+.getMessage("compressedSizeFormat",""+h);1073741824<h?(r=(r/1073741824)
+.toFixed(1)+"",h=(h/1073741824).toFixed(1)+"",B=chrome.i18n.getMessage
+("originalSizeFormatGb",r),D=chrome.i18n.getMessage("compressedSizeFormatGb",h
+)):1048576<h?(r=(r/1048576).toFixed(1)+"",h=(h/1048576).toFixed(1)+"",B=chrome
+.i18n.getMessage("originalSizeFormatMb",r),D=chrome.i18n.getMessage
+("compressedSizeFormatMb",h)):1024<h&&(r=(r/1024).toFixed(1)+"",h=(h/
+1024).toFixed(1)+"",B=chrome.i18n.getMessage("originalSizeFormatKb",r)
+,D=chrome.i18n.getMessage("compressedSizeFormatKb",h));document.getElementById
+("original_data_size").innerHTML=B;document.getElementById
+("compressed_data_size").innerHTML=D;m={labels:m,datasets:[{fillColor:"rgba
+(217, 217, 217, 1)",strokeColor:"rgba(217 , 217, 217, 1)",data:d},
+{fillColor:"rgba(3, 169, 244, 1)",strokeColor:"rgba(0, 0, 0, 0)",data:n}]};d=
+{bezierCurveTension:.1,animationSteps:10,animationEasing:"easeInOutSine"
+,datasetStrokeWidth:1,
+pointDot:!1,scaleShowGridLines:!1,showScale:!1,scaleBeginAtZero:!0
+,showTooltips:!1,onAnimationComplete:function(){isGraphAnimationInProgress=!1}
+};null==chart&&(n=document.getElementById("data_savings_graph").getContext
+("2d"),chart=new Chart(n));chart.Line(m,d)}}function onEnableProxyClicked()
+{chrome.dataReductionProxy.spdyProxyEnabled.set({value:!0})}function
+ onDisableProxyClicked(){chrome.dataReductionProxy.spdyProxyEnabled.set(
+{value:!1})}
+document.addEventListener("DOMContentLoaded",function(){createUI()
+;"undefined"===typeof chrome.dataReductionProxy||"undefined"===typeof chrome
+.preferencesPrivate?document.getElementById("chrome_incompatible").style
+.display="block":chrome.windows.getCurrent({},function(v){v.incognito?document
+.getElementById("incognito").style.display="block":(document.getElementById
+("main").style.display="block",chrome.dataReductionProxy.spdyProxyEnabled.get(
+{},updateUI),chrome.dataReductionProxy.spdyProxyEnabled.onChange.addListener
+(updateUI))});
+/mac/i.test(navigator.platform)&&setTimeout(function(){document.body.style
+.marginBottom="9px"},500)});
+function createUI(){document.getElementById("ext_name").innerText=chrome.i18n
+.getMessage("extNameBeta");document.getElementById
+("chrome_incompatible_message").innerText=chrome.i18n.getMessage
+("versionNotCompatible");document.getElementById("incognito_message")
+.innerText=chrome.i18n.getMessage("incognitoMessage");document.getElementById
+("info1").innerText=chrome.i18n.getMessage("info1");document.getElementById
+("info2").innerText=chrome.i18n.getMessage("info2");document.getElementById
+("learn_more").innerText=
+chrome.i18n.getMessage("learnMoreLinkText");document.getElementById
+("help_feedback").innerText=chrome.i18n.getMessage("helpAndFeedback");var
+ v=document.getElementById("enable_proxy");v.innerText=chrome.i18n.getMessage
+("enableDataSaverLabel");v.onclick=onEnableProxyClicked;v=document
+.getElementById("disable_proxy");v.innerText=chrome.i18n.getMessage
+("disableDataSaverLabel");v.onclick=onDisableProxyClicked;var v=navigator
+.language,p=new Date,m=new Date(p.getTime()-2592E6),d={day:"numeric"
+,month:"long"};
+document.getElementById("graph_start_date").innerText=m.toLocaleDateString(v,d
+);document.getElementById("graph_end_date").innerText=p.toLocaleDateString(v,d
+)};/*
+
+ Copyright (c) 2013-2014 Nick Downie
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ SOFTWARE.
+
+ Chart.js
+ http://chartjs.org/
+ Version: 1.0.1-beta.4
+
+ Copyright 2014 Nick Downie
+ Released under the MIT license
+ https://github.com/nnnick/Chart.js/blob/master/LICENSE.md
+*/
+(function(){var v=this,p=v.Chart,m=function(b){this.canvas=b.canvas;this.ctx=b
+;this.width=b.canvas.width;this.height=b.canvas.height;return this
+.aspectRatio=this.width/this.height,d.retinaScale(this),this};m.defaults=
+{global:{animation:!0,animationSteps:60,animationEasing:"easeOutQuart"
+,showScale:!0,scaleOverride:!1,scaleSteps:null,scaleStepWidth:null
+,scaleStartValue:null,scaleLineColor:"rgba(0,0,0,.1)",scaleLineWidth:1
+,scaleShowLabels:!0,scaleLabel:"<%=value%>",scaleIntegersOnly:!0
+,scaleBeginAtZero:!1,
+scaleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"
+,scaleFontSize:12,scaleFontStyle:"normal",scaleFontColor:"#666",responsive:!1
+,maintainAspectRatio:!0,showTooltips:!0,tooltipEvents:["mousemove"
+,"touchstart","touchmove","mouseout"],tooltipFillColor:"rgba(0,0,0,0.8)"
+,tooltipFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"
+,tooltipFontSize:14,tooltipFontStyle:"normal",tooltipFontColor:"#fff"
+,tooltipTitleFontFamily:"'Helvetica Neue', 'Helvetica', 'Arial', sans-serif"
+,tooltipTitleFontSize:14,
+tooltipTitleFontStyle:"bold",tooltipTitleFontColor:"#fff",tooltipYPadding:6
+,tooltipXPadding:6,tooltipCaretSize:8,tooltipCornerRadius:6,tooltipXOffset:10
+,tooltipTemplate:"<%if (label){%><%=label%>: <%}%><%= value %>"
+,multiTooltipTemplate:"<%= value %>",multiTooltipKeyBackground:"#fff"
+,onAnimationProgress:function(){},onAnimationComplete:function(){}}};m.types={
+};var d=m.helpers={},n=d.each=function(b,e,d){var h=Array.prototype.slice.call
+(arguments,3);if(b)if(b.length===+b.length){var n;for(n=0;n<b.length;n++)e
+.apply(d,
+[b[n],n].concat(h))}else for(n in b)e.apply(d,[b[n],n].concat(h))},h=d
+.clone=function(b){var e={};return n(b,function(d,h){b.hasOwnProperty(h)&&(e[h
+]=d)}),e},r=d.extend=function(b){return n(Array.prototype.slice.call(arguments
+,1),function(e){n(e,function(d,h){e.hasOwnProperty(h)&&(b[h]=d)})}),b},B=d
+.merge=function(){var b=Array.prototype.slice.call(arguments,0);return b
+.unshift({}),r.apply(null,b)},D=d.indexOf=function(b,e){if(Array.prototype
+.indexOf)return b.indexOf(e);for(var d=0;d<b.length;d++)if(b[d]===
+e)return d;return-1},M=(d.where=function(b,e){var q=[];return d.each(b
+,function(b){e(b)&&q.push(b)}),q},d.findNextWhere=function(b,e,d){d||(d=-1)
+;for(d+=1;d<b.length;d++){var h=b[d];if(e(h))return h}},d
+.findPreviousWhere=function(b,e,d){d||(d=b.length);for(--d;0<=d;d--){var h=b[d
+];if(e(h))return h}},d.inherits=function(b){var e=this,d=b&&b.hasOwnProperty
+("constructor")?b.constructor:function(){return e.apply(this,arguments)}
+,h=function(){this.constructor=d};return h.prototype=e.prototype,d.prototype=
+new h,d.extend=M,b&&r(d.prototype,b),d.__super__=e.prototype,d}),E=d
+.noop=function(){},A=d.uid=function(){var b=0;return function()
+{return"chart-"+b++}}(),V=d.warn=function(b){window.console&
+&"function"==typeof window.console.warn&&console.warn(b)},ra=d
+.amd="function"==typeof v.define&&v.define.amd,Q=d.isNumber=function(b)
+{return!isNaN(parseFloat(b))&&isFinite(b)},ea=d.max=function(b){return Math
+.max.apply(Math,b)},R=d.min=function(b){return Math.min.apply(Math,b)},sa=(d
+.cap=function(b,e,d){if(Q(e)){if(b>
+e)return e}else if(Q(d)&&d>b)return d;return b},d.getDecimalPlaces=function(b)
+{return 0!==b%1&&Q(b)?b.toString().split(".")[1].length:0}),F=d
+.radians=function(b){return Math.PI/180*b},Da=(d.getAngleFromPoint=function(b
+,e){var d=e.x-b.x,h=e.y-b.y,n=Math.sqrt(d*d+h*h),m=2*Math.PI+Math.atan2(h,d)
+;return 0>d&&0>h&&(m+=2*Math.PI),{angle:m,distance:n}},d.aliasPixel=function(b
+){return 0===b%2?0:.5}),Ea=(d.splineCurve=function(b,e,d,h){var n=Math.sqrt
+(Math.pow(e.x-b.x,2)+Math.pow(e.y-b.y,2)),m=Math.sqrt(Math.pow(d.x-
+e.x,2)+Math.pow(d.y-e.y,2)),r=h*n/(n+m);h=h*m/(n+m);return{inner:{x:e.x-r*(d
+.x-b.x),y:e.y-r*(d.y-b.y)},outer:{x:e.x+h*(d.x-b.x),y:e.y+h*(d.y-b.y)}}},d
+.calculateOrderOfMagnitude=function(b){return Math.floor(Math.log(b)/Math.LN10
+)}),S=(d.calculateScaleRange=function(b,e,d,h,n){e=Math.floor(e/(1.5*d))
+;d=2>=e;var m=ea(b),r=R(b);m===r&&(m+=.5,.5<=r&&!h?r-=.5:m+=.5);b=Math.abs(m-r
+);b=Ea(b);m=Math.ceil(m/(1*Math.pow(10,b)))*Math.pow(10,b);h=h?0:Math.floor(r/
+(1*Math.pow(10,b)))*Math.pow(10,b);for(var m=
+m-h,r=Math.pow(10,b),p=Math.round(m/r);(p>e||e>2*p)&&!d;)if(p>e)r*=2,p=Math
+.round(m/r),0!==p%1&&(d=!0);else{if(n&&0<=b&&0!==r/2%1)break;r/=2;p=Math.round
+(m/r)}return d&&(p=2,r=m/p),{steps:p,stepValue:r,min:h,max:h+p*r}},d
+.template=function(b,e){if(b instanceof Function)return b(e);var d={},h,n=b
+;h=e;d=/\W/.test(n)?new Function("obj","var p=[],print=function(){p.push.apply
+(p,arguments);};with(obj){p.push('"+n.replace(/[\r\t\n]/g," ").split("<%")
+.join("\t").replace(/((^|%>)[^\t]*)'/g,"$1\r").replace(/\t=(.*?)%>/g,
+"',$1,'").split("\t").join("');").split("%>").join("p.push('").split("\r")
+.join("\\'")+"');}return p.join('');"):d[n]=d[n];return h=h?d(h):d}),X=(d
+.generateLabels=function(b,e,d,h){var m=Array(e);return labelTemplateString&&n
+(m,function(e,n){m[n]=S(b,{value:d+h*(n+1)})}),m},d.easingEffects=
+{linear:function(b){return b},easeInQuad:function(b){return b*b}
+,easeOutQuad:function(b){return-1*b*(b-2)},easeInOutQuad:function(b){return 1>
+(b/=.5)?.5*b*b:-.5*(--b*(b-2)-1)},easeInCubic:function(b){return b*b*
+b},easeOutCubic:function(b){return 1*((b=b/1-1)*b*b+1)}
+,easeInOutCubic:function(b){return 1>(b/=.5)?.5*b*b*b:.5*((b-=2)*b*b+2)}
+,easeInQuart:function(b){return b*b*b*b},easeOutQuart:function(b){return-1*(
+(b=b/1-1)*b*b*b-1)},easeInOutQuart:function(b){return 1>(b/=.5)?.5*b*b*b*b:-
+.5*((b-=2)*b*b*b-2)},easeInQuint:function(b){return 1*(b/=1)*b*b*b*b}
+,easeOutQuint:function(b){return 1*((b=b/1-1)*b*b*b*b+1)}
+,easeInOutQuint:function(b){return 1>(b/=.5)?.5*b*b*b*b*b:.5*((b-=2)*b*b*b*b+2
+)},easeInSine:function(b){return-1*
+Math.cos(b/1*(Math.PI/2))+1},easeOutSine:function(b){return 1*Math.sin(b/1*
+(Math.PI/2))},easeInOutSine:function(b){return-.5*(Math.cos(Math.PI*b/1)-1)}
+,easeInExpo:function(b){return 0===b?1:1*Math.pow(2,10*(b/1-1))}
+,easeOutExpo:function(b){return 1===b?1:1*(-Math.pow(2,-10*b/1)+1)}
+,easeInOutExpo:function(b){return 0===b?0:1===b?1:1>(b/=.5)?.5*Math.pow(2,10*
+(b-1)):.5*(-Math.pow(2,-10*--b)+2)},easeInCirc:function(b){return 1<=b?b:-1*
+(Math.sqrt(1-(b/=1)*b)-1)},easeOutCirc:function(b){return 1*Math.sqrt(1-
+(b=b/1-1)*b)},easeInOutCirc:function(b){return 1>(b/=.5)?-.5*(Math.sqrt(1-b*b
+)-1):.5*(Math.sqrt(1-(b-=2)*b)+1)},easeInElastic:function(b){var e=1.70158,d=0
+,h=1;return 0===b?0:1==(b/=1)?1:(d||(d=.3),h<Math.abs(1)?(h=1,e=d/4):e=d/
+(2*Math.PI)*Math.asin(1/h),-(h*Math.pow(2,10*--b)*Math.sin(2*(1*b-e)*Math.PI/d
+)))},easeOutElastic:function(b){var e=1.70158,d=0,h=1;return 0===b?0:1==(b/=1
+)?1:(d||(d=.3),h<Math.abs(1)?(h=1,e=d/4):e=d/(2*Math.PI)*Math.asin(1/h),h*Math
+.pow(2,-10*b)*Math.sin(2*(1*b-e)*Math.PI/
+d)+1)},easeInOutElastic:function(b){var e=1.70158,d=0,h=1;return 0===b?0:2==
+(b/=.5)?1:(d||(d=.3*1.5),h<Math.abs(1)?(h=1,e=d/4):e=d/(2*Math.PI)*Math.asin
+(1/h),1>b?-.5*h*Math.pow(2,10*--b)*Math.sin(2*(1*b-e)*Math.PI/d):h*Math.pow(2
+,-10*--b)*Math.sin(2*(1*b-e)*Math.PI/d)*.5+1)},easeInBack:function(b){return
+ 1*(b/=1)*b*(2.70158*b-1.70158)},easeOutBack:function(b){return 1*((b=b/1-1
+)*b*(2.70158*b+1.70158)+1)},easeInOutBack:function(b){var e=1.70158;return 1>
+(b/=.5)?.5*b*b*(((e*=1.525)+1)*b-e):.5*((b-=
+2)*b*(((e*=1.525)+1)*b+e)+2)},easeInBounce:function(b){return 1-X
+.easeOutBounce(1-b)},easeOutBounce:function(b){return(b/=1)<1/2.75?7
+.5625*b*b:2/2.75>b?1*(7.5625*(b-=1.5/2.75)*b+.75):2.5/2.75>b?1*(7.5625*(b-=2
+.25/2.75)*b+.9375):1*(7.5625*(b-=2.625/2.75)*b+.984375)}
+,easeInOutBounce:function(b){return.5>b?.5*X.easeInBounce(2*b):.5*X
+.easeOutBounce(2*b-1)+.5}}),va=d.requestAnimFrame=function(){return window
+.requestAnimationFrame||window.webkitRequestAnimationFrame||window
+.mozRequestAnimationFrame||window.oRequestAnimationFrame||
+window.msRequestAnimationFrame||function(b){return window.setTimeout(b,1E3/60)
+}}(),Ga=(d.cancelAnimFrame=function(){return window.cancelAnimationFrame|
+|window.webkitCancelAnimationFrame||window.mozCancelAnimationFrame||window
+.oCancelAnimationFrame||window.msCancelAnimationFrame||function(b){return
+ window.clearTimeout(b,1E3/60)}}(),d.animationLoop=function(b,e,d,h,n,m){var
+ r=0,p=X[d]||X.linear,v=function(){r++;var d=r/e,q=p(d);b.call(m,q,d,r);h.call
+(m,q,d);e>r?m.animationFrame=va(v):n.apply(m)};va(v)},
+d.getRelativePosition=function(b){var e,d,h=b.originalEvent||b;b=b
+.currentTarget||b.srcElement;b=b.getBoundingClientRect();return h.touches?(e=h
+.touches[0].clientX-b.left,d=h.touches[0].clientY-b.top):(e=h.clientX-b.left
+,d=h.clientY-b.top),{x:e,y:d}},d.addEvent=function(b,e,d){b.addEventListener?b
+.addEventListener(e,d):b.attachEvent?b.attachEvent("on"+e,d):b["on"+e]=d})
+,Ha=d.removeEvent=function(b,e,d){b.removeEventListener?b.removeEventListener
+(e,d,!1):b.detachEvent?b.detachEvent("on"+e,d):b["on"+
+e]=E},Fa=(d.bindEvents=function(b,e,d){b.events||(b.events={});n(e,function(e)
+{b.events[e]=function(){d.apply(b,arguments)};Ga(b.chart.canvas,e,b.events[e])
+})},d.unbindEvents=function(b,e){n(e,function(e,d){Ha(b.chart.canvas,d,e)})})
+,Ja=d.getMaximumWidth=function(b){b=b.parentNode;return b.clientWidth},xa=d
+.getMaximumHeight=function(b){b=b.parentNode;return b.clientHeight},Ka=(d
+.getMaximumSize=d.getMaximumWidth,d.retinaScale=function(b){var e=b.ctx,d=b
+.canvas.width;b=b.canvas.height;window.devicePixelRatio&&
+(e.canvas.style.width=d+"px",e.canvas.style.height=b+"px",e.canvas
+.height=b*window.devicePixelRatio,e.canvas.width=d*window.devicePixelRatio,e
+.scale(window.devicePixelRatio,window.devicePixelRatio))}),La=d.clear=function
+(b){b.ctx.clearRect(0,0,b.width,b.height)},P=d.fontString=function(b,e,d)
+{return e+" "+b+"px "+d},ka=d.longestText=function(b,e,d){b.font=e;var h=0
+;return n(d,function(e){e=b.measureText(e).width;h=e>h?e:h}),h},ya=d
+.drawRoundedRectangle=function(b,e,d,h,n,m){b.beginPath();b.moveTo(e+
+m,d);b.lineTo(e+h-m,d);b.quadraticCurveTo(e+h,d,e+h,d+m);b.lineTo(e+h,d+n-m);b
+.quadraticCurveTo(e+h,d+n,e+h-m,d+n);b.lineTo(e+m,d+n);b.quadraticCurveTo(e
+,d+n,e,d+n-m);b.lineTo(e,d+m);b.quadraticCurveTo(e,d,e+m,d);b.closePath()};m
+.instances={};m.Type=function(b,e,d){this.options=e;this.chart=d;this.id=A();m
+.instances[this.id]=this;e.responsive&&this.resize();this.initialize.call(this
+,b)};r(m.Type.prototype,{initialize:function(){return this},clear:function()
+{return La(this.chart),this},stop:function(){return d.cancelAnimFrame.call(v,
+this.animationFrame),this},resize:function(b){this.stop();var e=this.chart
+.canvas,d=Ja(this.chart.canvas),h=this.options.maintainAspectRatio?d/this
+.chart.aspectRatio:xa(this.chart.canvas);return e.width=this.chart.width=d,e
+.height=this.chart.height=h,Ka(this.chart),"function"==typeof b&&b.apply(this
+,Array.prototype.slice.call(arguments,1)),this},reflow:E,render:function(b)
+{return b&&this.reflow(),this.options.animation&&!b?d.animationLoop(this.draw
+,this.options.animationSteps,this.options.animationEasing,
+this.options.onAnimationProgress,this.options.onAnimationComplete,this):(this
+.draw(),this.options.onAnimationComplete.call(this)),this}
+,generateLegend:function(){return S(this.options.legendTemplate,this)}
+,destroy:function(){this.clear();Fa(this,this.events);delete m.instances[this
+.id]},showTooltip:function(b,e){"undefined"==typeof this.activeElements&&(this
+.activeElements=[]);var h=function(b){var e=!1;return b.length!==this
+.activeElements.length?e=!0:(n(b,function(b,d){b!==this.activeElements[d]&&
+(e=!0)},this),e)}.call(this,b);if(h||e){if(this.activeElements=b,this.draw()
+,0<b.length)if(this.datasets&&1<this.datasets.length){for(var r,p,h=this
+.datasets.length-1;0<=h&&(r=this.datasets[h].points||this.datasets[h].bars|
+|this.datasets[h].segments,p=D(r,b[0]),-1===p);h--);var v=[],B=[];r=function()
+{var b,e,h,n,q,m=[],r=[],w=[];return d.each(this.datasets,function(e){b=e
+.points||e.bars||e.segments;b[p]&&b[p].hasValue()&&m.push(b[p])}),d.each(m
+,function(b){r.push(b.x);w.push(b.y);v.push(d.template(this.options
+.multiTooltipTemplate,
+b));B.push({fill:b._saved.fillColor||b.fillColor,stroke:b._saved.strokeColor|
+|b.strokeColor})},this),q=R(w),h=ea(w),n=R(r),e=ea(r),{x:n>this.chart
+.width/2?n:e,y:(q+h)/2}}.call(this,p);(new m.MultiTooltip({x:r.x,y:r.y
+,xPadding:this.options.tooltipXPadding,yPadding:this.options.tooltipYPadding
+,xOffset:this.options.tooltipXOffset,fillColor:this.options.tooltipFillColor
+,textColor:this.options.tooltipFontColor,fontFamily:this.options
+.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this
+.options.tooltipFontSize,
+titleTextColor:this.options.tooltipTitleFontColor,titleFontFamily:this.options
+.tooltipTitleFontFamily,titleFontStyle:this.options.tooltipTitleFontStyle
+,titleFontSize:this.options.tooltipTitleFontSize,cornerRadius:this.options
+.tooltipCornerRadius,labels:v,legendColors:B,legendColorBackground:this
+.options.multiTooltipKeyBackground,title:b[0].label,chart:this.chart,ctx:this
+.chart.ctx})).draw()}else n(b,function(b){var e=b.tooltipPosition();(new m
+.Tooltip({x:Math.round(e.x),y:Math.round(e.y),xPadding:this.options
+.tooltipXPadding,
+yPadding:this.options.tooltipYPadding,fillColor:this.options.tooltipFillColor
+,textColor:this.options.tooltipFontColor,fontFamily:this.options
+.tooltipFontFamily,fontStyle:this.options.tooltipFontStyle,fontSize:this
+.options.tooltipFontSize,caretHeight:this.options.tooltipCaretSize
+,cornerRadius:this.options.tooltipCornerRadius,text:S(this.options
+.tooltipTemplate,b),chart:this.chart})).draw()},this);return this}}
+,toBase64Image:function(){return this.chart.canvas.toDataURL.apply(this.chart
+.canvas,arguments)}});
+m.Type.extend=function(b){var e=this,d=function(){return e.apply(this
+,arguments)};if(d.prototype=h(e.prototype),r(d.prototype,b),d.extend=m.Type
+.extend,b.name||e.prototype.name){var n=b.name||e.prototype.name,p=m.defaults
+[e.prototype.name]?h(m.defaults[e.prototype.name]):{};m.defaults[n]=r(p,b
+.defaults);m.types[n]=d;m.prototype[n]=function(b,e){var h=B(m.defaults.global
+,m.defaults[n],e||{});return new d(b,h,this)}}else V("Name not provided for
+ this chart, so it hasn't been registered");return e};
+m.Element=function(b){r(this,b);this.initialize.apply(this,arguments);this
+.save()};r(m.Element.prototype,{initialize:function(){},restore:function(b)
+{return b?n(b,function(b){this[b]=this._saved[b]},this):r(this,this._saved)
+,this},save:function(){return this._saved=h(this),delete this._saved._saved
+,this},update:function(b){return n(b,function(b,d){this._saved[d]=this[d];this
+[d]=b},this),this},transition:function(b,e){return n(b,function(b,d){this[d]=
+(b-this._saved[d])*e+this._saved[d]},this),this},
+tooltipPosition:function(){return{x:this.x,y:this.y}},hasValue:function()
+{return Q(this.value)}});m.Element.extend=M;m.Point=m.Element.extend(
+{display:!0,inRange:function(b,e){var d=this.hitDetectionRadius+this.radius
+;return Math.pow(b-this.x,2)+Math.pow(e-this.y,2)<Math.pow(d,2)},draw:function
+(){if(this.display){var b=this.ctx;b.beginPath();b.arc(this.x,this.y,this
+.radius,0,2*Math.PI);b.closePath();b.strokeStyle=this.strokeColor;b
+.lineWidth=this.strokeWidth;b.fillStyle=this.fillColor;b.fill();b.stroke()}}})
+;
+m.Arc=m.Element.extend({inRange:function(b,e){var h=d.getAngleFromPoint(this,
+{x:b,y:e}),n=h.angle>=this.startAngle&&h.angle<=this.endAngle,h=h
+.distance>=this.innerRadius&&h.distance<=this.outerRadius;return n&&h}
+,tooltipPosition:function(){var b=this.startAngle+(this.endAngle-this
+.startAngle)/2,e=(this.outerRadius-this.innerRadius)/2+this.innerRadius;return
+{x:this.x+Math.cos(b)*e,y:this.y+Math.sin(b)*e}},draw:function(){var b=this
+.ctx;b.beginPath();b.arc(this.x,this.y,this.outerRadius,this.startAngle,
+this.endAngle);b.arc(this.x,this.y,this.innerRadius,this.endAngle,this
+.startAngle,!0);b.closePath();b.strokeStyle=this.strokeColor;b.lineWidth=this
+.strokeWidth;b.fillStyle=this.fillColor;b.fill();b.lineJoin="bevel";this
+.showStroke&&b.stroke()}});m.Rectangle=m.Element.extend({draw:function(){var
+ b=this.ctx,e=this.width/2,d=this.x-e,e=this.x+e,h=this.base-(this.base-this.y
+),n=this.strokeWidth/2;this.showStroke&&(d+=n,e-=n,h+=n);b.beginPath();b
+.fillStyle=this.fillColor;b.strokeStyle=this.strokeColor;
+b.lineWidth=this.strokeWidth;b.moveTo(d,this.base);b.lineTo(d,h);b.lineTo(e,h)
+;b.lineTo(e,this.base);b.fill();this.showStroke&&b.stroke()},height:function()
+{return this.base-this.y},inRange:function(b,e){return b>=this.x-this.width/2&
+&b<=this.x+this.width/2&&e>=this.y&&e<=this.base}});m.Tooltip=m.Element.extend
+({draw:function(){var b=this.chart.ctx;b.font=P(this.fontSize,this.fontStyle
+,this.fontFamily);this.xAlign="center";this.yAlign="above";var e=b.measureText
+(this.text).width+2*this.xPadding,d=
+this.fontSize+2*this.yPadding,h=d+this.caretHeight+2;this.x+e/2>this.chart
+.width?this.xAlign="left":0>this.x-e/2&&(this.xAlign="right");0>this.y-h&&
+(this.yAlign="below");var n=this.x-e/2,h=this.y-h;switch(b.fillStyle=this
+.fillColor,this.yAlign){case "above":b.beginPath();b.moveTo(this.x,this.y-2);b
+.lineTo(this.x+this.caretHeight,this.y-(2+this.caretHeight));b.lineTo(this
+.x-this.caretHeight,this.y-(2+this.caretHeight));b.closePath();b.fill();break
+;case "below":h=this.y+2+this.caretHeight,b.beginPath(),
+b.moveTo(this.x,this.y+2),b.lineTo(this.x+this.caretHeight,this.y+2+this
+.caretHeight),b.lineTo(this.x-this.caretHeight,this.y+2+this.caretHeight),b
+.closePath(),b.fill()}switch(this.xAlign){case "left":n=this.x-e+(this
+.cornerRadius+this.caretHeight);break;case "right":n=this.x-(this
+.cornerRadius+this.caretHeight)}ya(b,n,h,e,d,this.cornerRadius);b.fill();b
+.fillStyle=this.textColor;b.textAlign="center";b.textBaseline="middle";b
+.fillText(this.text,n+e/2,h+d/2)}});m.MultiTooltip=m.Element.extend(
+{initialize:function(){this.font=
+P(this.fontSize,this.fontStyle,this.fontFamily);this.titleFont=P(this
+.titleFontSize,this.titleFontStyle,this.titleFontFamily);this.height=this
+.labels.length*this.fontSize+this.fontSize/2*(this.labels.length-1)+2*this
+.yPadding+1.5*this.titleFontSize;this.ctx.font=this.titleFont;var b=this.ctx
+.measureText(this.title).width,e=ka(this.ctx,this.font,this.labels)+this
+.fontSize+3,b=ea([e,b]);this.width=b+2*this.xPadding;b=this.height/2;0>this
+.y-b?this.y=b:this.y+b>this.chart.height&&(this.y=this.chart.height-
+b);this.x>this.chart.width/2?this.x-=this.xOffset+this.width:this.x+=this
+.xOffset},getLineHeight:function(b){var e=this.y-this.height/2+this.yPadding
+,d=b-1;return 0===b?e+this.titleFontSize/2:e+(1.5*this.fontSize*d+this
+.fontSize/2)+1.5*this.titleFontSize},draw:function(){ya(this.ctx,this.x,this
+.y-this.height/2,this.width,this.height,this.cornerRadius);var b=this.ctx;b
+.fillStyle=this.fillColor;b.fill();b.closePath();b.textAlign="left";b
+.textBaseline="middle";b.fillStyle=this.titleTextColor;b.font=
+this.titleFont;b.fillText(this.title,this.x+this.xPadding,this.getLineHeight(0
+));b.font=this.font;d.each(this.labels,function(e,d){b.fillStyle=this
+.textColor;b.fillText(e,this.x+this.xPadding+this.fontSize+3,this
+.getLineHeight(d+1));b.fillStyle=this.legendColorBackground;b.fillRect(this
+.x+this.xPadding,this.getLineHeight(d+1)-this.fontSize/2,this.fontSize,this
+.fontSize);b.fillStyle=this.legendColors[d].fill;b.fillRect(this.x+this
+.xPadding,this.getLineHeight(d+1)-this.fontSize/2,this.fontSize,this.fontSize)
+},
+this)}});m.Scale=m.Element.extend({initialize:function(){this.fit()}
+,buildYLabels:function(){this.yLabels=[];for(var b=sa(this.stepValue),e=0
+;e<=this.steps;e++)this.yLabels.push(S(this.templateString,{value:(this
+.min+e*this.stepValue).toFixed(b)}));this.yLabelWidth=this.display&&this
+.showLabels?ka(this.ctx,this.font,this.yLabels):0},addXLabel:function(b){this
+.xLabels.push(b);this.valuesCount++;this.fit()},removeXLabel:function(){this
+.xLabels.shift();this.valuesCount--;this.fit()},fit:function(){this
+.startPoint=
+this.display?this.fontSize:0;this.endPoint=this.display?this.height-1.5*this
+.fontSize-5:this.height;this.startPoint+=this.padding;this.endPoint-=this
+.padding;var b,e=this.endPoint-this.startPoint;this.calculateYRange(e);this
+.buildYLabels();for(this.calculateXLabelRotation();e>this.endPoint-this
+.startPoint;)e=this.endPoint-this.startPoint,b=this.yLabelWidth,this
+.calculateYRange(e),this.buildYLabels(),b<this.yLabelWidth&&this
+.calculateXLabelRotation()},calculateXLabelRotation:function(){this.ctx.font=
+this.font;var b,e=this.ctx.measureText(this.xLabels[0]).width;b=this.ctx
+.measureText(this.xLabels[this.xLabels.length-1]).width;if(this
+.xScalePaddingRight=b/2+3,this.xScalePaddingLeft=e/2>this
+.yLabelWidth+10?e/2:this.yLabelWidth+10,this.xLabelRotation=0,this.display)
+{var d,h=ka(this.ctx,this.font,this.xLabels);this.xLabelWidth=h;for(var n=Math
+.floor(this.calculateX(1)-this.calculateX(0))-6;this.xLabelWidth>n&&0===this
+.xLabelRotation||this.xLabelWidth>n&&90>=this.xLabelRotation&&0<this
+.xLabelRotation;)d=
+Math.cos(F(this.xLabelRotation)),b=d*e,b+this.fontSize/2>this.yLabelWidth+8&&
+(this.xScalePaddingLeft=b+this.fontSize/2),this.xScalePaddingRight=this
+.fontSize/2,this.xLabelRotation++,this.xLabelWidth=d*h;0<this.xLabelRotation&&
+(this.endPoint-=Math.sin(F(this.xLabelRotation))*h+3)}else this.xLabelWidth=0
+,this.xScalePaddingLeft=this.xScalePaddingRight=this.padding}
+,calculateYRange:E,drawingArea:function(){return this.startPoint-this.endPoint
+},calculateY:function(b){var e=this.drawingArea()/(this.min-
+this.max);return this.endPoint-e*(b-this.min)},calculateX:function(b){var e=
+(0<this.xLabelRotation,this.width-(this.xScalePaddingLeft+this
+.xScalePaddingRight)),e=e/(this.valuesCount-(this.offsetGridLines?0:1))
+;b=e*b+this.xScalePaddingLeft;return this.offsetGridLines&&(b+=e/2),Math.round
+(b)},update:function(b){d.extend(this,b);this.fit()},draw:function(){var
+ b=this.ctx,e=(this.endPoint-this.startPoint)/this.steps,h=Math.round(this
+.xScalePaddingLeft);this.display&&(b.fillStyle=this.textColor,b.font=
+this.font,n(this.yLabels,function(n,m){var r=this.endPoint-e*m,p=Math.round(r)
+;b.textAlign="right";b.textBaseline="middle";this.showLabels&&b.fillText(n
+,h-10,r);b.beginPath();0<m?(b.lineWidth=this.gridLineWidth,b.strokeStyle=this
+.gridLineColor):(b.lineWidth=this.lineWidth,b.strokeStyle=this.lineColor);p+=d
+.aliasPixel(b.lineWidth);b.moveTo(h,p);b.lineTo(this.width,p);b.stroke();b
+.closePath();b.lineWidth=this.lineWidth;b.strokeStyle=this.lineColor;b
+.beginPath();b.moveTo(h-5,p);b.lineTo(h,p);b.stroke();
+b.closePath()},this),n(this.xLabels,function(e,d){var h=this.calculateX(d)+Da
+(this.lineWidth),n=this.calculateX(d-(this.offsetGridLines?.5:0))+Da(this
+.lineWidth),m=0<this.xLabelRotation;b.beginPath();0<d?(b.lineWidth=this
+.gridLineWidth,b.strokeStyle=this.gridLineColor):(b.lineWidth=this.lineWidth,b
+.strokeStyle=this.lineColor);b.moveTo(n,this.endPoint);b.lineTo(n,this
+.startPoint-3);b.stroke();b.closePath();b.lineWidth=this.lineWidth;b
+.strokeStyle=this.lineColor;b.beginPath();b.moveTo(n,this.endPoint);
+b.lineTo(n,this.endPoint+5);b.stroke();b.closePath();b.save();b.translate(h
+,m?this.endPoint+12:this.endPoint+8);b.rotate(-1*F(this.xLabelRotation));b
+.font=this.font;b.textAlign=m?"right":"center";b.textBaseline=m?"middle":"top"
+;b.fillText(e,0,0);b.restore()},this))}});m.RadialScale=m.Element.extend(
+{initialize:function(){this.size=R([this.height,this.width]);this
+.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY
+):this.size/2},calculateCenterOffset:function(b){var e=this.drawingArea/
+(this.max-this.min);return(b-this.min)*e},update:function(){this.lineArc?this
+.drawingArea=this.display?this.size/2-(this.fontSize/2+this.backdropPaddingY
+):this.size/2:this.setScaleSize();this.buildYLabels()},buildYLabels:function()
+{this.yLabels=[];for(var b=sa(this.stepValue),e=0;e<=this.steps;e++)this
+.yLabels.push(S(this.templateString,{value:(this.min+e*this.stepValue).toFixed
+(b)}))},getCircumference:function(){return 2*Math.PI/this.valuesCount}
+,setScaleSize:function(){var b,e,d,h,n,m,r,p=R([this.height/
+2-this.pointLabelFontSize-5,this.width/2]);r=this.width;var v=0;this.ctx
+.font=P(this.pointLabelFontSize,this.pointLabelFontStyle,this
+.pointLabelFontFamily);for(e=0;e<this.valuesCount;e++)b=this.getPointPosition
+(e,p),d=this.ctx.measureText(S(this.templateString,{value:this.labels[e]}))
+.width+5,0===e||e===this.valuesCount/2?(h=d/2,b.x+h>r&&(r=b.x+h,n=e),b.x-h<v&&
+(v=b.x-h,m=e)):e<this.valuesCount/2?b.x+d>r&&(r=b.x+d,n=e):e>this
+.valuesCount/2&&b.x-d<v&&(v=b.x-d,m=e);b=v;r=Math.ceil(r-this.width);n=this
+.getIndexAngle(n);
+m=this.getIndexAngle(m);n=r/Math.sin(n+Math.PI/2);m=b/Math.sin(m+Math.PI/2)
+;n=Q(n)?n:0;m=Q(m)?m:0;this.drawingArea=p-(m+n)/2;this.setCenterPoint(m,n)}
+,setCenterPoint:function(b,e){var d=this.width-e-this.drawingArea,h=b+this
+.drawingArea;this.xCenter=(h+d)/2;this.yCenter=this.height/2}
+,getIndexAngle:function(b){var e=2*Math.PI/this.valuesCount;return b*e-Math
+.PI/2},getPointPosition:function(b,e){var d=this.getIndexAngle(b);return
+{x:Math.cos(d)*e+this.xCenter,y:Math.sin(d)*e+this.yCenter}},draw:function()
+{if(this.display){var b=
+this.ctx;if(n(this.yLabels,function(e,d){if(0<d){var h;h=this.drawingArea/this
+.steps*d;var n=this.yCenter-h;if(0<this.lineWidth){if(b.strokeStyle=this
+.lineColor,b.lineWidth=this.lineWidth,this.lineArc)b.beginPath(),b.arc(this
+.xCenter,this.yCenter,h,0,2*Math.PI);else{b.beginPath();for(var m=0;m<this
+.valuesCount;m++)h=this.getPointPosition(m,this.calculateCenterOffset(this
+.min+d*this.stepValue)),0===m?b.moveTo(h.x,h.y):b.lineTo(h.x,h.y)}b.closePath(
+);b.stroke()}if(this.showLabels){if(b.font=P(this.fontSize,
+this.fontStyle,this.fontFamily),this.showLabelBackdrop)h=b.measureText(e)
+.width,b.fillStyle=this.backdropColor,b.fillRect(this.xCenter-h/2-this
+.backdropPaddingX,n-this.fontSize/2-this.backdropPaddingY,h+2*this
+.backdropPaddingX,this.fontSize+2*this.backdropPaddingY);b.textAlign="center"
+;b.textBaseline="middle";b.fillStyle=this.fontColor;b.fillText(e,this.xCenter
+,n)}}},this),!this.lineArc){b.lineWidth=this.angleLineWidth;b.strokeStyle=this
+.angleLineColor;for(var e=this.valuesCount-1;0<=e;e--){if(0<
+this.angleLineWidth){var d=this.getPointPosition(e,this.calculateCenterOffset
+(this.max));b.beginPath();b.moveTo(this.xCenter,this.yCenter);b.lineTo(d.x,d.y
+);b.stroke();b.closePath()}d=this.getPointPosition(e,this
+.calculateCenterOffset(this.max)+5);b.font=P(this.pointLabelFontSize,this
+.pointLabelFontStyle,this.pointLabelFontFamily);b.fillStyle=this
+.pointLabelFontColor;var h=this.labels.length,m=this.labels.length/2,r=m/2
+,p=r>e||e>h-r,h=e===r||e===h-r;b
+.textAlign=0===e?"center":e===m?"center":m>e?"left":
+"right";b.textBaseline=h?"middle":p?"bottom":"top";b.fillText(this.labels[e],d
+.x,d.y)}}}}});d.addEvent(window,"resize",function(){var b;return function()
+{clearTimeout(b);b=setTimeout(function(){n(m.instances,function(b){b.options
+.responsive&&b.resize(b.render,!0)})},50)}}());ra?define(function(){return m}
+):"object"==typeof module&&module.exports&&(module.exports=m);v.Chart=m;m
+.noConflict=function(){return v.Chart=p,m}}).call(this);
+(function(){var v=this,p=v.Chart,m=p.helpers,v={scaleBeginAtZero:!0
+,scaleShowGridLines:!0,scaleGridLineColor:"rgba(0,0,0,.05)"
+,scaleGridLineWidth:1,barShowStroke:!0,barStrokeWidth:2,barValueSpacing:5
+,barDatasetSpacing:1,legendTemplate:'<ul class="<%=name.toLowerCase(
+)%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span
+ style="background-color:<%=datasets[i].fillColor%>"></span><%if(datasets[i]
+.label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};p.Type.extend(
+{name:"Bar",defaults:v,initialize:function(d){var n=
+this.options;this.ScaleClass=p.Scale.extend({offsetGridLines:!0
+,calculateBarX:function(d,m,p){var v=this.calculateBaseWidth();p=this
+.calculateX(p)-v/2;d=this.calculateBarWidth(d);return p+d*m+m*n
+.barDatasetSpacing+d/2},calculateBaseWidth:function(){return this.calculateX(1
+)-this.calculateX(0)-2*n.barValueSpacing},calculateBarWidth:function(d){var
+ m=this.calculateBaseWidth()-(d-1)*n.barDatasetSpacing;return m/d}});this
+.datasets=[];this.options.showTooltips&&m.bindEvents(this,this.options
+.tooltipEvents,
+function(d){d="mouseout"!==d.type?this.getBarsAtEvent(d):[];this.eachBars
+(function(d){d.restore(["fillColor","strokeColor"])});m.each(d,function(d){d
+.fillColor=d.highlightFill;d.strokeColor=d.highlightStroke});this.showTooltip
+(d)});this.BarClass=p.Rectangle.extend({strokeWidth:this.options
+.barStrokeWidth,showStroke:this.options.barShowStroke,ctx:this.chart.ctx});m
+.each(d.datasets,function(h){var n={label:h.label||null,fillColor:h.fillColor
+,strokeColor:h.strokeColor,bars:[]};this.datasets.push(n);
+m.each(h.data,function(m,p){n.bars.push(new this.BarClass({value:m,label:d
+.labels[p],datasetLabel:h.label,strokeColor:h.strokeColor,fillColor:h
+.fillColor,highlightFill:h.highlightFill||h.fillColor,highlightStroke:h
+.highlightStroke||h.strokeColor}))},this)},this);this.buildScale(d.labels)
+;this.BarClass.prototype.base=this.scale.endPoint;this.eachBars(function(d,n,p
+){m.extend(d,{width:this.scale.calculateBarWidth(this.datasets.length),x:this
+.scale.calculateBarX(this.datasets.length,p,n),y:this.scale.endPoint});
+d.save()},this);this.render()},update:function(){this.scale.update();m.each
+(this.activeElements,function(d){d.restore(["fillColor","strokeColor"])});this
+.eachBars(function(d){d.save()});this.render()},eachBars:function(d){m.each
+(this.datasets,function(n,h){m.each(n.bars,d,this,h)},this)}
+,getBarsAtEvent:function(d){var n,h=[];d=m.getRelativePosition(d);for(var
+ r=function(d){h.push(d.bars[n])},p=0;p<this.datasets.length;p++)for(n=0
+;n<this.datasets[p].bars.length;n++)if(this.datasets[p].bars[n].inRange(d.x,
+d.y))return m.each(this.datasets,r),h;return h},buildScale:function(d){var
+ n=this,h=function(){var d=[];return n.eachBars(function(h){d.push(h.value)})
+,d};d={templateString:this.options.scaleLabel,height:this.chart.height
+,width:this.chart.width,ctx:this.chart.ctx,textColor:this.options
+.scaleFontColor,fontSize:this.options.scaleFontSize,fontStyle:this.options
+.scaleFontStyle,fontFamily:this.options.scaleFontFamily,valuesCount:d.length
+,beginAtZero:this.options.scaleBeginAtZero,integersOnly:this.options
+.scaleIntegersOnly,
+calculateYRange:function(d){d=m.calculateScaleRange(h(),d,this.fontSize,this
+.beginAtZero,this.integersOnly);m.extend(this,d)},xLabels:d,font:m.fontString
+(this.options.scaleFontSize,this.options.scaleFontStyle,this.options
+.scaleFontFamily),lineWidth:this.options.scaleLineWidth,lineColor:this.options
+.scaleLineColor,gridLineWidth:this.options.scaleShowGridLines?this.options
+.scaleGridLineWidth:0,gridLineColor:this.options.scaleShowGridLines?this
+.options.scaleGridLineColor:"rgba(0,0,0,0)",padding:this.options.showScale?
+0:this.options.barShowStroke?this.options.barStrokeWidth:0,showLabels:this
+.options.scaleShowLabels,display:this.options.showScale};this.options
+.scaleOverride&&m.extend(d,{calculateYRange:m.noop,steps:this.options
+.scaleSteps,stepValue:this.options.scaleStepWidth,min:this.options
+.scaleStartValue,max:this.options.scaleStartValue+this.options.scaleSteps*this
+.options.scaleStepWidth});this.scale=new this.ScaleClass(d)},addData:function
+(d,n){m.each(d,function(d,m){this.datasets[m].bars.push(new this.BarClass(
+{value:d,
+label:n,x:this.scale.calculateBarX(this.datasets.length,m,this.scale
+.valuesCount+1),y:this.scale.endPoint,width:this.scale.calculateBarWidth(this
+.datasets.length),base:this.scale.endPoint,strokeColor:this.datasets[m]
+.strokeColor,fillColor:this.datasets[m].fillColor}))},this);this.scale
+.addXLabel(n);this.update()},removeData:function(){this.scale.removeXLabel();m
+.each(this.datasets,function(d){d.bars.shift()},this);this.update()}
+,reflow:function(){m.extend(this.BarClass.prototype,{y:this.scale.endPoint,
+base:this.scale.endPoint});var d=m.extend({height:this.chart.height,width:this
+.chart.width});this.scale.update(d)},draw:function(d){var n=d||1;this.clear()
+;this.chart.ctx;this.scale.draw(n);m.each(this.datasets,function(d,p){m.each(d
+.bars,function(d,h){d.hasValue()&&(d.base=this.scale.endPoint,d.transition(
+{x:this.scale.calculateBarX(this.datasets.length,p,h),y:this.scale.calculateY
+(d.value),width:this.scale.calculateBarWidth(this.datasets.length)},n).draw())
+},this)},this)}})}).call(this);
+(function(){var v=this,p=v.Chart,m=p.helpers,v={segmentShowStroke:!0
+,segmentStrokeColor:"#fff",segmentStrokeWidth:2,percentageInnerCutout:50
+,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0
+,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><%
+ for (var i=0; i<segments.length; i++){%><li><span
+ style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i]
+.label){%><%=segments[i].label%><%}%></li><%}%></ul>'};p.Type.extend(
+{name:"Doughnut",defaults:v,
+initialize:function(d){this.segments=[];this.outerRadius=(m.min([this.chart
+.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2;this
+.SegmentArc=p.Arc.extend({ctx:this.chart.ctx,x:this.chart.width/2,y:this.chart
+.height/2});this.options.showTooltips&&m.bindEvents(this,this.options
+.tooltipEvents,function(d){d="mouseout"!==d.type?this.getSegmentsAtEvent(d):[]
+;m.each(this.segments,function(d){d.restore(["fillColor"])});m.each(d,function
+(d){d.fillColor=d.highlightColor});this.showTooltip(d)});
+this.calculateTotal(d);m.each(d,function(d,h){this.addData(d,h,!0)},this);this
+.render()},getSegmentsAtEvent:function(d){var n=[],h=m.getRelativePosition(d)
+;return m.each(this.segments,function(d){d.inRange(h.x,h.y)&&n.push(d)},this)
+,n},addData:function(d,n,h){n=n||this.segments.length;this.segments.splice(n,0
+,new this.SegmentArc({value:d.value,outerRadius:this.options
+.animateScale?0:this.outerRadius,innerRadius:this.options.animateScale?0:this
+.outerRadius/100*this.options.percentageInnerCutout,fillColor:d.color,
+highlightColor:d.highlight||d.color,showStroke:this.options.segmentShowStroke
+,strokeWidth:this.options.segmentStrokeWidth,strokeColor:this.options
+.segmentStrokeColor,startAngle:1.5*Math.PI,circumference:this.options
+.animateRotate?0:this.calculateCircumference(d.value),label:d.label}));h||
+(this.reflow(),this.update())},calculateCircumference:function(d){return
+ d/this.total*Math.PI*2},calculateTotal:function(d){this.total=0;m.each(d
+,function(d){this.total+=d.value},this)},update:function(){this.calculateTotal
+(this.segments);
+m.each(this.activeElements,function(d){d.restore(["fillColor"])});m.each(this
+.segments,function(d){d.save()});this.render()},removeData:function(d){d=m
+.isNumber(d)?d:this.segments.length-1;this.segments.splice(d,1);this.reflow()
+;this.update()},reflow:function(){m.extend(this.SegmentArc.prototype,{x:this
+.chart.width/2,y:this.chart.height/2});this.outerRadius=(m.min([this.chart
+.width,this.chart.height])-this.options.segmentStrokeWidth/2)/2;m.each(this
+.segments,function(d){d.update({outerRadius:this.outerRadius,
+innerRadius:this.outerRadius/100*this.options.percentageInnerCutout})},this)}
+,draw:function(d){var n=d?d:1;this.clear();m.each(this.segments,function(d,m)
+{d.transition({circumference:this.calculateCircumference(d.value)
+,outerRadius:this.outerRadius,innerRadius:this.outerRadius/100*this.options
+.percentageInnerCutout},n);d.endAngle=d.startAngle+d.circumference;d.draw()
+;0===m&&(d.startAngle=1.5*Math.PI);m<this.segments.length-1&&(this.segments
+[m+1].startAngle=d.endAngle)},this)}});p.types.Doughnut.extend({name:"Pie",
+defaults:m.merge(v,{percentageInnerCutout:0})})}).call(this);
+(function(){var v=this,p=v.Chart,m=p.helpers,v={scaleShowGridLines:!0
+,scaleGridLineColor:"rgba(0,0,0,.05)",scaleGridLineWidth:1,bezierCurve:!0
+,bezierCurveTension:.4,pointDot:!0,pointDotRadius:4,pointDotStrokeWidth:1
+,pointHitDetectionRadius:20,datasetStroke:!0,datasetStrokeWidth:2
+,datasetFill:!0,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><%
+ for (var i=0; i<datasets.length; i++){%><li><span
+ style="background-color:<%=datasets[i].strokeColor%>"></span><%if(datasets[i]
+.label){%><%=datasets[i].label%><%}%></li><%}%></ul>'};p.Type.extend(
+{name:"Line",
+defaults:v,initialize:function(d){this.PointClass=p.Point.extend(
+{strokeWidth:this.options.pointDotStrokeWidth,radius:this.options
+.pointDotRadius,display:this.options.pointDot,hitDetectionRadius:this.options
+.pointHitDetectionRadius,ctx:this.chart.ctx,inRange:function(d){return Math
+.pow(d-this.x,2)<Math.pow(this.radius+this.hitDetectionRadius,2)}});this
+.datasets=[];this.options.showTooltips&&m.bindEvents(this,this.options
+.tooltipEvents,function(d){d="mouseout"!==d.type?this.getPointsAtEvent(d):[];
+this.eachPoints(function(d){d.restore(["fillColor","strokeColor"])});m.each(d
+,function(d){d.fillColor=d.highlightFill;d.strokeColor=d.highlightStroke})
+;this.showTooltip(d)});m.each(d.datasets,function(n){var h={label:n.label|
+|null,fillColor:n.fillColor,strokeColor:n.strokeColor,pointColor:n.pointColor
+,pointStrokeColor:n.pointStrokeColor,points:[]};this.datasets.push(h);m.each(n
+.data,function(m,p){h.points.push(new this.PointClass({value:m,label:d.labels
+[p],datasetLabel:n.label,strokeColor:n.pointStrokeColor,
+fillColor:n.pointColor,highlightFill:n.pointHighlightFill||n.pointColor
+,highlightStroke:n.pointHighlightStroke||n.pointStrokeColor}))},this);this
+.buildScale(d.labels);this.eachPoints(function(d,h){m.extend(d,{x:this.scale
+.calculateX(h),y:this.scale.endPoint});d.save()},this)},this);this.render()}
+,update:function(){this.scale.update();m.each(this.activeElements,function(d)
+{d.restore(["fillColor","strokeColor"])});this.eachPoints(function(d){d.save()
+});this.render()},eachPoints:function(d){m.each(this.datasets,
+function(n){m.each(n.points,d,this)},this)},getPointsAtEvent:function(d){var
+ n=[],h=m.getRelativePosition(d);return m.each(this.datasets,function(d){m
+.each(d.points,function(d){d.inRange(h.x,h.y)&&n.push(d)})},this),n}
+,buildScale:function(d){var n=this,h=function(){var d=[];return n.eachPoints
+(function(h){d.push(h.value)}),d};d={templateString:this.options.scaleLabel
+,height:this.chart.height,width:this.chart.width,ctx:this.chart.ctx
+,textColor:this.options.scaleFontColor,fontSize:this.options.scaleFontSize,
+fontStyle:this.options.scaleFontStyle,fontFamily:this.options.scaleFontFamily
+,valuesCount:d.length,beginAtZero:this.options.scaleBeginAtZero
+,integersOnly:this.options.scaleIntegersOnly,calculateYRange:function(d){d=m
+.calculateScaleRange(h(),d,this.fontSize,this.beginAtZero,this.integersOnly);m
+.extend(this,d)},xLabels:d,font:m.fontString(this.options.scaleFontSize,this
+.options.scaleFontStyle,this.options.scaleFontFamily),lineWidth:this.options
+.scaleLineWidth,lineColor:this.options.scaleLineColor,gridLineWidth:this
+.options.scaleShowGridLines?
+this.options.scaleGridLineWidth:0,gridLineColor:this.options
+.scaleShowGridLines?this.options.scaleGridLineColor:"rgba(0,0,0,0)"
+,padding:this.options.showScale?0:this.options.pointDotRadius+this.options
+.pointDotStrokeWidth,showLabels:this.options.scaleShowLabels,display:this
+.options.showScale};this.options.scaleOverride&&m.extend(d,{calculateYRange:m
+.noop,steps:this.options.scaleSteps,stepValue:this.options.scaleStepWidth
+,min:this.options.scaleStartValue,max:this.options.scaleStartValue+this
+.options.scaleSteps*
+this.options.scaleStepWidth});this.scale=new p.Scale(d)},addData:function(d,n)
+{m.each(d,function(d,m){this.datasets[m].points.push(new this.PointClass(
+{value:d,label:n,x:this.scale.calculateX(this.scale.valuesCount+1),y:this
+.scale.endPoint,strokeColor:this.datasets[m].pointStrokeColor,fillColor:this
+.datasets[m].pointColor}))},this);this.scale.addXLabel(n);this.update()}
+,removeData:function(){this.scale.removeXLabel();m.each(this.datasets,function
+(d){d.points.shift()},this);this.update()},reflow:function(){var d=
+m.extend({height:this.chart.height,width:this.chart.width});this.scale.update
+(d)},draw:function(d){var n=d||1;this.clear();var h=this.chart.ctx,p=function
+(d){return null!==d.value},v=function(d,h,n){return m.findNextWhere(h,p,n)||d}
+,D=function(d,h,n){return m.findPreviousWhere(h,p,n)||d};this.scale.draw(n);m
+.each(this.datasets,function(d){var E=m.where(d.points,p);m.each(d.points
+,function(d,h){d.hasValue()&&d.transition({y:this.scale.calculateY(d.value)
+,x:this.scale.calculateX(h)},n)},this);this.options.bezierCurve&&
+m.each(E,function(d,h){var n=0<h&&h<E.length-1?this.options
+.bezierCurveTension:0;d.controlPoints=m.splineCurve(D(d,E,h),d,v(d,E,h),n);d
+.controlPoints.outer.y>this.scale.endPoint?d.controlPoints.outer.y=this.scale
+.endPoint:d.controlPoints.outer.y<this.scale.startPoint&&(d.controlPoints
+.outer.y=this.scale.startPoint);d.controlPoints.inner.y>this.scale.endPoint?d
+.controlPoints.inner.y=this.scale.endPoint:d.controlPoints.inner.y<this.scale
+.startPoint&&(d.controlPoints.inner.y=this.scale.startPoint)},
+this);h.lineWidth=this.options.datasetStrokeWidth;h.strokeStyle=d.strokeColor
+;h.beginPath();m.each(E,function(d,n){if(0===n)h.moveTo(d.x,d.y);else if(this
+.options.bezierCurve){var m=D(d,E,n);h.bezierCurveTo(m.controlPoints.outer.x,m
+.controlPoints.outer.y,d.controlPoints.inner.x,d.controlPoints.inner.y,d.x,d.y
+)}else h.lineTo(d.x,d.y)},this);h.stroke();this.options.datasetFill&&0<E
+.length&&(h.lineTo(E[E.length-1].x,this.scale.endPoint),h.lineTo(E[0].x,this
+.scale.endPoint),h.fillStyle=d.fillColor,h.closePath(),
+h.fill());m.each(E,function(d){d.draw()})},this)}})}).call(this);
+(function(){var v=this,p=v.Chart,m=p.helpers,v={scaleShowLabelBackdrop:!0
+,scaleBackdropColor:"rgba(255,255,255,0.75)",scaleBeginAtZero:!0
+,scaleBackdropPaddingY:2,scaleBackdropPaddingX:2,scaleShowLine:!0
+,segmentShowStroke:!0,segmentStrokeColor:"#fff",segmentStrokeWidth:2
+,animationSteps:100,animationEasing:"easeOutBounce",animateRotate:!0
+,animateScale:!1,legendTemplate:'<ul class="<%=name.toLowerCase()%>-legend"><%
+ for (var i=0; i<segments.length; i++){%><li><span
+ style="background-color:<%=segments[i].fillColor%>"></span><%if(segments[i]
+.label){%><%=segments[i].label%><%}%></li><%}%></ul>'};p.Type.extend(
+{name:"PolarArea",
+defaults:v,initialize:function(d){this.segments=[];this.SegmentArc=p.Arc
+.extend({showStroke:this.options.segmentShowStroke,strokeWidth:this.options
+.segmentStrokeWidth,strokeColor:this.options.segmentStrokeColor,ctx:this.chart
+.ctx,innerRadius:0,x:this.chart.width/2,y:this.chart.height/2});this.scale=new
+ p.RadialScale({display:this.options.showScale,fontStyle:this.options
+.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options
+.scaleFontFamily,fontColor:this.options.scaleFontColor,
+showLabels:this.options.scaleShowLabels,showLabelBackdrop:this.options
+.scaleShowLabelBackdrop,backdropColor:this.options.scaleBackdropColor
+,backdropPaddingY:this.options.scaleBackdropPaddingY,backdropPaddingX:this
+.options.scaleBackdropPaddingX,lineWidth:this.options.scaleShowLine?this
+.options.scaleLineWidth:0,lineColor:this.options.scaleLineColor,lineArc:!0
+,width:this.chart.width,height:this.chart.height,xCenter:this.chart.width/2
+,yCenter:this.chart.height/2,ctx:this.chart.ctx,templateString:this.options
+.scaleLabel,
+valuesCount:d.length});this.updateScaleRange(d);this.scale.update();m.each(d
+,function(d,h){this.addData(d,h,!0)},this);this.options.showTooltips&&m
+.bindEvents(this,this.options.tooltipEvents,function(d){d="mouseout"!==d
+.type?this.getSegmentsAtEvent(d):[];m.each(this.segments,function(d){d.restore
+(["fillColor"])});m.each(d,function(d){d.fillColor=d.highlightColor});this
+.showTooltip(d)});this.render()},getSegmentsAtEvent:function(d){var n=[],h=m
+.getRelativePosition(d);return m.each(this.segments,function(d){d.inRange(h.x,
+h.y)&&n.push(d)},this),n},addData:function(d,n,h){n=n||this.segments.length
+;this.segments.splice(n,0,new this.SegmentArc({fillColor:d.color
+,highlightColor:d.highlight||d.color,label:d.label,value:d.value
+,outerRadius:this.options.animateScale?0:this.scale.calculateCenterOffset(d
+.value),circumference:this.options.animateRotate?0:this.scale.getCircumference
+(),startAngle:1.5*Math.PI}));h||(this.reflow(),this.update())}
+,removeData:function(d){d=m.isNumber(d)?d:this.segments.length-1;this.segments
+.splice(d,
+1);this.reflow();this.update()},calculateTotal:function(d){this.total=0;m.each
+(d,function(d){this.total+=d.value},this);this.scale.valuesCount=this.segments
+.length},updateScaleRange:function(d){var n=[];m.each(d,function(d){n.push(d
+.value)});d=this.options.scaleOverride?{steps:this.options.scaleSteps
+,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue
+,max:this.options.scaleStartValue+this.options.scaleSteps*this.options
+.scaleStepWidth}:m.calculateScaleRange(n,m.min([this.chart.width,
+this.chart.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero
+,this.options.scaleIntegersOnly);m.extend(this.scale,d,{size:m.min([this.chart
+.width,this.chart.height]),xCenter:this.chart.width/2,yCenter:this.chart
+.height/2})},update:function(){this.calculateTotal(this.segments);m.each(this
+.segments,function(d){d.save()});this.render()},reflow:function(){m.extend
+(this.SegmentArc.prototype,{x:this.chart.width/2,y:this.chart.height/2});this
+.updateScaleRange(this.segments);this.scale.update();
+m.extend(this.scale,{xCenter:this.chart.width/2,yCenter:this.chart.height/2})
+;m.each(this.segments,function(d){d.update({outerRadius:this.scale
+.calculateCenterOffset(d.value)})},this)},draw:function(d){var n=d||1;this
+.clear();m.each(this.segments,function(d,m){d.transition({circumference:this
+.scale.getCircumference(),outerRadius:this.scale.calculateCenterOffset(d.value
+)},n);d.endAngle=d.startAngle+d.circumference;0===m&&(d.startAngle=1.5*Math.PI
+);m<this.segments.length-1&&(this.segments[m+1].startAngle=
+d.endAngle);d.draw()},this);this.scale.draw()}})}).call(this);
+(function(){var v=this,p=v.Chart,m=p.helpers;p.Type.extend({name:"Radar"
+,defaults:{scaleShowLine:!0,angleShowLineOut:!0,scaleShowLabels:!1
+,scaleBeginAtZero:!0,angleLineColor:"rgba(0,0,0,.1)",angleLineWidth:1
+,pointLabelFontFamily:"'Arial'",pointLabelFontStyle:"normal"
+,pointLabelFontSize:10,pointLabelFontColor:"#666",pointDot:!0,pointDotRadius:3
+,pointDotStrokeWidth:1,pointHitDetectionRadius:20,datasetStroke:!0
+,datasetStrokeWidth:2,datasetFill:!0,legendTemplate:'<ul class="<%=name
+.toLowerCase()%>-legend"><% for (var i=0; i<datasets.length; i++){%><li><span
+ style="background-color:<%=datasets[i].strokeColor%>"></span><%if(datasets[i]
+.label){%><%=datasets[i].label%><%}%></li><%}%></ul>'},
+initialize:function(d){this.PointClass=p.Point.extend({strokeWidth:this
+.options.pointDotStrokeWidth,radius:this.options.pointDotRadius,display:this
+.options.pointDot,hitDetectionRadius:this.options.pointHitDetectionRadius
+,ctx:this.chart.ctx});this.datasets=[];this.buildScale(d);this.options
+.showTooltips&&m.bindEvents(this,this.options.tooltipEvents,function(d)
+{d="mouseout"!==d.type?this.getPointsAtEvent(d):[];this.eachPoints(function(d)
+{d.restore(["fillColor","strokeColor"])});m.each(d,function(d){d.fillColor=
+d.highlightFill;d.strokeColor=d.highlightStroke});this.showTooltip(d)});m.each
+(d.datasets,function(n){var h={label:n.label||null,fillColor:n.fillColor
+,strokeColor:n.strokeColor,pointColor:n.pointColor,pointStrokeColor:n
+.pointStrokeColor,points:[]};this.datasets.push(h);m.each(n.data,function(m,p)
+{var v;this.scale.animation||(v=this.scale.getPointPosition(p,this.scale
+.calculateCenterOffset(m)));h.points.push(new this.PointClass({value:m,label:d
+.labels[p],datasetLabel:n.label,x:this.options.animation?
+this.scale.xCenter:v.x,y:this.options.animation?this.scale.yCenter:v.y
+,strokeColor:n.pointStrokeColor,fillColor:n.pointColor,highlightFill:n
+.pointHighlightFill||n.pointColor,highlightStroke:n.pointHighlightStroke||n
+.pointStrokeColor}))},this)},this);this.render()},eachPoints:function(d){m
+.each(this.datasets,function(n){m.each(n.points,d,this)},this)}
+,getPointsAtEvent:function(d){d=m.getRelativePosition(d);d=m.getAngleFromPoint
+({x:this.scale.xCenter,y:this.scale.yCenter},d);var n=2*Math.PI/this.scale
+.valuesCount,
+h=Math.round((d.angle-1.5*Math.PI)/n),p=[];return(h>=this.scale.valuesCount|
+|0>h)&&(h=0),d.distance<=this.scale.drawingArea&&m.each(this.datasets,function
+(d){p.push(d.points[h])}),p},buildScale:function(d){this.scale=new p
+.RadialScale({display:this.options.showScale,fontStyle:this.options
+.scaleFontStyle,fontSize:this.options.scaleFontSize,fontFamily:this.options
+.scaleFontFamily,fontColor:this.options.scaleFontColor,showLabels:this.options
+.scaleShowLabels,showLabelBackdrop:this.options.scaleShowLabelBackdrop,
+backdropColor:this.options.scaleBackdropColor,backdropPaddingY:this.options
+.scaleBackdropPaddingY,backdropPaddingX:this.options.scaleBackdropPaddingX
+,lineWidth:this.options.scaleShowLine?this.options.scaleLineWidth:0
+,lineColor:this.options.scaleLineColor,angleLineColor:this.options
+.angleLineColor,angleLineWidth:this.options.angleShowLineOut?this.options
+.angleLineWidth:0,pointLabelFontColor:this.options.pointLabelFontColor
+,pointLabelFontSize:this.options.pointLabelFontSize,pointLabelFontFamily:this
+.options.pointLabelFontFamily,
+pointLabelFontStyle:this.options.pointLabelFontStyle,height:this.chart.height
+,width:this.chart.width,xCenter:this.chart.width/2,yCenter:this.chart.height/2
+,ctx:this.chart.ctx,templateString:this.options.scaleLabel,labels:d.labels
+,valuesCount:d.datasets[0].data.length});this.scale.setScaleSize();this
+.updateScaleRange(d.datasets);this.scale.buildYLabels()}
+,updateScaleRange:function(d){var n=function(){var h=[];return m.each(d
+,function(d){d.data?h=h.concat(d.data):m.each(d.points,function(d){h.push(d
+.value)})}),
+h}(),n=this.options.scaleOverride?{steps:this.options.scaleSteps
+,stepValue:this.options.scaleStepWidth,min:this.options.scaleStartValue
+,max:this.options.scaleStartValue+this.options.scaleSteps*this.options
+.scaleStepWidth}:m.calculateScaleRange(n,m.min([this.chart.width,this.chart
+.height])/2,this.options.scaleFontSize,this.options.scaleBeginAtZero,this
+.options.scaleIntegersOnly);m.extend(this.scale,n)},addData:function(d,n){this
+.scale.valuesCount++;m.each(d,function(d,m){var p=this.scale.getPointPosition
+(this.scale.valuesCount,
+this.scale.calculateCenterOffset(d));this.datasets[m].points.push(new this
+.PointClass({value:d,label:n,x:p.x,y:p.y,strokeColor:this.datasets[m]
+.pointStrokeColor,fillColor:this.datasets[m].pointColor}))},this);this.scale
+.labels.push(n);this.reflow();this.update()},removeData:function(){this.scale
+.valuesCount--;this.scale.labels.shift();m.each(this.datasets,function(d){d
+.points.shift()},this);this.reflow();this.update()},update:function(){this
+.eachPoints(function(d){d.save()});this.reflow();this.render()},
+reflow:function(){m.extend(this.scale,{width:this.chart.width,height:this
+.chart.height,size:m.min([this.chart.width,this.chart.height]),xCenter:this
+.chart.width/2,yCenter:this.chart.height/2});this.updateScaleRange(this
+.datasets);this.scale.setScaleSize();this.scale.buildYLabels()},draw:function
+(d){var n=d||1,h=this.chart.ctx;this.clear();this.scale.draw();m.each(this
+.datasets,function(d){m.each(d.points,function(d,h){d.hasValue()&&d.transition
+(this.scale.getPointPosition(h,this.scale.calculateCenterOffset(d.value)),
+n)},this);h.lineWidth=this.options.datasetStrokeWidth;h.strokeStyle=d
+.strokeColor;h.beginPath();m.each(d.points,function(d,m){0===m?h.moveTo(d.x,d
+.y):h.lineTo(d.x,d.y)},this);h.closePath();h.stroke();h.fillStyle=d.fillColor
+;h.fill();m.each(d.points,function(d){d.hasValue()&&d.draw()})},this)}})})
+.call(this);
diff --git a/chrome/test/media_router/media_router_integration_browsertest.cc b/chrome/test/media_router/media_router_integration_browsertest.cc
index 34fdf13a..ef6e2bf 100644
--- a/chrome/test/media_router/media_router_integration_browsertest.cc
+++ b/chrome/test/media_router/media_router_integration_browsertest.cc
@@ -38,7 +38,7 @@
 const char kCheckSessionScript[] = "checkSession();";
 const char kCheckStartFailedScript[] = "checkStartFailed('%s', '%s');";
 const char kStartSessionScript[] = "startSession();";
-const char kStopSessionScript[] = "stopSession()";
+const char kTerminateSessionScript[] = "terminateSession()";
 const char kWaitDeviceScript[] = "waitUntilDeviceAvailable();";
 const char kChooseSinkScript[] =
     "var sinks = document.getElementById('media-router-container')."
@@ -332,7 +332,7 @@
       GetDefaultRequestSessionId(web_contents));
   EXPECT_EQ(session_id, default_request_session_id);
 
-  ExecuteJavaScriptAPI(web_contents, kStopSessionScript);
+  ExecuteJavaScriptAPI(web_contents, kTerminateSessionScript);
 }
 
 IN_PROC_BROWSER_TEST_F(MediaRouterIntegrationBrowserTest,
diff --git a/chrome/test/media_router/resources/common.js b/chrome/test/media_router/resources/common.js
index 19baed4..5e8c8dd6 100644
--- a/chrome/test/media_router/resources/common.js
+++ b/chrome/test/media_router/resources/common.js
@@ -65,8 +65,8 @@
         sendResult(true, '');
       }
     }).catch(function() {
-      // close old session if exists
-      startedSession && startedSession.close();
+      // terminate old session if exists
+      startedSession && startedSession.terminate();
       sendResult(false, 'Failed to start session');
     })
   }
@@ -98,11 +98,11 @@
 }
 
 /**
- * Stops current session.
+ * Terminates current session.
  */
-function stopSession() {
+function terminateSession() {
   if (startedSession) {
-    startedSession.close();
+    startedSession.terminate();
   }
   sendResult(true, '');
 }
diff --git a/components/content_settings/core/browser/content_settings_registry.cc b/components/content_settings/core/browser/content_settings_registry.cc
index faa5f838..a5974d449 100644
--- a/components/content_settings/core/browser/content_settings_registry.cc
+++ b/components/content_settings/core/browser/content_settings_registry.cc
@@ -117,19 +117,22 @@
            WebsiteSettingsInfo::SYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_SESSION_ONLY));
+                         CONTENT_SETTING_SESSION_ONLY),
+           WebsiteSettingsInfo::REQUESTING_DOMAIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_IMAGES, "images", CONTENT_SETTING_ALLOW,
            WebsiteSettingsInfo::SYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
                               kExtensionScheme),
-           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK));
+           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_JAVASCRIPT, "javascript",
            CONTENT_SETTING_ALLOW, WebsiteSettingsInfo::SYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
                               kExtensionScheme),
-           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK));
+           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_PLUGINS, "plugins",
            CONTENT_SETTING_DETECT_IMPORTANT_CONTENT,
@@ -137,85 +140,99 @@
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
                          CONTENT_SETTING_ASK,
-                         CONTENT_SETTING_DETECT_IMPORTANT_CONTENT));
+                         CONTENT_SETTING_DETECT_IMPORTANT_CONTENT),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_POPUPS, "popups", CONTENT_SETTING_BLOCK,
            WebsiteSettingsInfo::SYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
                               kExtensionScheme),
-           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK));
+           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_GEOLOCATION, "geolocation",
            CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
            WhitelistedSchemes(),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_NOTIFICATIONS, "notifications",
            CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
            WhitelistedSchemes(),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_FULLSCREEN, "fullscreen", CONTENT_SETTING_ASK,
            WebsiteSettingsInfo::SYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
-           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK));
+           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_MOUSELOCK, "mouselock", CONTENT_SETTING_ASK,
            WebsiteSettingsInfo::SYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC, "media-stream-mic",
            CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA, "media-stream-camera",
            CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_PPAPI_BROKER, "ppapi-broker",
            CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS, "automatic-downloads",
            CONTENT_SETTING_ASK, WebsiteSettingsInfo::SYNCABLE,
            WhitelistedSchemes(kChromeUIScheme, kChromeDevToolsScheme,
                               kExtensionScheme),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_MIDI_SYSEX, "midi-sysex", CONTENT_SETTING_ASK,
            WebsiteSettingsInfo::SYNCABLE, WhitelistedSchemes(),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_PUSH_MESSAGING, "push-messaging",
            CONTENT_SETTING_ASK, WebsiteSettingsInfo::SYNCABLE,
            WhitelistedSchemes(),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE);
 
 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
   Register(CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER,
            "protected-media-identifier", CONTENT_SETTING_ASK,
            WebsiteSettingsInfo::UNSYNCABLE, WhitelistedSchemes(),
            ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK,
-                         CONTENT_SETTING_ASK));
+                         CONTENT_SETTING_ASK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE);
 #endif
 
   Register(CONTENT_SETTINGS_TYPE_DURABLE_STORAGE, "durable-storage",
            CONTENT_SETTING_ASK, WebsiteSettingsInfo::UNSYNCABLE,
            WhitelistedSchemes(),
-           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK));
+           ValidSettings(CONTENT_SETTING_ALLOW, CONTENT_SETTING_BLOCK),
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE);
 
   // Content settings that aren't used to store any data. TODO(raymes): use a
   // different mechanism rather than content settings to represent these.
@@ -223,16 +240,19 @@
   // content setting.
   Register(CONTENT_SETTINGS_TYPE_PROTOCOL_HANDLERS, "protocol-handler",
            CONTENT_SETTING_DEFAULT, WebsiteSettingsInfo::UNSYNCABLE,
-           WhitelistedSchemes(), ValidSettings());
+           WhitelistedSchemes(), ValidSettings(),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   Register(CONTENT_SETTINGS_TYPE_MIXEDSCRIPT, "mixed-script",
            CONTENT_SETTING_DEFAULT, WebsiteSettingsInfo::UNSYNCABLE,
-           WhitelistedSchemes(), ValidSettings());
+           WhitelistedSchemes(), ValidSettings(),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   // Deprecated.
   Register(CONTENT_SETTINGS_TYPE_MEDIASTREAM, "media-stream",
            CONTENT_SETTING_DEFAULT, WebsiteSettingsInfo::UNSYNCABLE,
-           WhitelistedSchemes(), ValidSettings());
+           WhitelistedSchemes(), ValidSettings(),
+           WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 }
 
 void ContentSettingsRegistry::Register(
@@ -241,15 +261,16 @@
     ContentSetting initial_default_value,
     WebsiteSettingsInfo::SyncStatus sync_status,
     const std::vector<std::string>& whitelisted_schemes,
-    const std::set<ContentSetting>& valid_settings) {
+    const std::set<ContentSetting>& valid_settings,
+    WebsiteSettingsInfo::ScopingType scoping_type) {
   // Ensure that nothing has been registered yet for the given type.
   DCHECK(!website_settings_registry_->Get(type));
   scoped_ptr<base::Value> default_value(
       new base::FundamentalValue(static_cast<int>(initial_default_value)));
   const WebsiteSettingsInfo* website_settings_info =
-      website_settings_registry_->Register(type, name, default_value.Pass(),
-                                           sync_status,
-                                           WebsiteSettingsInfo::NOT_LOSSY);
+      website_settings_registry_->Register(
+          type, name, default_value.Pass(), sync_status,
+          WebsiteSettingsInfo::NOT_LOSSY, scoping_type);
   DCHECK(!ContainsKey(content_settings_info_, type));
   content_settings_info_.set(
       type, make_scoped_ptr(new ContentSettingsInfo(
diff --git a/components/content_settings/core/browser/content_settings_registry.h b/components/content_settings/core/browser/content_settings_registry.h
index c0e6b734..7bbd07ca 100644
--- a/components/content_settings/core/browser/content_settings_registry.h
+++ b/components/content_settings/core/browser/content_settings_registry.h
@@ -61,7 +61,8 @@
                 ContentSetting initial_default_value,
                 WebsiteSettingsInfo::SyncStatus sync_status,
                 const std::vector<std::string>& whitelisted_schemes,
-                const std::set<ContentSetting>& valid_settings);
+                const std::set<ContentSetting>& valid_settings,
+                WebsiteSettingsInfo::ScopingType scoping_type);
 
   Map content_settings_info_;
   WebsiteSettingsRegistry* website_settings_registry_;
diff --git a/components/content_settings/core/browser/website_settings_info.cc b/components/content_settings/core/browser/website_settings_info.cc
index 20faa27..4bffcb8 100644
--- a/components/content_settings/core/browser/website_settings_info.cc
+++ b/components/content_settings/core/browser/website_settings_info.cc
@@ -30,14 +30,16 @@
     const std::string& name,
     scoped_ptr<base::Value> initial_default_value,
     SyncStatus sync_status,
-    LossyStatus lossy_status)
+    LossyStatus lossy_status,
+    ScopingType scoping_type)
     : type_(type),
       name_(name),
       pref_name_(GetPrefName(name, kPrefPrefix)),
       default_value_pref_name_(GetPrefName(name, kDefaultPrefPrefix)),
       initial_default_value_(initial_default_value.Pass()),
       sync_status_(sync_status),
-      lossy_status_(lossy_status) {
+      lossy_status_(lossy_status),
+      scoping_type_(scoping_type) {
   // For legacy reasons the default value is currently restricted to be an int.
   // TODO(raymes): We should migrate the underlying pref to be a dictionary
   // rather than an int.
diff --git a/components/content_settings/core/browser/website_settings_info.h b/components/content_settings/core/browser/website_settings_info.h
index 8ad9842..532878e 100644
--- a/components/content_settings/core/browser/website_settings_info.h
+++ b/components/content_settings/core/browser/website_settings_info.h
@@ -24,11 +24,28 @@
 
   enum LossyStatus { LOSSY, NOT_LOSSY };
 
+  enum ScopingType {
+    // Settings scoped to the domain of the main frame only.
+    TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+
+    // Settings scoped to the origin of the requesting frame only.
+    REQUESTING_ORIGIN_ONLY_SCOPE,
+
+    // Settings scoped to the domain of the requesting frame only. This should
+    // not generally be used.
+    REQUESTING_DOMAIN_ONLY_SCOPE,
+
+    // Settings scoped to the combination of the origin of the requesting
+    // frame and the origin of the top level frame.
+    REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE
+  };
+
   WebsiteSettingsInfo(ContentSettingsType type,
                       const std::string& name,
                       scoped_ptr<base::Value> initial_default_value,
                       SyncStatus sync_status,
-                      LossyStatus lossy_status);
+                      LossyStatus lossy_status,
+                      ScopingType scoping_type);
   ~WebsiteSettingsInfo();
 
   ContentSettingsType type() const { return type_; }
@@ -44,6 +61,8 @@
 
   uint32 GetPrefRegistrationFlags() const;
 
+  ScopingType scoping_type() const { return scoping_type_; }
+
  private:
   const ContentSettingsType type_;
   const std::string name_;
@@ -53,6 +72,7 @@
   const scoped_ptr<base::Value> initial_default_value_;
   const SyncStatus sync_status_;
   const LossyStatus lossy_status_;
+  const ScopingType scoping_type_;
 
   DISALLOW_COPY_AND_ASSIGN(WebsiteSettingsInfo);
 };
diff --git a/components/content_settings/core/browser/website_settings_registry.cc b/components/content_settings/core/browser/website_settings_registry.cc
index cf237501..662141e 100644
--- a/components/content_settings/core/browser/website_settings_registry.cc
+++ b/components/content_settings/core/browser/website_settings_registry.cc
@@ -54,9 +54,11 @@
     const std::string& name,
     scoped_ptr<base::Value> initial_default_value,
     WebsiteSettingsInfo::SyncStatus sync_status,
-    WebsiteSettingsInfo::LossyStatus lossy_status) {
-  WebsiteSettingsInfo* info = new WebsiteSettingsInfo(
-      type, name, initial_default_value.Pass(), sync_status, lossy_status);
+    WebsiteSettingsInfo::LossyStatus lossy_status,
+    WebsiteSettingsInfo::ScopingType scoping_type) {
+  WebsiteSettingsInfo* info =
+      new WebsiteSettingsInfo(type, name, initial_default_value.Pass(),
+                              sync_status, lossy_status, scoping_type);
   website_settings_info_.set(info->type(), make_scoped_ptr(info));
   return info;
 }
@@ -80,16 +82,21 @@
   // Website settings.
   Register(CONTENT_SETTINGS_TYPE_AUTO_SELECT_CERTIFICATE,
            "auto-select-certificate", nullptr, WebsiteSettingsInfo::UNSYNCABLE,
-           WebsiteSettingsInfo::NOT_LOSSY);
+           WebsiteSettingsInfo::NOT_LOSSY,
+           WebsiteSettingsInfo::REQUESTING_DOMAIN_ONLY_SCOPE);
   Register(CONTENT_SETTINGS_TYPE_SSL_CERT_DECISIONS, "ssl-cert-decisions",
            nullptr, WebsiteSettingsInfo::UNSYNCABLE,
-           WebsiteSettingsInfo::NOT_LOSSY);
+           WebsiteSettingsInfo::NOT_LOSSY,
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE);
   Register(CONTENT_SETTINGS_TYPE_APP_BANNER, "app-banner", nullptr,
-           WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY);
+           WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+           WebsiteSettingsInfo::REQUESTING_DOMAIN_ONLY_SCOPE);
   Register(CONTENT_SETTINGS_TYPE_SITE_ENGAGEMENT, "site-engagement", nullptr,
-           WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY);
+           WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::LOSSY,
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_ONLY_SCOPE);
   Register(CONTENT_SETTINGS_TYPE_USB_CHOOSER_DATA, "usb-chooser-data", nullptr,
-           WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY);
+           WebsiteSettingsInfo::UNSYNCABLE, WebsiteSettingsInfo::NOT_LOSSY,
+           WebsiteSettingsInfo::REQUESTING_ORIGIN_AND_TOP_LEVEL_ORIGIN_SCOPE);
 }
 
 }  // namespace content_settings
diff --git a/components/content_settings/core/browser/website_settings_registry.h b/components/content_settings/core/browser/website_settings_registry.h
index 7d9ed4c..8cafcbb 100644
--- a/components/content_settings/core/browser/website_settings_registry.h
+++ b/components/content_settings/core/browser/website_settings_registry.h
@@ -46,7 +46,8 @@
       const std::string& name,
       scoped_ptr<base::Value> initial_default_value,
       WebsiteSettingsInfo::SyncStatus sync_status,
-      WebsiteSettingsInfo::LossyStatus lossy_status);
+      WebsiteSettingsInfo::LossyStatus lossy_status,
+      WebsiteSettingsInfo::ScopingType scoping_type);
 
   const_iterator begin() const;
   const_iterator end() const;
diff --git a/components/content_settings/core/browser/website_settings_registry_unittest.cc b/components/content_settings/core/browser/website_settings_registry_unittest.cc
index 73f12294..c476859 100644
--- a/components/content_settings/core/browser/website_settings_registry_unittest.cc
+++ b/components/content_settings/core/browser/website_settings_registry_unittest.cc
@@ -45,7 +45,8 @@
   // Register a new setting.
   registry()->Register(static_cast<ContentSettingsType>(10), "test", nullptr,
                        WebsiteSettingsInfo::UNSYNCABLE,
-                       WebsiteSettingsInfo::LOSSY);
+                       WebsiteSettingsInfo::LOSSY,
+                       WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
   info = registry()->GetByName("test");
   ASSERT_TRUE(info);
   EXPECT_EQ(10, info->type());
@@ -69,7 +70,8 @@
   registry()->Register(static_cast<ContentSettingsType>(10), "test",
                        make_scoped_ptr(new base::FundamentalValue(999)),
                        WebsiteSettingsInfo::SYNCABLE,
-                       WebsiteSettingsInfo::LOSSY);
+                       WebsiteSettingsInfo::LOSSY,
+                       WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
   info = registry()->Get(static_cast<ContentSettingsType>(10));
   ASSERT_TRUE(info);
   EXPECT_EQ("profile.content_settings.exceptions.test", info->pref_name());
@@ -81,13 +83,16 @@
   EXPECT_EQ(PrefRegistry::LOSSY_PREF |
                 user_prefs::PrefRegistrySyncable::SYNCABLE_PREF,
             info->GetPrefRegistrationFlags());
+  EXPECT_EQ(WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE,
+            info->scoping_type());
 }
 
 TEST_F(WebsiteSettingsRegistryTest, Iteration) {
   registry()->Register(static_cast<ContentSettingsType>(10), "test",
                        make_scoped_ptr(new base::FundamentalValue(999)),
                        WebsiteSettingsInfo::SYNCABLE,
-                       WebsiteSettingsInfo::LOSSY);
+                       WebsiteSettingsInfo::LOSSY,
+                       WebsiteSettingsInfo::TOP_LEVEL_DOMAIN_ONLY_SCOPE);
 
   bool found = false;
   for (const WebsiteSettingsInfo* info : *registry()) {
diff --git a/components/history/core/browser/history_backend.cc b/components/history/core/browser/history_backend.cc
index 542e952..3347cbb 100644
--- a/components/history/core/browser/history_backend.cc
+++ b/components/history/core/browser/history_backend.cc
@@ -424,6 +424,29 @@
   return top_hosts;
 }
 
+OriginCountMap HistoryBackend::GetCountsForOrigins(
+    const std::set<GURL>& origins) const {
+  if (!db_)
+    return OriginCountMap();
+
+  URLDatabase::URLEnumerator it;
+  if (!db_->InitURLEnumeratorForEverything(&it))
+    return OriginCountMap();
+
+  OriginCountMap origin_count_map;
+  for (const GURL& origin : origins)
+    origin_count_map[origin] = 0;
+
+  URLRow row;
+  while (it.GetNextURL(&row)) {
+    GURL origin = row.url().GetOrigin();
+    if (ContainsValue(origins, origin))
+      ++origin_count_map[origin];
+  }
+
+  return origin_count_map;
+}
+
 int HistoryBackend::HostRankIfAvailable(const GURL& url) const {
   auto it = host_ranks_.find(HostForTopHosts(url));
   return it != host_ranks_.end() ? it->second : kMaxTopHosts;
diff --git a/components/history/core/browser/history_backend.h b/components/history/core/browser/history_backend.h
index 71f3eb3..cd15078 100644
--- a/components/history/core/browser/history_backend.h
+++ b/components/history/core/browser/history_backend.h
@@ -212,6 +212,12 @@
   // generating internal metrics.
   TopHostsList TopHosts(int num_hosts) const;
 
+  // Gets the counts of URLs that belong to |origins| in the history database.
+  // Origins that are not in the history database will be in the map with a
+  // count of 0.
+  // Returns an empty map if db_ is not initialized.
+  OriginCountMap GetCountsForOrigins(const std::set<GURL>& origins) const;
+
   // Returns, for the given URL, a 0-based index into the list produced by
   // TopHosts(), corresponding to that URL's host. If TopHosts() has not
   // previously been run, or the host is not in the top kMaxTopHosts, returns
@@ -558,6 +564,7 @@
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, TopHosts_IgnoreUnusualURLs);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, HostRankIfAvailable);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, RecordTopHostsMetrics);
+  FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, GetCountsForOrigins);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, UpdateVisitDuration);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, ExpireHistoryForTimes);
   FRIEND_TEST_ALL_PREFIXES(HistoryBackendTest, DeleteFTSIndexDatabases);
diff --git a/components/history/core/browser/history_backend_unittest.cc b/components/history/core/browser/history_backend_unittest.cc
index eb7f16c..6f911ef 100644
--- a/components/history/core/browser/history_backend_unittest.cc
+++ b/components/history/core/browser/history_backend_unittest.cc
@@ -3316,6 +3316,35 @@
               ElementsAre(base::Bucket(1, 1), base::Bucket(51, 1)));
 }
 
+TEST_F(HistoryBackendTest, GetCountsForOrigins) {
+  std::vector<GURL> urls;
+  urls.push_back(GURL("http://cnn.com/us"));
+  urls.push_back(GURL("http://cnn.com/intl"));
+  urls.push_back(GURL("https://cnn.com/intl"));
+  urls.push_back(GURL("http://cnn.com:8080/path"));
+  urls.push_back(GURL("http://dogtopia.com/pups?q=poods"));
+  for (const GURL& url : urls) {
+    backend_->AddPageVisit(url, base::Time::Now(), 0, ui::PAGE_TRANSITION_LINK,
+                           history::SOURCE_BROWSED);
+  }
+
+  std::set<GURL> origins;
+  origins.insert(GURL("http://cnn.com/"));
+  EXPECT_THAT(backend_->GetCountsForOrigins(origins),
+              ElementsAre(std::make_pair(GURL("http://cnn.com/"), 2)));
+
+  origins.insert(GURL("http://dogtopia.com/"));
+  origins.insert(GURL("http://cnn.com:8080/"));
+  origins.insert(GURL("https://cnn.com/"));
+  origins.insert(GURL("http://notpresent.com/"));
+  EXPECT_THAT(backend_->GetCountsForOrigins(origins),
+              ElementsAre(std::make_pair(GURL("http://cnn.com/"), 2),
+                          std::make_pair(GURL("http://cnn.com:8080/"), 1),
+                          std::make_pair(GURL("http://dogtopia.com/"), 1),
+                          std::make_pair(GURL("http://notpresent.com/"), 0),
+                          std::make_pair(GURL("https://cnn.com/"), 1)));
+}
+
 TEST_F(HistoryBackendTest, UpdateVisitDuration) {
   // This unit test will test adding and deleting visit details information.
   ASSERT_TRUE(backend_.get());
diff --git a/components/history/core/browser/history_service.cc b/components/history/core/browser/history_service.cc
index f72305a..00ef0ac 100644
--- a/components/history/core/browser/history_service.cc
+++ b/components/history/core/browser/history_service.cc
@@ -367,6 +367,17 @@
       callback);
 }
 
+void HistoryService::GetCountsForOrigins(
+    const std::set<GURL>& origins,
+    const GetCountsForOriginsCallback& callback) const {
+  DCHECK(thread_) << "History service being called after cleanup";
+  DCHECK(thread_checker_.CalledOnValidThread());
+  PostTaskAndReplyWithResult(thread_->task_runner().get(), FROM_HERE,
+                             base::Bind(&HistoryBackend::GetCountsForOrigins,
+                                        history_backend_.get(), origins),
+                             callback);
+}
+
 void HistoryService::HostRankIfAvailable(
     const GURL& url,
     const base::Callback<void(int)>& callback) const {
diff --git a/components/history/core/browser/history_service.h b/components/history/core/browser/history_service.h
index 94fafaa8..577666e 100644
--- a/components/history/core/browser/history_service.h
+++ b/components/history/core/browser/history_service.h
@@ -151,6 +151,10 @@
   // KeyedService:
   void Shutdown() override;
 
+  // Callback for value asynchronously returned by GetCountsForOrigins().
+  typedef base::Callback<void(const OriginCountMap&)>
+      GetCountsForOriginsCallback;
+
   // Computes the |num_hosts| most-visited hostnames in the past 30 days and
   // returns a list of those hosts paired with their visit counts. The following
   // caveats apply:
@@ -165,6 +169,10 @@
   // Note: Virtual needed for mocking.
   virtual void TopHosts(int num_hosts, const TopHostsCallback& callback) const;
 
+  // Gets the counts of URLs that belong to |origins| in the history database.
+  void GetCountsForOrigins(const std::set<GURL>& origins,
+                           const GetCountsForOriginsCallback& callback) const;
+
   // Returns, for the given URL, a 0-based index into the list produced by
   // TopHosts(), corresponding to that URL's host. If TopHosts() has not
   // previously been run, or the host is not in the top kMaxTopHosts, returns
@@ -592,7 +600,7 @@
 
   // Called by the HistoryURLProvider class to schedule an autocomplete, it
   // will be called back on the internal history thread with the history
-  // database so it can query. See history_autocomplete.cc for a diagram.
+  // database so it can query. See history_url_provider.h for a diagram.
   void ScheduleAutocomplete(
       const base::Callback<void(HistoryBackend*, URLDatabase*)>& callback);
 
diff --git a/components/history/core/browser/history_types.h b/components/history/core/browser/history_types.h
index bc3d215..ea8b7ec1 100644
--- a/components/history/core/browser/history_types.h
+++ b/components/history/core/browser/history_types.h
@@ -452,6 +452,9 @@
 // Map from host to visit count, sorted by visit count descending.
 typedef std::vector<std::pair<std::string, int>> TopHostsList;
 
+// Map from origins to a count of matching URLs.
+typedef std::map<GURL, int> OriginCountMap;
+
 // Statistics -----------------------------------------------------------------
 
 // HistoryCountResult encapsulates the result of a call to
diff --git a/components/mus/example/mock_sysui/BUILD.gn b/components/mus/example/mock_sysui/BUILD.gn
index 1cb05f223..ba489bb 100644
--- a/components/mus/example/mock_sysui/BUILD.gn
+++ b/components/mus/example/mock_sysui/BUILD.gn
@@ -23,7 +23,7 @@
     "//mojo/converters/network",
     "//skia",
     "//ui/views",
-    "//ui/views/mus",
+    "//ui/views/mus:for_mojo_application",
   ]
 
   resources = [ "$root_out_dir/views_mus_resources.pak" ]
diff --git a/components/mus/example/views_examples/BUILD.gn b/components/mus/example/views_examples/BUILD.gn
index ecc10f1..1ca37c9 100644
--- a/components/mus/example/views_examples/BUILD.gn
+++ b/components/mus/example/views_examples/BUILD.gn
@@ -29,7 +29,7 @@
     "//ui/gfx/geometry",
     "//ui/views",
     "//ui/views/examples:views_examples_lib",
-    "//ui/views/mus",
+    "//ui/views/mus:for_mojo_application",
   ]
 
   resources = [ "$root_out_dir/views_mus_resources.pak" ]
diff --git a/components/mus/example/window_type_launcher/BUILD.gn b/components/mus/example/window_type_launcher/BUILD.gn
index 95a6b0c0..5caa465 100644
--- a/components/mus/example/window_type_launcher/BUILD.gn
+++ b/components/mus/example/window_type_launcher/BUILD.gn
@@ -37,7 +37,7 @@
     "//ui/gfx",
     "//ui/gfx/geometry",
     "//ui/views",
-    "//ui/views/mus",
+    "//ui/views/mus:for_shared_library",
   ]
 
   data_deps = [
diff --git a/components/mus/example/wm/BUILD.gn b/components/mus/example/wm/BUILD.gn
index ec214f1..5c69574 100644
--- a/components/mus/example/wm/BUILD.gn
+++ b/components/mus/example/wm/BUILD.gn
@@ -50,7 +50,7 @@
     "//skia",
     "//ui/mojo/init",
     "//ui/views",
-    "//ui/views/mus",
+    "//ui/views/mus:for_mojo_application",
   ]
 }
 
diff --git a/components/mus/gles2/command_buffer_local.cc b/components/mus/gles2/command_buffer_local.cc
index 461262b..9018c56e 100644
--- a/components/mus/gles2/command_buffer_local.cc
+++ b/components/mus/gles2/command_buffer_local.cc
@@ -202,12 +202,6 @@
   NOTIMPLEMENTED();
 }
 
-uint32_t CommandBufferLocal::CreateStreamTexture(uint32_t texture_id) {
-  // TODO(piman)
-  NOTIMPLEMENTED();
-  return 0;
-}
-
 void CommandBufferLocal::SetLock(base::Lock* lock) {
   NOTIMPLEMENTED();
 }
diff --git a/components/mus/gles2/command_buffer_local.h b/components/mus/gles2/command_buffer_local.h
index 02ed8ea..c9c0dd9 100644
--- a/components/mus/gles2/command_buffer_local.h
+++ b/components/mus/gles2/command_buffer_local.h
@@ -68,7 +68,6 @@
                        const base::Closure& callback) override;
   void SignalQuery(uint32 query, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
-  uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
diff --git a/components/mus/public/cpp/BUILD.gn b/components/mus/public/cpp/BUILD.gn
index dc8114a..926acb4 100644
--- a/components/mus/public/cpp/BUILD.gn
+++ b/components/mus/public/cpp/BUILD.gn
@@ -65,4 +65,8 @@
   data_deps = [
     "//components/mus",
   ]
+
+  if (is_component_build) {
+    deps += [ "//mojo/gles2" ]
+  }
 }
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.cc b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
index 7e753bca..7f304bb4 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.cc
@@ -82,8 +82,7 @@
 }
 
 void RecordInternalError(InternalErrorLoadEvent event) {
-  UMA_HISTOGRAM_ENUMERATION(
-      "PageLoad.Events.InternalError", event, ERR_LAST_ENTRY);
+  UMA_HISTOGRAM_ENUMERATION(kErrorEvents, event, ERR_LAST_ENTRY);
 }
 
 base::TimeDelta GetFirstContentfulPaint(const PageLoadTiming& timing) {
@@ -235,23 +234,18 @@
 
   if (!timing_.dom_content_loaded_event_start.is_zero()) {
     if (timing_.dom_content_loaded_event_start < background_delta) {
-      PAGE_LOAD_HISTOGRAM(
-          "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired",
-          timing_.dom_content_loaded_event_start);
+      PAGE_LOAD_HISTOGRAM(kHistogramDomContentLoaded,
+                          timing_.dom_content_loaded_event_start);
     } else {
-      PAGE_LOAD_HISTOGRAM(
-          "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.Background",
-          timing_.dom_content_loaded_event_start);
+      PAGE_LOAD_HISTOGRAM(kBackgroundHistogramDomContentLoaded,
+                          timing_.dom_content_loaded_event_start);
     }
   }
   if (!timing_.load_event_start.is_zero()) {
     if (timing_.load_event_start < background_delta) {
-      PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToLoadEventFired",
-                          timing_.load_event_start);
+      PAGE_LOAD_HISTOGRAM(kHistogramLoad, timing_.load_event_start);
     } else {
-      PAGE_LOAD_HISTOGRAM(
-          "PageLoad.Timing2.NavigationToLoadEventFired.Background",
-          timing_.load_event_start);
+      PAGE_LOAD_HISTOGRAM(kBackgroundHistogramLoad, timing_.load_event_start);
     }
   }
   if (timing_.first_layout.is_zero()) {
@@ -259,74 +253,65 @@
                          HasBackgrounded());
   } else {
     if (timing_.first_layout < background_delta) {
-      PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout",
-                          timing_.first_layout);
+      PAGE_LOAD_HISTOGRAM(kHistogramFirstLayout, timing_.first_layout);
       RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, false);
     } else {
-      PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstLayout.Background",
+      PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstLayout,
                           timing_.first_layout);
       RecordCommittedEvent(COMMITTED_LOAD_SUCCESSFUL_FIRST_LAYOUT, true);
     }
   }
   if (!timing_.first_paint.is_zero()) {
     if (timing_.first_paint < background_delta) {
-      PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstPaint",
-                          timing_.first_paint);
+      PAGE_LOAD_HISTOGRAM(kHistogramFirstPaint, timing_.first_paint);
     } else {
-      PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstPaint.Background",
-                          timing_.first_paint);
+      PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstPaint, timing_.first_paint);
     }
   }
   if (!timing_.first_text_paint.is_zero()) {
     if (timing_.first_text_paint < background_delta) {
-      PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstTextPaint",
-                          timing_.first_text_paint);
+      PAGE_LOAD_HISTOGRAM(kHistogramFirstTextPaint, timing_.first_text_paint);
     } else {
-      PAGE_LOAD_HISTOGRAM(
-          "PageLoad.Timing2.NavigationToFirstTextPaint.Background",
-          timing_.first_text_paint);
+      PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstTextPaint,
+                          timing_.first_text_paint);
     }
   }
   if (!timing_.first_image_paint.is_zero()) {
     if (timing_.first_image_paint < background_delta) {
-      PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstImagePaint",
-                          timing_.first_image_paint);
+      PAGE_LOAD_HISTOGRAM(kHistogramFirstImagePaint, timing_.first_image_paint);
     } else {
-      PAGE_LOAD_HISTOGRAM(
-          "PageLoad.Timing2.NavigationToFirstImagePaint.Background",
-          timing_.first_image_paint);
+      PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstImagePaint,
+                          timing_.first_image_paint);
     }
   }
   base::TimeDelta first_contentful_paint = GetFirstContentfulPaint(timing_);
   if (!first_contentful_paint.is_zero()) {
     if (first_contentful_paint < background_delta) {
-      PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstContentfulPaint",
+      PAGE_LOAD_HISTOGRAM(kHistogramFirstContentfulPaint,
                           first_contentful_paint);
     } else {
-      PAGE_LOAD_HISTOGRAM(
-          "PageLoad.Timing2.NavigationToFirstContentfulPaint.Background",
-          first_contentful_paint);
+      PAGE_LOAD_HISTOGRAM(kBackgroundHistogramFirstContentfulPaint,
+                          first_contentful_paint);
     }
   }
 
   // Log time to first foreground / time to first background. Log counts that we
   // started a relevant page load in the foreground / background.
   if (!background_time_.is_null()) {
-    PAGE_LOAD_HISTOGRAM("PageLoad.Timing2.NavigationToFirstBackground",
-                        background_delta);
+    PAGE_LOAD_HISTOGRAM(kHistogramFirstBackground, background_delta);
   } else if (!foreground_time_.is_null()) {
     PAGE_LOAD_HISTOGRAM(
-        "PageLoad.Timing2.NavigationToFirstForeground",
+        kHistogramFirstForeground,
         WallTimeFromTimeTicks(foreground_time_) - timing_.navigation_start);
   }
 }
 
 void PageLoadTracker::RecordProvisionalEvent(ProvisionalLoadEvent event) {
   if (HasBackgrounded()) {
-    UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Provisional.Background", event,
+    UMA_HISTOGRAM_ENUMERATION(kBackgroundProvisionalEvents, event,
                               PROVISIONAL_LOAD_LAST_ENTRY);
   } else {
-    UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Provisional", event,
+    UMA_HISTOGRAM_ENUMERATION(kProvisionalEvents, event,
                               PROVISIONAL_LOAD_LAST_ENTRY);
   }
 }
@@ -337,10 +322,10 @@
 void PageLoadTracker::RecordCommittedEvent(CommittedLoadEvent event,
                                            bool backgrounded) {
   if (backgrounded) {
-    UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Committed.Background", event,
+    UMA_HISTOGRAM_ENUMERATION(kBackgroundCommittedEvents, event,
                               COMMITTED_LOAD_LAST_ENTRY);
   } else {
-    UMA_HISTOGRAM_ENUMERATION("PageLoad.Events.Committed", event,
+    UMA_HISTOGRAM_ENUMERATION(kCommittedEvents, event,
                               COMMITTED_LOAD_LAST_ENTRY);
   }
 }
@@ -365,9 +350,8 @@
     // The IsSlow flag is just a one bit boolean if the first layout was > 10s.
     sample->SetFlagsField("IsSlow", first_contentful_paint.InSecondsF() >= 10,
                           1);
-    rappor_service->RecordSampleObj(
-        "PageLoad.CoarseTiming.NavigationToFirstContentfulPaint",
-        sample.Pass());
+    rappor_service->RecordSampleObj(kRapporMetricsNameCoarseTiming,
+                                     sample.Pass());
   }
 }
 
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer.h b/components/page_load_metrics/browser/metrics_web_contents_observer.h
index e6fd36e..3cc08830 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer.h
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer.h
@@ -34,26 +34,43 @@
 namespace page_load_metrics {
 
 // These constants are for keeping the tests in sync.
-const char kHistogramNameFirstLayout[] =
-    "PageLoad.Timing2.NavigationToFirstLayout";
-const char kHistogramNameFirstTextPaint[] =
+const char kHistogramFirstLayout[] = "PageLoad.Timing2.NavigationToFirstLayout";
+const char kHistogramFirstTextPaint[] =
     "PageLoad.Timing2.NavigationToFirstTextPaint";
-const char kHistogramNameDomContent[] =
+const char kHistogramDomContentLoaded[] =
     "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired";
-const char kHistogramNameLoad[] = "PageLoad.Timing2.NavigationToLoadEventFired";
-const char kBGHistogramNameFirstLayout[] =
+const char kHistogramLoad[] = "PageLoad.Timing2.NavigationToLoadEventFired";
+const char kHistogramFirstPaint[] = "PageLoad.Timing2.NavigationToFirstPaint";
+const char kHistogramFirstImagePaint[] =
+    "PageLoad.Timing2.NavigationToFirstImagePaint";
+const char kHistogramFirstContentfulPaint[] =
+    "PageLoad.Timing2.NavigationToFirstContentfulPaint";
+const char kBackgroundHistogramFirstLayout[] =
     "PageLoad.Timing2.NavigationToFirstLayout.Background";
-const char kBGHistogramNameFirstTextPaint[] =
+const char kBackgroundHistogramFirstTextPaint[] =
     "PageLoad.Timing2.NavigationToFirstTextPaint.Background";
-const char kBGHistogramNameDomContent[] =
+const char kBackgroundHistogramDomContentLoaded[] =
     "PageLoad.Timing2.NavigationToDOMContentLoadedEventFired.Background";
-const char kBGHistogramNameLoad[] =
+const char kBackgroundHistogramLoad[] =
     "PageLoad.Timing2.NavigationToLoadEventFired.Background";
+const char kBackgroundHistogramFirstPaint[] =
+    "PageLoad.Timing2.NavigationToFirstPaint.Background";
+const char kBackgroundHistogramFirstImagePaint[] =
+    "PageLoad.Timing2.NavigationToFirstImagePaint.Background.";
+const char kBackgroundHistogramFirstContentfulPaint[] =
+    "PageLoad.Timing2.NavigationToFirstContentfulPaint.Background";
+
+const char kHistogramFirstBackground[] =
+    "PageLoad.Timing2.NavigationToFirstBackground";
+const char kHistogramFirstForeground[] =
+    "PageLoad.Timing2.NavigationToFirstForeground";
 
 const char kProvisionalEvents[] = "PageLoad.Events.Provisional";
 const char kCommittedEvents[] = "PageLoad.Events.Committed";
-const char kBGProvisionalEvents[] = "PageLoad.Events.Provisional.Background";
-const char kBGCommittedEvents[] = "PageLoad.Events.Committed.Background";
+const char kBackgroundProvisionalEvents[] =
+    "PageLoad.Events.Provisional.Background";
+const char kBackgroundCommittedEvents[] =
+    "PageLoad.Events.Committed.Background";
 
 const char kErrorEvents[] = "PageLoad.Events.InternalError";
 
diff --git a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
index b3bad62..769c237 100644
--- a/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
+++ b/components/page_load_metrics/browser/metrics_web_contents_observer_unittest.cc
@@ -69,17 +69,18 @@
   }
 
   void AssertNoHistogramsLogged() {
-    histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 0);
-    histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 0);
-    histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 0);
-    histogram_tester_.ExpectTotalCount(kHistogramNameFirstTextPaint, 0);
+    histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
+    histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
+    histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0);
+    histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
   }
 
   void CheckProvisionalEvent(ProvisionalLoadEvent event,
                              int count,
                              bool background) {
     if (background) {
-      histogram_tester_.ExpectBucketCount(kBGProvisionalEvents, event, count);
+      histogram_tester_.ExpectBucketCount(kBackgroundProvisionalEvents, event,
+                                          count);
       num_provisional_events_bg_ += count;
     } else {
       histogram_tester_.ExpectBucketCount(kProvisionalEvents, event, count);
@@ -91,7 +92,8 @@
                            int count,
                            bool background) {
     if (background) {
-      histogram_tester_.ExpectBucketCount(kBGCommittedEvents, event, count);
+      histogram_tester_.ExpectBucketCount(kBackgroundCommittedEvents, event,
+                                          count);
       num_committed_events_bg_ += count;
     } else {
       histogram_tester_.ExpectBucketCount(kCommittedEvents, event, count);
@@ -108,9 +110,9 @@
     histogram_tester_.ExpectTotalCount(kProvisionalEvents,
                                        num_provisional_events_);
     histogram_tester_.ExpectTotalCount(kCommittedEvents, num_committed_events_);
-    histogram_tester_.ExpectTotalCount(kBGProvisionalEvents,
+    histogram_tester_.ExpectTotalCount(kBackgroundProvisionalEvents,
                                        num_provisional_events_bg_);
-    histogram_tester_.ExpectTotalCount(kBGCommittedEvents,
+    histogram_tester_.ExpectTotalCount(kBackgroundCommittedEvents,
                                        num_committed_events_bg_);
     histogram_tester_.ExpectTotalCount(kErrorEvents, num_errors_);
   }
@@ -204,12 +206,12 @@
   // But we should keep the timing info and log it when we get another
   // navigation.
   web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 1);
-  histogram_tester_.ExpectBucketCount(kHistogramNameFirstLayout,
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
+  histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
                                       first_layout.InMilliseconds(), 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstTextPaint, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
 }
 
 TEST_F(MetricsWebContentsObserverTest, SingleMetricAfterCommit) {
@@ -232,12 +234,12 @@
   // Navigate again to force histogram recording.
   web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 1);
-  histogram_tester_.ExpectBucketCount(kHistogramNameFirstLayout,
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
+  histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
                                       first_layout.InMilliseconds(), 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstTextPaint, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
 }
 
 TEST_F(MetricsWebContentsObserverTest, MultipleMetricsAfterCommits) {
@@ -276,25 +278,24 @@
 
   web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
 
-  histogram_tester_.ExpectBucketCount(kHistogramNameFirstLayout,
+  histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
                                       first_layout_1.InMilliseconds(), 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 2);
-  histogram_tester_.ExpectBucketCount(kHistogramNameFirstLayout,
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 2);
+  histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
                                       first_layout_1.InMilliseconds(), 1);
-  histogram_tester_.ExpectBucketCount(kHistogramNameFirstLayout,
+  histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
                                       first_layout_2.InMilliseconds(), 1);
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstTextPaint, 1);
-  histogram_tester_.ExpectBucketCount(kHistogramNameFirstTextPaint,
+  histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 1);
+  histogram_tester_.ExpectBucketCount(kHistogramFirstTextPaint,
                                       first_text_paint.InMilliseconds(), 1);
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 1);
-  histogram_tester_.ExpectBucketCount(kHistogramNameDomContent,
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
+  histogram_tester_.ExpectBucketCount(kHistogramDomContentLoaded,
                                       dom_content.InMilliseconds(), 1);
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 1);
-  histogram_tester_.ExpectBucketCount(kHistogramNameLoad, load.InMilliseconds(),
-                                      1);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 1);
+  histogram_tester_.ExpectBucketCount(kHistogramLoad, load.InMilliseconds(), 1);
 }
 
 TEST_F(MetricsWebContentsObserverTest, BackgroundDifferentHistogram) {
@@ -323,17 +324,17 @@
   // Navigate again to force histogram recording.
   web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
 
-  histogram_tester_.ExpectTotalCount(kBGHistogramNameDomContent, 0);
-  histogram_tester_.ExpectTotalCount(kBGHistogramNameLoad, 0);
-  histogram_tester_.ExpectTotalCount(kBGHistogramNameFirstLayout, 1);
-  histogram_tester_.ExpectBucketCount(kBGHistogramNameFirstLayout,
+  histogram_tester_.ExpectTotalCount(kBackgroundHistogramDomContentLoaded, 0);
+  histogram_tester_.ExpectTotalCount(kBackgroundHistogramLoad, 0);
+  histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstLayout, 1);
+  histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstLayout,
                                       first_layout.InMilliseconds(), 1);
-  histogram_tester_.ExpectTotalCount(kBGHistogramNameFirstTextPaint, 0);
+  histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstTextPaint, 0);
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstTextPaint, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
 }
 
 TEST_F(MetricsWebContentsObserverTest, DontLogPrerender) {
@@ -381,23 +382,23 @@
   // Navigate again to force histogram recording.
   web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl2));
 
-  histogram_tester_.ExpectTotalCount(kBGHistogramNameDomContent, 0);
-  histogram_tester_.ExpectTotalCount(kBGHistogramNameLoad, 0);
-  histogram_tester_.ExpectTotalCount(kBGHistogramNameFirstLayout, 1);
-  histogram_tester_.ExpectBucketCount(kBGHistogramNameFirstLayout,
+  histogram_tester_.ExpectTotalCount(kBackgroundHistogramDomContentLoaded, 0);
+  histogram_tester_.ExpectTotalCount(kBackgroundHistogramLoad, 0);
+  histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstLayout, 1);
+  histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstLayout,
                                       timing.first_layout.InMilliseconds(), 1);
-  histogram_tester_.ExpectTotalCount(kBGHistogramNameFirstTextPaint, 1);
-  histogram_tester_.ExpectBucketCount(kBGHistogramNameFirstTextPaint,
+  histogram_tester_.ExpectTotalCount(kBackgroundHistogramFirstTextPaint, 1);
+  histogram_tester_.ExpectBucketCount(kBackgroundHistogramFirstTextPaint,
                                       timing.first_text_paint.InMilliseconds(),
                                       1);
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 1);
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 1);
   histogram_tester_.ExpectBucketCount(
-      kHistogramNameDomContent,
+      kHistogramDomContentLoaded,
       timing.dom_content_loaded_event_start.InMilliseconds(), 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstTextPaint, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
 }
 
 TEST_F(MetricsWebContentsObserverTest, DontBackgroundQuickerLoad) {
@@ -432,12 +433,12 @@
   // Navigate again to see if the timing updated for a subframe message.
   web_contents_tester->NavigateAndCommit(GURL(kDefaultTestUrl));
 
-  histogram_tester_.ExpectTotalCount(kHistogramNameDomContent, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameLoad, 0);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstLayout, 1);
-  histogram_tester_.ExpectBucketCount(kHistogramNameFirstLayout,
+  histogram_tester_.ExpectTotalCount(kHistogramDomContentLoaded, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramLoad, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstLayout, 1);
+  histogram_tester_.ExpectBucketCount(kHistogramFirstLayout,
                                       first_layout.InMilliseconds(), 1);
-  histogram_tester_.ExpectTotalCount(kHistogramNameFirstTextPaint, 0);
+  histogram_tester_.ExpectTotalCount(kHistogramFirstTextPaint, 0);
 }
 
 TEST_F(MetricsWebContentsObserverTest, FailProvisionalLoad) {
diff --git a/content/browser/BUILD.gn b/content/browser/BUILD.gn
index d97c5cb..9990e72 100644
--- a/content/browser/BUILD.gn
+++ b/content/browser/BUILD.gn
@@ -104,6 +104,8 @@
             ],
             ".")
 
+    defines += [ "MOJO_SHELL_CLIENT" ]
+
     # Non-iOS deps.
     deps += [
       "//cc",
@@ -417,6 +419,7 @@
       "//ui/aura",
       "//ui/aura_extra",
       "//ui/strings",
+      "//ui/views/mus:for_component",
       "//ui/wm",
     ]
   } else {  # Not aura.
diff --git a/content/browser/DEPS b/content/browser/DEPS
index d29e52f..298ec09 100644
--- a/content/browser/DEPS
+++ b/content/browser/DEPS
@@ -2,6 +2,7 @@
   # Allow inclusion of specific components that we depend on. We may only
   # depend on components which we share with the mojo html_viewer.
   "+components/mime_util",
+  "+components/mus/public/interfaces",
   "+components/scheduler/common",
   "+components/tracing",
   "+components/url_formatter",
@@ -20,6 +21,7 @@
   "+mojo",
   "+sql",
   "+ui/aura_extra",
+  "+ui/views/mus",  # http://crbug.com/555767
   "+ui/webui",
   "+win8/util",
 
diff --git a/content/browser/android/browser_jni_registrar.cc b/content/browser/android/browser_jni_registrar.cc
index 7e91117..4805d962 100644
--- a/content/browser/android/browser_jni_registrar.cc
+++ b/content/browser/android/browser_jni_registrar.cc
@@ -20,7 +20,6 @@
 #include "content/browser/accessibility/browser_accessibility_manager_android.h"
 #include "content/browser/android/background_sync_network_observer_android.h"
 #include "content/browser/android/composited_touch_handle_drawable.h"
-#include "content/browser/android/content_readback_handler.h"
 #include "content/browser/android/content_view_core_impl.h"
 #include "content/browser/android/content_view_render_view.h"
 #include "content/browser/android/content_view_statics.h"
@@ -66,8 +65,6 @@
     {"CardboardVRDevice",
      content::CardboardVRDevice::RegisterCardboardVRDevice},
 #endif
-    {"ContentReadbackHandler",
-     content::ContentReadbackHandler::RegisterContentReadbackHandler},
     {"ContentViewCore", content::RegisterContentViewCore},
     {"ContentViewRenderView",
      content::ContentViewRenderView::RegisterContentViewRenderView},
diff --git a/content/browser/android/content_readback_handler.cc b/content/browser/android/content_readback_handler.cc
deleted file mode 100644
index d1db971..0000000
--- a/content/browser/android/content_readback_handler.cc
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "content/browser/android/content_readback_handler.h"
-
-#include "base/android/jni_android.h"
-#include "base/bind.h"
-#include "cc/output/copy_output_request.h"
-#include "cc/output/copy_output_result.h"
-#include "content/browser/android/content_view_core_impl.h"
-#include "jni/ContentReadbackHandler_jni.h"
-#include "third_party/skia/include/core/SkBitmap.h"
-#include "ui/android/window_android.h"
-#include "ui/android/window_android_compositor.h"
-#include "ui/gfx/android/java_bitmap.h"
-#include "ui/gfx/geometry/rect.h"
-
-namespace content {
-
-// static
-bool ContentReadbackHandler::RegisterContentReadbackHandler(JNIEnv* env) {
-  return RegisterNativesImpl(env);
-}
-
-ContentReadbackHandler::ContentReadbackHandler(JNIEnv* env, jobject obj)
-    : weak_factory_(this) {
-  java_obj_.Reset(env, obj);
-}
-
-void ContentReadbackHandler::Destroy(JNIEnv* env, jobject obj) {
-  delete this;
-}
-
-void ContentReadbackHandler::GetContentBitmap(JNIEnv* env,
-                                              jobject obj,
-                                              jint readback_id,
-                                              jfloat scale,
-                                              jobject color_type,
-                                              jfloat x,
-                                              jfloat y,
-                                              jfloat width,
-                                              jfloat height,
-                                              jobject content_view_core) {
-  ContentViewCore* view =
-      ContentViewCore::GetNativeContentViewCore(env, content_view_core);
-  DCHECK(view);
-
-  const ReadbackRequestCallback result_callback =
-      base::Bind(&ContentReadbackHandler::OnFinishReadback,
-                 weak_factory_.GetWeakPtr(),
-                 readback_id);
-
-  SkColorType sk_color_type = gfx::ConvertToSkiaColorType(color_type);
-  view->GetScaledContentBitmap(
-      scale, sk_color_type, gfx::Rect(x, y, width, height), result_callback);
-}
-
-ContentReadbackHandler::~ContentReadbackHandler() {}
-
-void ContentReadbackHandler::OnFinishReadback(int readback_id,
-                                              const SkBitmap& bitmap,
-                                              ReadbackResponse response) {
-  JNIEnv* env = base::android::AttachCurrentThread();
-  ScopedJavaLocalRef<jobject> java_bitmap;
-  if (response == READBACK_SUCCESS)
-    java_bitmap = gfx::ConvertToJavaBitmap(&bitmap);
-
-  Java_ContentReadbackHandler_notifyGetBitmapFinished(
-      env, java_obj_.obj(), readback_id, java_bitmap.obj(), response);
-}
-
-// static
-static jlong Init(JNIEnv* env, const JavaParamRef<jobject>& obj) {
-  ContentReadbackHandler* content_readback_handler =
-      new ContentReadbackHandler(env, obj);
-  return reinterpret_cast<intptr_t>(content_readback_handler);
-}
-
-}  // namespace content
diff --git a/content/browser/android/content_readback_handler.h b/content/browser/android/content_readback_handler.h
deleted file mode 100644
index 44d2a3d..0000000
--- a/content/browser/android/content_readback_handler.h
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CONTENT_BROWSER_ANDROID_CONTENT_READBACK_HANDLER_H_
-#define CONTENT_BROWSER_ANDROID_CONTENT_READBACK_HANDLER_H_
-
-#include <jni.h>
-
-#include "base/android/jni_weak_ref.h"
-#include "base/callback.h"
-#include "base/memory/weak_ptr.h"
-#include "content/public/browser/readback_types.h"
-
-class SkBitmap;
-
-namespace cc {
-class CopyOutputResult;
-}
-
-namespace content {
-
-// Native side of the ContentReadbackHandler.java, which issues content
-// readbacks from the Java side.
-class ContentReadbackHandler {
- public:
-  // Registers the JNI methods for ContentViewRender.
-  static bool RegisterContentReadbackHandler(JNIEnv* env);
-
-  // Methods called from Java via JNI -----------------------------------------
-  ContentReadbackHandler(JNIEnv* env, jobject obj);
-  void Destroy(JNIEnv* env, jobject obj);
-  void GetContentBitmap(JNIEnv* env,
-                        jobject obj,
-                        jint readback_id,
-                        jfloat scale,
-                        jobject config,
-                        jfloat x,
-                        jfloat y,
-                        jfloat width,
-                        jfloat height,
-                        jobject content_view_core);
-
- private:
-  virtual ~ContentReadbackHandler();
-
-  void OnFinishReadback(int readback_id,
-                        const SkBitmap& bitmap,
-                        ReadbackResponse response);
-
-  base::android::ScopedJavaGlobalRef<jobject> java_obj_;
-  base::WeakPtrFactory<ContentReadbackHandler> weak_factory_;
-
-  DISALLOW_COPY_AND_ASSIGN(ContentReadbackHandler);
-};
-
-}  // namespace content
-
-#endif  // CONTENT_BROWSER_ANDROID_CONTENT_READBACK_HANDLER_H_
diff --git a/content/browser/android/in_process/synchronous_compositor_factory_impl.cc b/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
index 5cbb319..7f5808da 100644
--- a/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
+++ b/content/browser/android/in_process/synchronous_compositor_factory_impl.cc
@@ -98,6 +98,10 @@
     return gl_in_process_context_->GetSurfaceTexture(stream_id);
   }
 
+  uint32 CreateStreamTexture(uint32 texture_id) override {
+    return gl_in_process_context_->CreateStreamTexture(texture_id);
+  }
+
   gpu::gles2::GLES2Interface* ContextGL() override {
     return context_provider_->ContextGL();
   }
diff --git a/content/browser/browser_main_loop.cc b/content/browser/browser_main_loop.cc
index 8566b99..0747cdb 100644
--- a/content/browser/browser_main_loop.cc
+++ b/content/browser/browser_main_loop.cc
@@ -170,6 +170,14 @@
 #include "crypto/nss_util.h"
 #endif
 
+#if defined(MOJO_SHELL_CLIENT)
+#include "components/mus/public/interfaces/window_manager.mojom.h"
+#include "content/common/mojo/mojo_shell_connection_impl.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/converters/network/network_type_converters.h"
+#include "ui/views/mus/window_manager_connection.h"
+#endif
+
 // One of the linux specific headers defines this as a macro.
 #ifdef DestroyAll
 #undef DestroyAll
@@ -903,6 +911,21 @@
 }
 
 int BrowserMainLoop::PreMainMessageLoopRun() {
+#if defined(MOJO_SHELL_CLIENT)
+  if (IsRunningInMojoShell()) {
+    MojoShellConnectionImpl::Create();
+#if defined(USE_AURA)
+    mus::mojom::WindowManagerPtr window_manager;
+    mojo::ApplicationImpl* application =
+        MojoShellConnection::Get()->GetApplication();
+    application->ConnectToService(
+        mojo::URLRequest::From(std::string("mojo:example_wm")),
+        &window_manager);
+    views::WindowManagerConnection::Create(window_manager.Pass(), application);
+#endif
+  }
+#endif
+
   if (parts_) {
     TRACE_EVENT0("startup",
         "BrowserMainLoop::CreateThreads:PreMainMessageLoopRun");
@@ -949,6 +972,9 @@
       base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
                  true));
 
+#if defined(MOJO_SHELL_CLIENT)
+  MojoShellConnection::Destroy();
+#endif
   mojo_ipc_support_.reset();
   mojo_shell_context_.reset();
 
diff --git a/content/browser/child_process_launcher.cc b/content/browser/child_process_launcher.cc
index 53d21fdb..830d5b93 100644
--- a/content/browser/child_process_launcher.cc
+++ b/content/browser/child_process_launcher.cc
@@ -13,6 +13,7 @@
 #include "base/metrics/histogram.h"
 #include "base/process/process.h"
 #include "base/profiler/scoped_tracker.h"
+#include "base/strings/string_number_conversions.h"
 #include "base/synchronization/lock.h"
 #include "base/threading/thread.h"
 #include "content/public/browser/content_browser_client.h"
@@ -47,6 +48,17 @@
 #include "gin/v8_initializer.h"
 #endif
 
+#if defined(MOJO_SHELL_CLIENT)
+#include "base/thread_task_runner_handle.h"
+#include "content/public/common/mojo_shell_connection.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/converters/network/network_type_converters.h"
+#include "mojo/shell/application_manager.mojom.h"
+#include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
+#include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
+#include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
+#endif
+
 namespace content {
 
 namespace {
@@ -321,7 +333,11 @@
 #endif
 }
 
-}  // anonymous namespace
+#if defined(MOJO_SHELL_CLIENT)
+void DidCreateChannel(mojo::embedder::ChannelInfo* info) {}
+#endif
+
+}  // namespace
 
 ChildProcessLauncher::ChildProcessLauncher(
     SandboxedProcessLauncherDelegate* delegate,
@@ -364,6 +380,10 @@
     int child_process_id) {
   DCHECK(CalledOnValidThread());
 
+#if defined(MOJO_SHELL_CLIENT)
+  CreateMojoShellChannel(cmd_line, child_process_id);
+#endif
+
 #if defined(OS_ANDROID)
   // Android only supports renderer, sandboxed utility and gpu.
   std::string process_type =
@@ -503,6 +523,46 @@
   }
 }
 
+#if defined(MOJO_SHELL_CLIENT)
+void ChildProcessLauncher::CreateMojoShellChannel(
+    base::CommandLine* command_line,
+    int child_process_id) {
+  // Some process types get created before the main message loop.
+  if (!MojoShellConnection::Get())
+    return;
+
+  // Create the channel to be shared with the target process.
+  mojo::embedder::HandlePassingInformation handle_passing_info;
+  mojo::embedder::PlatformChannelPair platform_channel_pair;
+
+  // Give one end to the shell so that it can create an instance.
+  mojo::embedder::ScopedPlatformHandle platform_channel =
+      platform_channel_pair.PassServerHandle();
+  mojo::ScopedMessagePipeHandle handle(mojo::embedder::CreateChannel(
+      platform_channel.Pass(), base::Bind(&DidCreateChannel),
+      base::ThreadTaskRunnerHandle::Get()));
+  mojo::shell::mojom::ApplicationManagerPtr application_manager;
+  MojoShellConnection::Get()->GetApplication()->ConnectToService(
+      mojo::URLRequest::From(std::string("mojo:shell")),
+      &application_manager);
+  // The content of the URL/qualifier we pass is actually meaningless, it's only
+  // important that they're unique per process.
+  // TODO(beng): We need to specify a restrictive CapabilityFilter here that
+  //             matches the needs of the target process. Figure out where that
+  //             specification is best determined (not here, this is a common
+  //             chokepoint for all process types) and how to wire it through.
+  //             http://crbug.com/555393
+  application_manager->CreateInstanceForHandle(
+      mojo::ScopedHandle(mojo::Handle(handle.release().value())),
+      "exe:chrome_renderer",  // See above about how this string is meaningless.
+      base::IntToString(child_process_id));
+
+  // Put the other end on the command line used to launch the target.
+  platform_channel_pair.PrepareToPassClientHandleToChildProcess(
+      command_line, &handle_passing_info);
+}
+#endif  // defined(MOJO_SHELL_CLIENT)
+
 bool ChildProcessLauncher::IsStarting() {
   // TODO(crbug.com/469248): This fails in some tests.
   // DCHECK(CalledOnValidThread());
diff --git a/content/browser/child_process_launcher.h b/content/browser/child_process_launcher.h
index 2d647f40..768367d 100644
--- a/content/browser/child_process_launcher.h
+++ b/content/browser/child_process_launcher.h
@@ -107,6 +107,15 @@
 #endif
               base::Process process);
 
+#if defined(MOJO_SHELL_CLIENT)
+  // When this process is run from an external Mojo shell, this function will
+  // create a channel and pass one end to the spawned process and register the
+  // other end with the external shell, allowing the spawned process to bind an
+  // Application request from the shell.
+  void CreateMojoShellChannel(base::CommandLine* command_line,
+                              int child_process_id);
+#endif
+
   Client* client_;
   BrowserThread::ID client_thread_id_;
   base::Process process_;
diff --git a/content/browser/fileapi/dragged_file_util_unittest.cc b/content/browser/fileapi/dragged_file_util_unittest.cc
index 38d8337..398ce6d 100644
--- a/content/browser/fileapi/dragged_file_util_unittest.cc
+++ b/content/browser/fileapi/dragged_file_util_unittest.cc
@@ -374,8 +374,6 @@
       storage::DirectoryEntry entry;
       entry.is_directory = file_info.IsDirectory();
       entry.name = current.BaseName().value();
-      entry.size = file_info.GetSize();
-      entry.last_modified_time = file_info.GetLastModifiedTime();
       expected_entry_map[entry.name] = entry;
 
 #if defined(OS_POSIX)
@@ -403,9 +401,6 @@
       EXPECT_TRUE(found != expected_entry_map.end());
       EXPECT_EQ(found->second.name, entry.name);
       EXPECT_EQ(found->second.is_directory, entry.is_directory);
-      EXPECT_EQ(found->second.size, entry.size);
-      EXPECT_EQ(found->second.last_modified_time.ToDoubleT(),
-                entry.last_modified_time.ToDoubleT());
     }
   }
 }
diff --git a/content/browser/web_contents/web_contents_android.cc b/content/browser/web_contents/web_contents_android.cc
index 7ef1ffd..1da0efe 100644
--- a/content/browser/web_contents/web_contents_android.cc
+++ b/content/browser/web_contents/web_contents_android.cc
@@ -35,12 +35,15 @@
 #include "net/android/network_library.h"
 #include "ui/accessibility/ax_node_data.h"
 #include "ui/gfx/android/device_display_info.h"
+#include "ui/gfx/android/java_bitmap.h"
+#include "ui/gfx/geometry/rect.h"
 
 using base::android::AttachCurrentThread;
 using base::android::ConvertJavaStringToUTF8;
 using base::android::ConvertJavaStringToUTF16;
 using base::android::ConvertUTF8ToJavaString;
 using base::android::ConvertUTF16ToJavaString;
+using base::android::JavaParamRef;
 using base::android::ScopedJavaGlobalRef;
 using base::android::ToJavaIntArray;
 
@@ -560,4 +563,50 @@
                                                 web_contents_->GetEncoding());
 }
 
+void WebContentsAndroid::GetContentBitmap(
+    JNIEnv* env,
+    const JavaParamRef<jobject>& obj,
+    const JavaParamRef<jobject>& jcallback,
+    const JavaParamRef<jobject>& color_type,
+    jfloat scale,
+    jfloat x,
+    jfloat y,
+    jfloat width,
+    jfloat height) {
+  RenderWidgetHostViewAndroid* view = GetRenderWidgetHostViewAndroid();
+  const ReadbackRequestCallback result_callback =
+      base::Bind(&WebContentsAndroid::OnFinishGetContentBitmap,
+                 weak_factory_.GetWeakPtr(),
+                 base::Owned(new ScopedJavaGlobalRef<jobject>(env, obj)),
+                 base::Owned(new ScopedJavaGlobalRef<jobject>(env, jcallback)));
+  SkColorType pref_color_type = gfx::ConvertToSkiaColorType(color_type.obj());
+  if (!view || pref_color_type == kUnknown_SkColorType) {
+    result_callback.Run(SkBitmap(), READBACK_FAILED);
+    return;
+  }
+  if (!view->IsSurfaceAvailableForCopy()) {
+    result_callback.Run(SkBitmap(), READBACK_SURFACE_UNAVAILABLE);
+    return;
+  }
+  view->GetScaledContentBitmap(scale,
+                               pref_color_type,
+                               gfx::Rect(x, y, width, height),
+                               result_callback);
+}
+
+void WebContentsAndroid::OnFinishGetContentBitmap(
+    ScopedJavaGlobalRef<jobject>* obj,
+    ScopedJavaGlobalRef<jobject>* callback,
+    const SkBitmap& bitmap,
+    ReadbackResponse response) {
+  JNIEnv* env = base::android::AttachCurrentThread();
+  ScopedJavaLocalRef<jobject> java_bitmap;
+  if (response == READBACK_SUCCESS)
+    java_bitmap = gfx::ConvertToJavaBitmap(&bitmap);
+  Java_WebContentsImpl_onGetContentBitmapFinished(env,
+                                                  obj->obj(),
+                                                  callback->obj(),
+                                                  java_bitmap.obj(),
+                                                  response);
+}
 }  // namespace content
diff --git a/content/browser/web_contents/web_contents_android.h b/content/browser/web_contents/web_contents_android.h
index a153b1f..7710bb2 100644
--- a/content/browser/web_contents/web_contents_android.h
+++ b/content/browser/web_contents/web_contents_android.h
@@ -7,6 +7,7 @@
 
 #include <jni.h>
 
+#include "base/android/jni_android.h"
 #include "base/android/scoped_java_ref.h"
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
@@ -122,6 +123,16 @@
   base::android::ScopedJavaLocalRef<jstring> GetEncoding(JNIEnv* env,
                                                          jobject obj) const;
 
+  // Relay the access from Java layer to GetScaledContentBitmap through JNI.
+  void GetContentBitmap(JNIEnv* env,
+                        const base::android::JavaParamRef<jobject>& obj,
+                        const base::android::JavaParamRef<jobject>& jcallback,
+                        const base::android::JavaParamRef<jobject>& color_type,
+                        jfloat scale,
+                        jfloat x,
+                        jfloat y,
+                        jfloat width,
+                        jfloat height);
   void set_synchronous_compositor_client(SynchronousCompositorClient* client) {
     synchronous_compositor_client_ = client;
   }
@@ -132,6 +143,12 @@
  private:
   RenderWidgetHostViewAndroid* GetRenderWidgetHostViewAndroid();
 
+  void OnFinishGetContentBitmap(
+      base::android::ScopedJavaGlobalRef<jobject>* obj,
+      base::android::ScopedJavaGlobalRef<jobject>* callback,
+      const SkBitmap& bitmap,
+      ReadbackResponse response);
+
   WebContents* web_contents_;
   NavigationControllerAndroid navigation_controller_;
   base::android::ScopedJavaGlobalRef<jobject> obj_;
diff --git a/content/common/BUILD.gn b/content/common/BUILD.gn
index 2b9778b..fbe711a 100644
--- a/content/common/BUILD.gn
+++ b/content/common/BUILD.gn
@@ -133,6 +133,13 @@
                         ".",
                         "//content")
 
+  # These files are only built in a GN build because they bring in
+  # dependencies that don't build with GYP.
+  sources += [
+    "mojo/mojo_shell_connection_impl.cc",
+    "mojo/mojo_shell_connection_impl.h",
+  ]
+
   configs += [
     "//content:content_implementation",
     "//build/config:precompiled_headers",
@@ -146,10 +153,14 @@
   deps = [
     "//base",
     "//build/util:webkit_version",
+    "//components/mus/public/interfaces",
     "//components/tracing",
     "//components/tracing:startup_tracing",
     "//gpu/command_buffer/client:gles2_interface",
     "//gpu/command_buffer/common:gles2_utils",
+    "//mojo/application/public/cpp",
+    "//mojo/converters/network",
+    "//mojo/runner/child:lib",
     "//net",
     "//skia",
     "//third_party/icu",
@@ -197,7 +208,7 @@
     ]
   }
 
-  defines = []
+  defines = [ "MOJO_SHELL_CLIENT" ]
   include_dirs = []
   libs = []
   ldflags = []
diff --git a/content/common/frame_messages.h b/content/common/frame_messages.h
index 8ea66254..a2766fd 100644
--- a/content/common/frame_messages.h
+++ b/content/common/frame_messages.h
@@ -761,7 +761,7 @@
 // Sent when the renderer starts a provisional load for a frame.
 IPC_MESSAGE_ROUTED2(FrameHostMsg_DidStartProvisionalLoad,
                     GURL /* url */,
-                    base::TimeTicks /* navigation_start */);
+                    base::TimeTicks /* navigation_start */)
 
 // Sent when the renderer fails a provisional load with an error.
 IPC_MESSAGE_ROUTED1(FrameHostMsg_DidFailProvisionalLoadWithError,
diff --git a/content/common/gpu/client/command_buffer_proxy_impl.h b/content/common/gpu/client/command_buffer_proxy_impl.h
index 5646cca..0adf9aa 100644
--- a/content/common/gpu/client/command_buffer_proxy_impl.h
+++ b/content/common/gpu/client/command_buffer_proxy_impl.h
@@ -119,7 +119,6 @@
                        const base::Closure& callback) override;
   void SignalQuery(uint32 query, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
-  uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock* lock) override;
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
@@ -170,6 +169,7 @@
   base::SharedMemoryHandle GetSharedStateHandle() const {
     return shared_state_shm_->handle();
   }
+  uint32 CreateStreamTexture(uint32 texture_id);
 
  private:
   typedef std::map<int32, scoped_refptr<gpu::Buffer> > TransferBufferMap;
diff --git a/content/common/mojo/DEPS b/content/common/mojo/DEPS
index c6b0111..a8c7fc4b 100644
--- a/content/common/mojo/DEPS
+++ b/content/common/mojo/DEPS
@@ -1,3 +1,6 @@
 include_rules = [
+  "+mojo/application/public/cpp",
   "+mojo/application/public/interfaces",
+  "+mojo/converters/network",
+  "+mojo/runner/child",
 ]
diff --git a/content/common/mojo/mojo_shell_connection_impl.cc b/content/common/mojo/mojo_shell_connection_impl.cc
new file mode 100644
index 0000000..5125df35
--- /dev/null
+++ b/content/common/mojo/mojo_shell_connection_impl.cc
@@ -0,0 +1,95 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "content/common/mojo/mojo_shell_connection_impl.h"
+
+#include "base/command_line.h"
+#include "base/lazy_instance.h"
+#include "base/threading/thread_local.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+#include "mojo/application/public/cpp/application_impl.h"
+#include "mojo/converters/network/network_type_converters.h"
+#include "mojo/runner/child/runner_connection.h"
+
+namespace content {
+namespace {
+using MojoShellConnectionPtr =
+    base::ThreadLocalPointer<MojoShellConnectionImpl>;
+
+// Env is thread local so that aura may be used on multiple threads.
+base::LazyInstance<MojoShellConnectionPtr>::Leaky lazy_tls_ptr =
+    LAZY_INSTANCE_INITIALIZER;
+
+}  // namespace
+
+bool IsRunningInMojoShell() {
+  return base::CommandLine::ForCurrentProcess()->HasSwitch(
+      "mojo-platform-channel-handle");
+}
+
+// static
+void MojoShellConnectionImpl::Create() {
+  DCHECK(IsRunningInMojoShell());
+  DCHECK(!lazy_tls_ptr.Pointer()->Get());
+  MojoShellConnectionImpl* connection = new MojoShellConnectionImpl;
+  lazy_tls_ptr.Pointer()->Set(connection);
+  connection->WaitForShell();
+}
+
+MojoShellConnectionImpl::MojoShellConnectionImpl() : initialized_(false) {}
+MojoShellConnectionImpl::~MojoShellConnectionImpl() {}
+
+void MojoShellConnectionImpl::WaitForShell() {
+  mojo::InterfaceRequest<mojo::Application> application_request;
+  runner_connection_.reset(
+      mojo::runner::RunnerConnection::ConnectToRunner(&application_request));
+  application_impl_.reset(new mojo::ApplicationImpl(
+      this, application_request.Pass()));
+  application_impl_->WaitForInitialize();
+}
+
+void MojoShellConnectionImpl::Initialize(mojo::ApplicationImpl* application) {
+  initialized_ = true;
+}
+
+bool MojoShellConnectionImpl::ConfigureIncomingConnection(
+    mojo::ApplicationConnection* connection) {
+  bool found = false;
+  for (auto listener : listeners_)
+    found |= listener->ConfigureIncomingConnection(connection);
+  return found;
+}
+
+mojo::ApplicationImpl* MojoShellConnectionImpl::GetApplication() {
+  DCHECK(initialized_);
+  return application_impl_.get();
+}
+
+void MojoShellConnectionImpl::AddListener(Listener* listener) {
+  DCHECK(std::find(listeners_.begin(), listeners_.end(), listener) ==
+         listeners_.end());
+  listeners_.push_back(listener);
+}
+
+void MojoShellConnectionImpl::RemoveListener(Listener* listener) {
+  auto it = std::find(listeners_.begin(), listeners_.end(), listener);
+  DCHECK(it != listeners_.end());
+  listeners_.erase(it);
+}
+
+// static
+MojoShellConnection* MojoShellConnection::Get() {
+  return lazy_tls_ptr.Pointer()->Get();
+}
+
+// static
+void MojoShellConnection::Destroy() {
+  // This joins the shell controller thread.
+  delete Get();
+  lazy_tls_ptr.Pointer()->Set(nullptr);
+}
+
+MojoShellConnection::~MojoShellConnection() {}
+
+}  // namespace content
diff --git a/content/common/mojo/mojo_shell_connection_impl.h b/content/common/mojo/mojo_shell_connection_impl.h
new file mode 100644
index 0000000..484e2ab7
--- /dev/null
+++ b/content/common/mojo/mojo_shell_connection_impl.h
@@ -0,0 +1,65 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_COMMON_MOJO_SHELL_CONNECTION_IMPL_H_
+#define CONTENT_COMMON_MOJO_SHELL_CONNECTION_IMPL_H_
+
+#include <vector>
+
+#include "base/macros.h"
+#include "base/memory/scoped_ptr.h"
+#include "content/public/common/mojo_shell_connection.h"
+#include "mojo/application/public/cpp/application_delegate.h"
+
+namespace mojo {
+namespace runner {
+class RunnerConnection;
+}
+}
+
+namespace content {
+
+// Returns true if the Chrome browser process was launched from the external
+// Mojo shell.
+bool IsRunningInMojoShell();
+
+class MojoShellConnectionImpl : public MojoShellConnection,
+                                public mojo::ApplicationDelegate {
+ public:
+  // Creates an instance of this class and stuffs it in TLS on the calling
+  // thread. Retrieve it using MojoShellConnection::Get(). Blocks the calling
+  // thread until calling GetApplication() will return an Initialized()
+  // application with a bound ShellPtr.
+  static void Create();
+
+ private:
+  MojoShellConnectionImpl();
+  ~MojoShellConnectionImpl() override;
+
+  // mojo::ApplicationDelegate:
+  void Initialize(mojo::ApplicationImpl* application) override;
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override;
+
+  // MojoShellConnection:
+  mojo::ApplicationImpl* GetApplication() override;
+  void AddListener(Listener* listener) override;
+  void RemoveListener(Listener* listener) override;
+
+  // Blocks the calling thread until a connection to the spawning shell is
+  // established, an Application request from it is bound, and the Initialize()
+  // method on that application is called.
+  void WaitForShell();
+
+  bool initialized_;
+  scoped_ptr<mojo::runner::RunnerConnection> runner_connection_;
+  scoped_ptr<mojo::ApplicationImpl> application_impl_;
+  std::vector<Listener*> listeners_;
+
+  DISALLOW_COPY_AND_ASSIGN(MojoShellConnectionImpl);
+};
+
+}  // namespace content
+
+#endif  // CONTENT_COMMON_MOJO_SHELL_CONNECTION_IMPL_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi
index 383ba9b..3c7e636 100644
--- a/content/content_browser.gypi
+++ b/content/content_browser.gypi
@@ -1586,8 +1586,6 @@
         'browser/accessibility/browser_accessibility_manager_android.h',
         'browser/android/composited_touch_handle_drawable.cc',
         'browser/android/composited_touch_handle_drawable.h',
-        'browser/android/content_readback_handler.cc',
-        'browser/android/content_readback_handler.h',
         'browser/android/content_view_core_impl.cc',
         'browser/android/content_view_core_impl.h',
         'browser/android/content_view_render_view.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi
index f9236da8..7a04d5e 100644
--- a/content/content_common.gypi
+++ b/content/content_common.gypi
@@ -91,6 +91,7 @@
       'public/common/message_port_types.h',
       'public/common/mojo_channel_switches.cc',
       'public/common/mojo_channel_switches.h',
+      'public/common/mojo_shell_connection.h',
       'public/common/navigator_connect_client.cc',
       'public/common/navigator_connect_client.h',
       'public/common/origin_util.h',
diff --git a/content/content_jni.gypi b/content/content_jni.gypi
index a5295d5..958e58c 100644
--- a/content/content_jni.gypi
+++ b/content/content_jni.gypi
@@ -14,7 +14,6 @@
     'public/android/java/src/org/chromium/content/browser/BackgroundSyncNetworkObserver.java',
     'public/android/java/src/org/chromium/content/browser/BrowserStartupController.java',
     'public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java',
-    'public/android/java/src/org/chromium/content/browser/ContentReadbackHandler.java',
     'public/android/java/src/org/chromium/content/browser/ContentVideoView.java',
     'public/android/java/src/org/chromium/content/browser/ContentViewCore.java',
     'public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java',
diff --git a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
index dc91394..cba341c2f 100644
--- a/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
+++ b/content/public/android/java/src/org/chromium/content/browser/ContentViewRenderView.java
@@ -31,8 +31,6 @@
     private final SurfaceView mSurfaceView;
     protected ContentViewCore mContentViewCore;
 
-    private ContentReadbackHandler mContentReadbackHandler;
-
     /**
      * Constructs a new ContentViewRenderView.
      * This should be called and the {@link ContentViewRenderView} should be added to the view
@@ -93,21 +91,6 @@
         };
         mSurfaceView.getHolder().addCallback(mSurfaceCallback);
         mSurfaceView.setVisibility(VISIBLE);
-
-        mContentReadbackHandler = new ContentReadbackHandler() {
-            @Override
-            protected boolean readyForReadback() {
-                return mNativeContentViewRenderView != 0 && mContentViewCore != null;
-            }
-        };
-        mContentReadbackHandler.initNativeContentReadbackHandler();
-    }
-
-    /**
-     * @return The content readback handler.
-     */
-    public ContentReadbackHandler getContentReadbackHandler() {
-        return mContentReadbackHandler;
     }
 
     /**
@@ -134,8 +117,6 @@
      * native resource can be freed.
      */
     public void destroy() {
-        mContentReadbackHandler.destroy();
-        mContentReadbackHandler = null;
         mSurfaceView.getHolder().removeCallback(mSurfaceCallback);
         nativeDestroy(mNativeContentViewRenderView);
         mNativeContentViewRenderView = 0;
diff --git a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
index 2e625f32..a6f4cfb5 100644
--- a/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
+++ b/content/public/android/java/src/org/chromium/content/browser/webcontents/WebContentsImpl.java
@@ -4,7 +4,9 @@
 
 package org.chromium.content.browser.webcontents;
 
+import android.graphics.Bitmap;
 import android.graphics.Color;
+import android.graphics.Rect;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.ParcelUuid;
@@ -15,6 +17,7 @@
 import org.chromium.base.annotations.JNINamespace;
 import org.chromium.content_public.browser.AccessibilitySnapshotCallback;
 import org.chromium.content_public.browser.AccessibilitySnapshotNode;
+import org.chromium.content_public.browser.ContentBitmapCallback;
 import org.chromium.content_public.browser.JavaScriptCallback;
 import org.chromium.content_public.browser.NavigationController;
 import org.chromium.content_public.browser.WebContents;
@@ -413,6 +416,19 @@
         mObserverProxy.removeObserver(observer);
     }
 
+    @Override
+    public void getContentBitmapAsync(Bitmap.Config config, float scale, Rect srcRect,
+            ContentBitmapCallback callback) {
+        nativeGetContentBitmap(mNativeWebContentsAndroid, callback, config, scale,
+                srcRect.top, srcRect.left, srcRect.width(), srcRect.height());
+    }
+
+    @CalledByNative
+    private void onGetContentBitmapFinished(ContentBitmapCallback callback, Bitmap bitmap,
+            int response) {
+        callback.onFinishGetBitmap(bitmap, response);
+    }
+
     // This is static to avoid exposing a public destroy method on the native side of this class.
     private static native void nativeDestroyWebContents(long webContentsAndroidPtr);
 
@@ -468,4 +484,7 @@
     private native void nativeSuspendMediaSession(long nativeWebContentsAndroid);
     private native void nativeStopMediaSession(long nativeWebContentsAndroid);
     private native String nativeGetEncoding(long nativeWebContentsAndroid);
+    private native void nativeGetContentBitmap(long nativeWebContentsAndroid,
+            ContentBitmapCallback callback, Bitmap.Config config, float scale,
+            float x, float y, float width, float height);
 }
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/ContentBitmapCallback.java b/content/public/android/java/src/org/chromium/content_public/browser/ContentBitmapCallback.java
new file mode 100644
index 0000000..f6d372d
--- /dev/null
+++ b/content/public/android/java/src/org/chromium/content_public/browser/ContentBitmapCallback.java
@@ -0,0 +1,22 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.content_public.browser;
+
+import android.graphics.Bitmap;
+
+/**
+* An interface used to get notified of the completion of content bitmap acquisition.
+*/
+public interface ContentBitmapCallback {
+    /**
+     * Called when bitmap version of the content is acquired.
+     *
+     * @param bitmap content snapshot in the format of {@link Bitmap}, or an empty
+     *        bitmap if the operation failed.
+     * @param response one of response types as defined in
+     *        {@link org.chromium.content_public.browser.readback_types.ReadbackResponse}
+     */
+    void onFinishGetBitmap(Bitmap bitmap, int response);
+}
diff --git a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
index e43c084..919fd1b 100644
--- a/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
+++ b/content/public/android/java/src/org/chromium/content_public/browser/WebContents.java
@@ -4,6 +4,8 @@
 
 package org.chromium.content_public.browser;
 
+import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.os.Parcelable;
 
 import org.chromium.base.VisibleForTesting;
@@ -325,4 +327,7 @@
      */
     @VisibleForTesting
     String getEncoding();
+
+    public void getContentBitmapAsync(Bitmap.Config config, float scale, Rect srcRect,
+            ContentBitmapCallback callback);
 }
diff --git a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewReadbackTest.java b/content/public/android/javatests/src/org/chromium/content/browser/ContentViewReadbackTest.java
deleted file mode 100644
index a3a74f8..0000000
--- a/content/public/android/javatests/src/org/chromium/content/browser/ContentViewReadbackTest.java
+++ /dev/null
@@ -1,127 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.content.browser;
-
-import static org.chromium.base.test.util.ScalableTimeout.scaleTimeout;
-
-import android.graphics.Bitmap;
-import android.graphics.Color;
-import android.graphics.Rect;
-import android.os.SystemClock;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.AssertionFailedError;
-
-import org.chromium.base.ThreadUtils;
-import org.chromium.base.test.util.Feature;
-import org.chromium.base.test.util.UrlUtils;
-import org.chromium.content.browser.ContentReadbackHandler.GetBitmapCallback;
-import org.chromium.content.browser.test.util.Criteria;
-import org.chromium.content.browser.test.util.CriteriaHelper;
-import org.chromium.content_public.browser.readback_types.ReadbackResponse;
-import org.chromium.content_shell_apk.ContentShellTestBase;
-
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.atomic.AtomicInteger;
-
-/**
- * Tests that we can readback the contents of a ContentView.
- */
-public class ContentViewReadbackTest extends ContentShellTestBase {
-
-    private static final int COLOR_THRESHOLD = 8;
-    private static final long WAIT_FOR_READBACK_TIMEOUT =  scaleTimeout(10000);
-
-    @Override
-    protected void setUp() throws Exception {
-        super.setUp();
-        launchContentShellWithUrl(UrlUtils.encodeHtmlDataUri(
-                "<html style=\"background: #00f;\"><head><style>body { height: 5000px; }</style>"
-                        + "</head></html>"));
-        assertTrue("Page failed to load", waitForActiveShellToBeDoneLoading());
-    }
-
-    private static void assertEqualColor(int actual, int expected, int threshold) {
-        int deltaR = Math.abs(Color.red(actual) - Color.red(expected));
-        int deltaG = Math.abs(Color.green(actual) - Color.green(expected));
-        int deltaB = Math.abs(Color.blue(actual) - Color.blue(expected));
-        if (deltaR > threshold || deltaG > threshold || deltaB > threshold) {
-            throw new AssertionFailedError(
-                    "Color does not match; expected " + expected + ", got " + actual);
-        }
-    }
-
-    private void assertWaitForYScroll(final int previousYScroll) throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return getContentViewCore().getNativeScrollYForTest() > previousYScroll;
-            }
-        }));
-    }
-
-    private void assertWaitForReadback(final AtomicBoolean readbackDone)
-            throws InterruptedException {
-        assertTrue(CriteriaHelper.pollForCriteria(new Criteria() {
-            @Override
-            public boolean isSatisfied() {
-                return readbackDone.get();
-            }
-        }, WAIT_FOR_READBACK_TIMEOUT, CriteriaHelper.DEFAULT_POLLING_INTERVAL));
-    }
-
-    /**
-     * Test to make sure the screenshots captured of the ContentView are not blank.
-     *
-     * @throws InterruptedException
-     */
-    @SmallTest
-    @Feature({"Main"})
-    public void testScreenshotIsNotBlank() throws Throwable {
-        final AtomicBoolean readbackDone = new AtomicBoolean(false);
-        final AtomicInteger color = new AtomicInteger();
-
-        // We wait on the fling to make sure that the compositor side has a layer available by the
-        // time we reach readback.
-        int previousYScroll = getContentViewCore().getNativeScrollYForTest();
-        ThreadUtils.runOnUiThreadBlocking(new Runnable() {
-            @Override
-            public void run() {
-                getContentViewCore().flingViewport(SystemClock.uptimeMillis(), 0, -1000);
-            }
-        });
-        assertWaitForYScroll(previousYScroll);
-
-        runTestOnUiThread(new Runnable() {
-            @Override
-            public void run() {
-                ContentReadbackHandler contentReadbackHandler = new ContentReadbackHandler() {
-                    @Override
-                    protected boolean readyForReadback() {
-                        return true;
-                    }
-                };
-
-                GetBitmapCallback callback = new GetBitmapCallback() {
-                    @Override
-                    public void onFinishGetBitmap(Bitmap bitmap, int response) {
-                        assertEquals(ReadbackResponse.SUCCESS, response);
-                        assertNotNull("Readback did not return valid bitmap", bitmap);
-                        // Verify a pixel in the center of the screenshot.
-                        color.set(bitmap.getPixel(bitmap.getWidth() / 2, bitmap.getHeight() / 2));
-                        readbackDone.set(true);
-                    }
-                };
-
-                contentReadbackHandler.initNativeContentReadbackHandler();
-                contentReadbackHandler.getContentBitmapAsync(1.0f, new Rect(), getContentViewCore(),
-                        Bitmap.Config.ARGB_8888, callback);
-            }
-        });
-        assertWaitForReadback(readbackDone);
-
-        assertEqualColor(color.get(), Color.BLUE, COLOR_THRESHOLD);
-    }
-}
diff --git a/content/public/common/mojo_shell_connection.h b/content/public/common/mojo_shell_connection.h
new file mode 100644
index 0000000..af4cce1
--- /dev/null
+++ b/content/public/common/mojo_shell_connection.h
@@ -0,0 +1,59 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CONTENT_PUBLIC_COMMON_MOJO_SHELL_CONNECTION_H_
+#define CONTENT_PUBLIC_COMMON_MOJO_SHELL_CONNECTION_H_
+
+#include "content/common/content_export.h"
+
+namespace mojo {
+class ApplicationConnection;
+class ApplicationImpl;
+}
+
+namespace content {
+
+// Encapsulates a connection to a spawning external Mojo shell.
+// Access an instance by calling Get(), on the thread the Shell connection is
+// bound. Clients can implement Listener, which allows them to register services
+// to expose to inbound connections. Clients should call this any time after
+// the main message loop is created but not yet run (e.g. in the browser process
+// this object is created in PreMainMessageLoopRun(), so the BrowserMainParts
+// impl can access this in its implementation of that same method.
+class CONTENT_EXPORT MojoShellConnection {
+ public:
+  // Override to add additional services to inbound connections.
+  class Listener {
+   public:
+    virtual bool ConfigureIncomingConnection(
+        mojo::ApplicationConnection* connection) = 0;
+
+   protected:
+    virtual ~Listener() {}
+  };
+
+  // Will return null if no connection has been established (either because it
+  // hasn't happened yet or the application was not spawned from the external
+  // Mojo shell.
+  static MojoShellConnection* Get();
+
+  // Destroys the connection. Must be called on the thread the connection was
+  // created on.
+  static void Destroy();
+
+  // Returns an Initialized() ApplicationImpl.
+  virtual mojo::ApplicationImpl* GetApplication() = 0;
+
+  // [De]Register an impl of Listener that will be consulted when the wrapped
+  // ApplicationImpl exposes services to inbound connections.
+  virtual void AddListener(Listener* listener) = 0;
+  virtual void RemoveListener(Listener* listener) = 0;
+
+ protected:
+  virtual ~MojoShellConnection();
+};
+
+}  // namespace content
+
+#endif  // CONTENT_PUBLIC_COMMON_MOJO_SHELL_CONNECTION_H_
diff --git a/content/renderer/media/android/stream_texture_factory.h b/content/renderer/media/android/stream_texture_factory.h
index 812fd1ee2..ae2ac3a 100644
--- a/content/renderer/media/android/stream_texture_factory.h
+++ b/content/renderer/media/android/stream_texture_factory.h
@@ -60,7 +60,7 @@
   // object for the given stream_id. After the the surface is created,
   // it will be passed back to the WebMediaPlayerAndroid object identified by
   // the player_id.
-  virtual void EstablishPeer(int32 stream_id, int player_id) = 0;
+  virtual void EstablishPeer(int32 stream_id, int player_id, int frame_id) = 0;
 
   // Creates a StreamTexture and returns its id.  Sets |*texture_id| to the
   // client-side id of the StreamTexture. The texture is produced into
diff --git a/content/renderer/media/android/stream_texture_factory_impl.cc b/content/renderer/media/android/stream_texture_factory_impl.cc
index a17531b2c9..740fed3c 100644
--- a/content/renderer/media/android/stream_texture_factory_impl.cc
+++ b/content/renderer/media/android/stream_texture_factory_impl.cc
@@ -5,6 +5,7 @@
 #include "content/renderer/media/android/stream_texture_factory_impl.h"
 
 #include "cc/output/context_provider.h"
+#include "content/common/gpu/client/context_provider_command_buffer.h"
 #include "content/common/gpu/client/gpu_channel_host.h"
 #include "content/common/gpu/gpu_messages.h"
 #include "content/renderer/gpu/stream_texture_host_android.h"
@@ -110,19 +111,15 @@
 
 // static
 scoped_refptr<StreamTextureFactoryImpl> StreamTextureFactoryImpl::Create(
-    const scoped_refptr<cc::ContextProvider>& context_provider,
-    GpuChannelHost* channel,
-    int frame_id) {
-  return new StreamTextureFactoryImpl(context_provider, channel, frame_id);
+    const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+    GpuChannelHost* channel) {
+  return new StreamTextureFactoryImpl(context_provider, channel);
 }
 
 StreamTextureFactoryImpl::StreamTextureFactoryImpl(
-    const scoped_refptr<cc::ContextProvider>& context_provider,
-    GpuChannelHost* channel,
-    int frame_id)
-    : context_provider_(context_provider),
-      channel_(channel),
-      frame_id_(frame_id) {
+    const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+    GpuChannelHost* channel)
+    : context_provider_(context_provider), channel_(channel) {
   DCHECK(channel);
 }
 
@@ -134,10 +131,12 @@
   return new StreamTextureProxyImpl(host);
 }
 
-void StreamTextureFactoryImpl::EstablishPeer(int32 stream_id, int player_id) {
+void StreamTextureFactoryImpl::EstablishPeer(int32 stream_id,
+                                             int player_id,
+                                             int frame_id) {
   DCHECK(channel_.get());
   channel_->Send(
-      new GpuStreamTextureMsg_EstablishPeer(stream_id, frame_id_, player_id));
+      new GpuStreamTextureMsg_EstablishPeer(stream_id, frame_id, player_id));
 }
 
 unsigned StreamTextureFactoryImpl::CreateStreamTexture(
@@ -147,9 +146,9 @@
   GLuint stream_id = 0;
   gpu::gles2::GLES2Interface* gl = context_provider_->ContextGL();
   gl->GenTextures(1, texture_id);
-
-  stream_id = gl->CreateStreamTextureCHROMIUM(*texture_id);
-
+  gl->ShallowFlushCHROMIUM();
+  stream_id = context_provider_->GetCommandBufferProxy()->CreateStreamTexture(
+      *texture_id);
   gl->GenMailboxCHROMIUM(texture_mailbox->name);
   gl->ProduceTextureDirectCHROMIUM(
       *texture_id, texture_target, texture_mailbox->name);
diff --git a/content/renderer/media/android/stream_texture_factory_impl.h b/content/renderer/media/android/stream_texture_factory_impl.h
index 0374879..f39ba49 100644
--- a/content/renderer/media/android/stream_texture_factory_impl.h
+++ b/content/renderer/media/android/stream_texture_factory_impl.h
@@ -19,18 +19,18 @@
 
 namespace content {
 
+class ContextProviderCommandBuffer;
 class GpuChannelHost;
 
 class StreamTextureFactoryImpl : public StreamTextureFactory {
  public:
   static scoped_refptr<StreamTextureFactoryImpl> Create(
-      const scoped_refptr<cc::ContextProvider>& context_provider,
-      GpuChannelHost* channel,
-      int frame_id);
+      const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+      GpuChannelHost* channel);
 
   // StreamTextureFactory implementation.
   StreamTextureProxy* CreateProxy() override;
-  void EstablishPeer(int32 stream_id, int player_id) override;
+  void EstablishPeer(int32 stream_id, int player_id, int frame_id) override;
   unsigned CreateStreamTexture(unsigned texture_target,
                                unsigned* texture_id,
                                gpu::Mailbox* texture_mailbox) override;
@@ -42,14 +42,12 @@
  private:
   friend class base::RefCounted<StreamTextureFactoryImpl>;
   StreamTextureFactoryImpl(
-      const scoped_refptr<cc::ContextProvider>& context_provider,
-      GpuChannelHost* channel,
-      int frame_id);
+      const scoped_refptr<ContextProviderCommandBuffer>& context_provider,
+      GpuChannelHost* channel);
   ~StreamTextureFactoryImpl() override;
 
-  scoped_refptr<cc::ContextProvider> context_provider_;
+  scoped_refptr<content::ContextProviderCommandBuffer> context_provider_;
   scoped_refptr<GpuChannelHost> channel_;
-  int frame_id_;
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(StreamTextureFactoryImpl);
 };
diff --git a/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc b/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
index d92d3ab8..116fc011 100644
--- a/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
+++ b/content/renderer/media/android/stream_texture_factory_synchronous_impl.cc
@@ -179,7 +179,8 @@
 }
 
 void StreamTextureFactorySynchronousImpl::EstablishPeer(int32 stream_id,
-                                                        int player_id) {
+                                                        int player_id,
+                                                        int frame_id) {
   DCHECK(context_provider_.get());
   scoped_refptr<gfx::SurfaceTexture> surface_texture =
       context_provider_->GetSurfaceTexture(stream_id);
@@ -200,8 +201,8 @@
   unsigned stream_id = 0;
   GLES2Interface* gl = context_provider_->ContextGL();
   gl->GenTextures(1, texture_id);
-  stream_id = gl->CreateStreamTextureCHROMIUM(*texture_id);
-
+  gl->ShallowFlushCHROMIUM();
+  stream_id = context_provider_->CreateStreamTexture(*texture_id);
   gl->GenMailboxCHROMIUM(texture_mailbox->name);
   gl->ProduceTextureDirectCHROMIUM(
       *texture_id, texture_target, texture_mailbox->name);
diff --git a/content/renderer/media/android/stream_texture_factory_synchronous_impl.h b/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
index 1e2db8a5..6f1da28 100644
--- a/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
+++ b/content/renderer/media/android/stream_texture_factory_synchronous_impl.h
@@ -30,6 +30,8 @@
     virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
         uint32 stream_id) = 0;
 
+    virtual uint32 CreateStreamTexture(uint32 texture_id) = 0;
+
     virtual gpu::gles2::GLES2Interface* ContextGL() = 0;
 
     virtual void AddObserver(StreamTextureFactoryContextObserver* obs) = 0;
@@ -48,7 +50,7 @@
       int frame_id);
 
   StreamTextureProxy* CreateProxy() override;
-  void EstablishPeer(int32 stream_id, int player_id) override;
+  void EstablishPeer(int32 stream_id, int player_id, int frame_id) override;
   unsigned CreateStreamTexture(unsigned texture_target,
                                unsigned* texture_id,
                                gpu::Mailbox* texture_mailbox) override;
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc
index cfd92af..6d5a317 100644
--- a/content/renderer/media/android/webmediaplayer_android.cc
+++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -161,6 +161,7 @@
     RendererMediaPlayerManager* player_manager,
     media::CdmFactory* cdm_factory,
     scoped_refptr<StreamTextureFactory> factory,
+    int frame_id,
     const media::WebMediaPlayerParams& params)
     : RenderFrameObserver(RenderFrame::FromWebFrame(frame)),
       frame_(frame),
@@ -201,6 +202,7 @@
       allow_stored_credentials_(false),
       is_local_resource_(false),
       interpolator_(&default_tick_clock_),
+      frame_id_(frame_id),
       weak_factory_(this) {
   DCHECK(player_manager_);
   DCHECK(cdm_factory_);
@@ -1388,7 +1390,7 @@
     return;
 
   if (stream_texture_factory_.get() && stream_id_)
-    stream_texture_factory_->EstablishPeer(stream_id_, player_id_);
+    stream_texture_factory_->EstablishPeer(stream_id_, player_id_, frame_id_);
 
   // Set the deferred size because the size was changed in remote mode.
   if (!is_remote_ && cached_stream_texture_size_ != natural_size_) {
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h
index 59859ff1..2734bf8 100644
--- a/content/renderer/media/android/webmediaplayer_android.h
+++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -95,6 +95,7 @@
       RendererMediaPlayerManager* player_manager,
       media::CdmFactory* cdm_factory,
       scoped_refptr<StreamTextureFactory> factory,
+      int frame_id,
       const media::WebMediaPlayerParams& params);
   virtual ~WebMediaPlayerAndroid();
 
@@ -531,6 +532,8 @@
 
   scoped_ptr<MediaSourceDelegate> media_source_delegate_;
 
+  int frame_id_;
+
   // NOTE: Weak pointers must be invalidated before all other member variables.
   base::WeakPtrFactory<WebMediaPlayerAndroid> weak_factory_;
 
diff --git a/content/renderer/media/mock_peer_connection_impl.h b/content/renderer/media/mock_peer_connection_impl.h
index ef7d63b..2787b99 100644
--- a/content/renderer/media/mock_peer_connection_impl.h
+++ b/content/renderer/media/mock_peer_connection_impl.h
@@ -61,9 +61,8 @@
     NOTIMPLEMENTED();
     return PeerConnectionInterface::kIceGatheringNew;
   }
-  void Close() override {
-    NOTIMPLEMENTED();
-  }
+
+  MOCK_METHOD0(Close, void());
 
   const webrtc::SessionDescriptionInterface* local_description() const override;
   const webrtc::SessionDescriptionInterface* remote_description()
diff --git a/content/renderer/media/rtc_peer_connection_handler.cc b/content/renderer/media/rtc_peer_connection_handler.cc
index 6dfe0d9f..aa2a2ec 100644
--- a/content/renderer/media/rtc_peer_connection_handler.cc
+++ b/content/renderer/media/rtc_peer_connection_handler.cc
@@ -796,8 +796,10 @@
     blink::WebRTCPeerConnectionHandlerClient* client,
     PeerConnectionDependencyFactory* dependency_factory)
     : client_(client),
+      is_closed_(false),
       dependency_factory_(dependency_factory),
       weak_factory_(this) {
+  CHECK(client_),
   g_peer_connection_handlers.Get().insert(this);
 }
 
@@ -817,13 +819,13 @@
 
 // static
 void RTCPeerConnectionHandler::DestructAllHandlers() {
+  // Copy g_peer_connection_handlers since releasePeerConnectionHandler will
+  // remove an item.
   std::set<RTCPeerConnectionHandler*> handlers(
       g_peer_connection_handlers.Get().begin(),
       g_peer_connection_handlers.Get().end());
-  for (auto handler : handlers) {
-    if (handler->client_)
-      handler->client_->releasePeerConnectionHandler();
-  }
+  for (auto* handler : handlers)
+    handler->client_->releasePeerConnectionHandler();
 }
 
 // static
@@ -1309,7 +1311,7 @@
 
 void RTCPeerConnectionHandler::CloseClientPeerConnection() {
   DCHECK(thread_checker_.CalledOnValidThread());
-  if (client_)
+  if (!is_closed_)
     client_->closePeerConnection();
 }
 
@@ -1380,7 +1382,7 @@
   DCHECK(thread_checker_.CalledOnValidThread());
   DVLOG(1) << "RTCPeerConnectionHandler::stop";
 
-  if (!client_ || !native_peer_connection_.get())
+  if (is_closed_ || !native_peer_connection_.get())
     return;  // Already stopped.
 
   if (peer_connection_tracker_)
@@ -1388,9 +1390,8 @@
 
   native_peer_connection_->Close();
 
-  // The client_ pointer is not considered valid after this point and no further
-  // callbacks must be made.
-  client_ = nullptr;
+  // This object may no longer forward call backs to blink.
+  is_closed_ = true;
 }
 
 void RTCPeerConnectionHandler::OnSignalingChange(
@@ -1402,7 +1403,7 @@
       GetWebKitSignalingState(new_state);
   if (peer_connection_tracker_)
     peer_connection_tracker_->TrackSignalingStateChange(this, state);
-  if (client_)
+  if (!is_closed_)
     client_->didChangeSignalingState(state);
 }
 
@@ -1438,7 +1439,7 @@
       GetWebKitIceConnectionState(new_state);
   if (peer_connection_tracker_)
     peer_connection_tracker_->TrackIceConnectionStateChange(this, state);
-  if(client_)
+  if (!is_closed_)
     client_->didChangeICEConnectionState(state);
 }
 
@@ -1451,7 +1452,7 @@
   if (new_state == webrtc::PeerConnectionInterface::kIceGatheringComplete) {
     // If ICE gathering is completed, generate a NULL ICE candidate,
     // to signal end of candidates.
-    if (client_) {
+    if (!is_closed_) {
       blink::WebRTCICECandidate null_candidate;
       client_->didGenerateICECandidate(null_candidate);
     }
@@ -1508,7 +1509,7 @@
 
   track_metrics_.AddStream(MediaStreamTrackMetrics::RECEIVED_STREAM,
                            s->webrtc_stream().get());
-  if (client_)
+  if (!is_closed_)
     client_->didAddRemoteStream(s->webkit_stream());
 }
 
@@ -1536,7 +1537,7 @@
         this, webkit_stream, PeerConnectionTracker::SOURCE_REMOTE);
   }
 
-  if (client_)
+  if (!is_closed_)
     client_->didRemoveRemoteStream(webkit_stream);
 }
 
@@ -1550,7 +1551,7 @@
         this, handler->channel().get(), PeerConnectionTracker::SOURCE_REMOTE);
   }
 
-  if (client_)
+  if (!is_closed_)
     client_->didAddRemoteDataChannel(handler.release());
 }
 
@@ -1579,7 +1580,7 @@
       NOTREACHED();
     }
   }
-  if (client_)
+  if (!is_closed_)
     client_->didGenerateICECandidate(web_candidate);
 }
 
diff --git a/content/renderer/media/rtc_peer_connection_handler.h b/content/renderer/media/rtc_peer_connection_handler.h
index 8e8af25..fa45d6a 100644
--- a/content/renderer/media/rtc_peer_connection_handler.h
+++ b/content/renderer/media/rtc_peer_connection_handler.h
@@ -225,8 +225,14 @@
 
   base::ThreadChecker thread_checker_;
 
-  // |client_| is a weak pointer, and is valid until stop() has returned.
-  blink::WebRTCPeerConnectionHandlerClient* client_;
+  // |client_| is a weak pointer to the blink object (blink::RTCPeerConnection)
+  // that owns this object.
+  // It is valid for the lifetime of this object.
+  blink::WebRTCPeerConnectionHandlerClient* const client_;
+  // True if this PeerConnection has been closed.
+  // After the PeerConnection has been closed, this object may no longer
+  // forward callbacks to blink.
+  bool is_closed_;
 
   // |dependency_factory_| is a raw pointer, and is valid for the lifetime of
   // RenderThreadImpl.
diff --git a/content/renderer/media/rtc_peer_connection_handler_unittest.cc b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
index 6cbdd1db..e2867d14 100644
--- a/content/renderer/media/rtc_peer_connection_handler_unittest.cc
+++ b/content/renderer/media/rtc_peer_connection_handler_unittest.cc
@@ -231,6 +231,7 @@
 
     mock_peer_connection_ = pc_handler_->native_peer_connection();
     ASSERT_TRUE(mock_peer_connection_);
+    EXPECT_CALL(*mock_peer_connection_, Close());
   }
 
   void TearDown() override {
@@ -334,6 +335,11 @@
   pc_handler_.reset(NULL);
 }
 
+TEST_F(RTCPeerConnectionHandlerTest, DestructAllHandlers) {
+  EXPECT_CALL(*mock_client_.get(), releasePeerConnectionHandler())
+      .Times(1);
+  RTCPeerConnectionHandler::DestructAllHandlers();
+}
 TEST_F(RTCPeerConnectionHandlerTest, CreateOffer) {
   blink::WebRTCSessionDescriptionRequest request;
   blink::WebMediaConstraints options;
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc
index f8c5afa..d07cd18e 100644
--- a/content/renderer/render_frame_impl.cc
+++ b/content/renderer/render_frame_impl.cc
@@ -5231,31 +5231,18 @@
           SynchronousCompositorFactory::GetInstance()) {
     stream_texture_factory = factory->CreateStreamTextureFactory(routing_id_);
   } else {
-    GpuChannelHost* gpu_channel_host =
-        RenderThreadImpl::current()->EstablishGpuChannelSync(
-            CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE);
-
-    if (!gpu_channel_host) {
-      LOG(ERROR) << "Failed to establish GPU channel for media player";
+    stream_texture_factory =
+        RenderThreadImpl::current()->GetStreamTexureFactory();
+    if (!stream_texture_factory.get()) {
+      LOG(ERROR) << "Failed to get stream texture factory!";
       return NULL;
     }
-
-    scoped_refptr<cc_blink::ContextProviderWebContext> context_provider =
-        RenderThreadImpl::current()->SharedMainThreadContextProvider();
-
-    if (!context_provider.get()) {
-      LOG(ERROR) << "Failed to get context3d for media player";
-      return NULL;
-    }
-
-    stream_texture_factory = StreamTextureFactoryImpl::Create(
-        context_provider, gpu_channel_host, routing_id_);
   }
 
   return new WebMediaPlayerAndroid(frame_, client, encrypted_client,
                                    GetWebMediaPlayerDelegate()->AsWeakPtr(),
                                    GetMediaPlayerManager(), GetCdmFactory(),
-                                   stream_texture_factory, params);
+                                   stream_texture_factory, routing_id_, params);
 }
 
 RendererMediaPlayerManager* RenderFrameImpl::GetMediaPlayerManager() {
diff --git a/content/renderer/render_thread_impl.cc b/content/renderer/render_thread_impl.cc
index 28fde258..9dd0a4d 100644
--- a/content/renderer/render_thread_impl.cc
+++ b/content/renderer/render_thread_impl.cc
@@ -163,6 +163,7 @@
 #include "content/renderer/android/synchronous_compositor_factory.h"
 #include "content/renderer/android/synchronous_compositor_filter.h"
 #include "content/renderer/media/android/renderer_demuxer_android.h"
+#include "content/renderer/media/android/stream_texture_factory_impl.h"
 #endif
 
 #if defined(OS_MACOSX)
@@ -868,6 +869,7 @@
     RemoveFilter(sync_compositor_message_filter_.get());
     sync_compositor_message_filter_ = nullptr;
   }
+  stream_texture_factory_ = nullptr;
 #endif
 
   media_thread_.reset();
@@ -1468,6 +1470,30 @@
   return shared_main_thread_contexts_;
 }
 
+#if defined(OS_ANDROID)
+scoped_refptr<StreamTextureFactory> RenderThreadImpl::GetStreamTexureFactory() {
+  DCHECK(IsMainThread());
+  if (!stream_texture_factory_.get() ||
+      stream_texture_factory_->ContextGL()->GetGraphicsResetStatusKHR() !=
+          GL_NO_ERROR) {
+    if (!SharedMainThreadContextProvider().get()) {
+      stream_texture_factory_ = NULL;
+      return NULL;
+    }
+    scoped_refptr<GpuChannelHost> gpu_channel_host(EstablishGpuChannelSync(
+        CAUSE_FOR_GPU_LAUNCH_VIDEODECODEACCELERATOR_INITIALIZE));
+    if (!gpu_channel_host.get()) {
+      LOG(ERROR) << "Failed to establish GPU channel for media player";
+      stream_texture_factory_ = NULL;
+    } else {
+      stream_texture_factory_ = StreamTextureFactoryImpl::Create(
+          shared_main_thread_contexts_, gpu_channel_host.get());
+    }
+  }
+  return stream_texture_factory_;
+}
+#endif
+
 AudioRendererMixerManager* RenderThreadImpl::GetAudioRendererMixerManager() {
   if (!audio_renderer_mixer_manager_) {
     audio_renderer_mixer_manager_.reset(new AudioRendererMixerManager());
diff --git a/content/renderer/render_thread_impl.h b/content/renderer/render_thread_impl.h
index 0683487..abd0289 100644
--- a/content/renderer/render_thread_impl.h
+++ b/content/renderer/render_thread_impl.h
@@ -116,6 +116,7 @@
 class WebRTCIdentityService;
 
 #if defined(OS_ANDROID)
+class StreamTextureFactory;
 class SynchronousCompositorFilter;
 #endif
 
@@ -288,6 +289,8 @@
   SynchronousCompositorFilter* sync_compositor_message_filter() {
     return sync_compositor_message_filter_.get();
   }
+
+  scoped_refptr<StreamTextureFactory> GetStreamTexureFactory();
 #endif
 
   // Creates the embedder implementation of WebMediaStreamCenter.
@@ -612,12 +615,12 @@
 
 #if defined(OS_ANDROID)
   scoped_refptr<SynchronousCompositorFilter> sync_compositor_message_filter_;
+  scoped_refptr<StreamTextureFactory> stream_texture_factory_;
 #endif
 
   scoped_refptr<BluetoothMessageFilter> bluetooth_message_filter_;
 
-  scoped_refptr<cc_blink::ContextProviderWebContext>
-      shared_main_thread_contexts_;
+  scoped_refptr<ContextProviderCommandBuffer> shared_main_thread_contexts_;
 
   base::ObserverList<RenderProcessObserver> observers_;
 
diff --git a/gpu/GLES2/gl2chromium_autogen.h b/gpu/GLES2/gl2chromium_autogen.h
index e07f3f3f..8a78728 100644
--- a/gpu/GLES2/gl2chromium_autogen.h
+++ b/gpu/GLES2/gl2chromium_autogen.h
@@ -285,7 +285,6 @@
 #define glGetTransformFeedbackVaryingsCHROMIUM \
   GLES2_GET_FUN(GetTransformFeedbackVaryingsCHROMIUM)
 #define glGetUniformsES3CHROMIUM GLES2_GET_FUN(GetUniformsES3CHROMIUM)
-#define glCreateStreamTextureCHROMIUM GLES2_GET_FUN(CreateStreamTextureCHROMIUM)
 #define glCreateImageCHROMIUM GLES2_GET_FUN(CreateImageCHROMIUM)
 #define glDestroyImageCHROMIUM GLES2_GET_FUN(DestroyImageCHROMIUM)
 #define glCreateGpuMemoryBufferImageCHROMIUM \
diff --git a/gpu/command_buffer/build_gles2_cmd_buffer.py b/gpu/command_buffer/build_gles2_cmd_buffer.py
index ecd79bc..fb30873 100755
--- a/gpu/command_buffer/build_gles2_cmd_buffer.py
+++ b/gpu/command_buffer/build_gles2_cmd_buffer.py
@@ -3791,14 +3791,6 @@
     'extension': 'CHROMIUM_request_extension',
     'chromium': True,
   },
-  'CreateStreamTextureCHROMIUM':  {
-    'type': 'HandWritten',
-    'impl_func': False,
-    'gen_cmd': False,
-    'extension': True,
-    'chromium': True,
-    'trace_level': 1,
-  },
   'TexImageIOSurface2DCHROMIUM': {
     'decoder_func': 'DoTexImageIOSurface2DCHROMIUM',
     'unit_test': False,
diff --git a/gpu/command_buffer/client/gl_in_process_context.cc b/gpu/command_buffer/client/gl_in_process_context.cc
index 3b32c481..774f7d2 100644
--- a/gpu/command_buffer/client/gl_in_process_context.cc
+++ b/gpu/command_buffer/client/gl_in_process_context.cc
@@ -72,6 +72,7 @@
 #if defined(OS_ANDROID)
   scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
       uint32 stream_id) override;
+  uint32 CreateStreamTexture(uint32 texture_id) override;
 #endif
 
  private:
@@ -266,6 +267,10 @@
 GLInProcessContextImpl::GetSurfaceTexture(uint32 stream_id) {
   return command_buffer_->GetSurfaceTexture(stream_id);
 }
+
+uint32 GLInProcessContextImpl::CreateStreamTexture(uint32 texture_id) {
+  return command_buffer_->CreateStreamTexture(texture_id);
+}
 #endif
 
 }  // anonymous namespace
diff --git a/gpu/command_buffer/client/gl_in_process_context.h b/gpu/command_buffer/client/gl_in_process_context.h
index 8c3a1c5..656c8b2 100644
--- a/gpu/command_buffer/client/gl_in_process_context.h
+++ b/gpu/command_buffer/client/gl_in_process_context.h
@@ -81,6 +81,7 @@
 #if defined(OS_ANDROID)
   virtual scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
       uint32 stream_id) = 0;
+  virtual uint32 CreateStreamTexture(uint32 texture_id) = 0;
 #endif
 };
 
diff --git a/gpu/command_buffer/client/gles2_c_lib_autogen.h b/gpu/command_buffer/client/gles2_c_lib_autogen.h
index b96fdae..112889c 100644
--- a/gpu/command_buffer/client/gles2_c_lib_autogen.h
+++ b/gpu/command_buffer/client/gles2_c_lib_autogen.h
@@ -1294,9 +1294,6 @@
                                              void* info) {
   gles2::GetGLContext()->GetUniformsES3CHROMIUM(program, bufsize, size, info);
 }
-GLuint GL_APIENTRY GLES2CreateStreamTextureCHROMIUM(GLuint texture) {
-  return gles2::GetGLContext()->CreateStreamTextureCHROMIUM(texture);
-}
 GLuint GL_APIENTRY GLES2CreateImageCHROMIUM(ClientBuffer buffer,
                                             GLsizei width,
                                             GLsizei height,
@@ -2692,10 +2689,6 @@
         reinterpret_cast<GLES2FunctionPointer>(glGetUniformsES3CHROMIUM),
     },
     {
-        "glCreateStreamTextureCHROMIUM",
-        reinterpret_cast<GLES2FunctionPointer>(glCreateStreamTextureCHROMIUM),
-    },
-    {
         "glCreateImageCHROMIUM",
         reinterpret_cast<GLES2FunctionPointer>(glCreateImageCHROMIUM),
     },
diff --git a/gpu/command_buffer/client/gles2_implementation.cc b/gpu/command_buffer/client/gles2_implementation.cc
index 0b44e30..b7b8a7f 100644
--- a/gpu/command_buffer/client/gles2_implementation.cc
+++ b/gpu/command_buffer/client/gles2_implementation.cc
@@ -4864,15 +4864,6 @@
   memcpy(info, &result[0], result.size());
 }
 
-GLuint GLES2Implementation::CreateStreamTextureCHROMIUM(GLuint texture) {
-  GPU_CLIENT_SINGLE_THREAD_CHECK();
-  GPU_CLIENT_LOG("[" << GetLogPrefix() << "] CreateStreamTextureCHROMIUM("
-      << texture << ")");
-  TRACE_EVENT0("gpu", "GLES2::CreateStreamTextureCHROMIUM");
-  helper_->CommandBufferHelper::Flush();
-  return gpu_control_->CreateStreamTexture(texture);
-}
-
 void GLES2Implementation::PostSubBufferCHROMIUM(
     GLint x, GLint y, GLint width, GLint height) {
   GPU_CLIENT_SINGLE_THREAD_CHECK();
diff --git a/gpu/command_buffer/client/gles2_implementation_autogen.h b/gpu/command_buffer/client/gles2_implementation_autogen.h
index d6dc983..b74d1500 100644
--- a/gpu/command_buffer/client/gles2_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_implementation_autogen.h
@@ -896,8 +896,6 @@
                             GLsizei* size,
                             void* info) override;
 
-GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
-
 GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                            GLsizei width,
                            GLsizei height,
diff --git a/gpu/command_buffer/client/gles2_interface_autogen.h b/gpu/command_buffer/client/gles2_interface_autogen.h
index 974f96b..461d597 100644
--- a/gpu/command_buffer/client/gles2_interface_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_autogen.h
@@ -665,7 +665,6 @@
                                     GLsizei bufsize,
                                     GLsizei* size,
                                     void* info) = 0;
-virtual GLuint CreateStreamTextureCHROMIUM(GLuint texture) = 0;
 virtual GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                                    GLsizei width,
                                    GLsizei height,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
index 4974e2e..9ad7c50 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_autogen.h
@@ -642,7 +642,6 @@
                             GLsizei bufsize,
                             GLsizei* size,
                             void* info) override;
-GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
 GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                            GLsizei width,
                            GLsizei height,
diff --git a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
index 1c6e254f..ddc7cec 100644
--- a/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_interface_stub_impl_autogen.h
@@ -883,9 +883,6 @@
                                                 GLsizei /* bufsize */,
                                                 GLsizei* /* size */,
                                                 void* /* info */) {}
-GLuint GLES2InterfaceStub::CreateStreamTextureCHROMIUM(GLuint /* texture */) {
-  return 0;
-}
 GLuint GLES2InterfaceStub::CreateImageCHROMIUM(ClientBuffer /* buffer */,
                                                GLsizei /* width */,
                                                GLsizei /* height */,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
index 1bf1503c..8779c04 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_autogen.h
@@ -642,7 +642,6 @@
                             GLsizei bufsize,
                             GLsizei* size,
                             void* info) override;
-GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
 GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                            GLsizei width,
                            GLsizei height,
diff --git a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
index 37f3127..9d80272a 100644
--- a/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
+++ b/gpu/command_buffer/client/gles2_trace_implementation_impl_autogen.h
@@ -1887,12 +1887,6 @@
   gl_->GetUniformsES3CHROMIUM(program, bufsize, size, info);
 }
 
-GLuint GLES2TraceImplementation::CreateStreamTextureCHROMIUM(GLuint texture) {
-  TRACE_EVENT_BINARY_EFFICIENT0("gpu",
-                                "GLES2Trace::CreateStreamTextureCHROMIUM");
-  return gl_->CreateStreamTextureCHROMIUM(texture);
-}
-
 GLuint GLES2TraceImplementation::CreateImageCHROMIUM(ClientBuffer buffer,
                                                      GLsizei width,
                                                      GLsizei height,
diff --git a/gpu/command_buffer/client/gpu_control.h b/gpu/command_buffer/client/gpu_control.h
index c6e5871..0adf93a9 100644
--- a/gpu/command_buffer/client/gpu_control.h
+++ b/gpu/command_buffer/client/gpu_control.h
@@ -77,10 +77,6 @@
 
   virtual void SetSurfaceVisible(bool visible) = 0;
 
-  // Attaches an external stream to the texture given by |texture_id| and
-  // returns a stream identifier.
-  virtual uint32_t CreateStreamTexture(uint32_t texture_id) = 0;
-
   // Sets a lock this will be held on every callback from the GPU
   // implementation. This lock must be set and must be held on every call into
   // the GPU implementation if it is to be used from multiple threads. This
diff --git a/gpu/command_buffer/cmd_buffer_functions.txt b/gpu/command_buffer/cmd_buffer_functions.txt
index 50a2963..e31f1a8 100644
--- a/gpu/command_buffer/cmd_buffer_functions.txt
+++ b/gpu/command_buffer/cmd_buffer_functions.txt
@@ -272,7 +272,6 @@
 GL_APICALL void         GL_APIENTRY glGetUniformBlocksCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
 GL_APICALL void         GL_APIENTRY glGetTransformFeedbackVaryingsCHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
 GL_APICALL void         GL_APIENTRY glGetUniformsES3CHROMIUM (GLidProgram program, GLsizeiNotNegative bufsize, GLsizei* size, void* info);
-GL_APICALL GLuint       GL_APIENTRY glCreateStreamTextureCHROMIUM (GLuint texture);
 GL_APICALL GLuint       GL_APIENTRY glCreateImageCHROMIUM (ClientBuffer buffer, GLsizei width, GLsizei height, GLenum internalformat);
 GL_APICALL void         GL_APIENTRY glDestroyImageCHROMIUM (GLuint image_id);
 GL_APICALL GLuint       GL_APIENTRY glCreateGpuMemoryBufferImageCHROMIUM (GLsizei width, GLsizei height, GLenum internalformat, GLenum usage);
diff --git a/gpu/command_buffer/service/in_process_command_buffer.cc b/gpu/command_buffer/service/in_process_command_buffer.cc
index 3f22542..7cb6179 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.cc
+++ b/gpu/command_buffer/service/in_process_command_buffer.cc
@@ -951,19 +951,6 @@
 
 void InProcessCommandBuffer::SetSurfaceVisible(bool visible) {}
 
-uint32 InProcessCommandBuffer::CreateStreamTexture(uint32 texture_id) {
-  base::WaitableEvent completion(true, false);
-  uint32 stream_id = 0;
-  base::Callback<uint32(void)> task =
-      base::Bind(&InProcessCommandBuffer::CreateStreamTextureOnGpuThread,
-                 base::Unretained(this),
-                 texture_id);
-  QueueTask(
-      base::Bind(&RunTaskWithResult<uint32>, task, &stream_id, &completion));
-  completion.Wait();
-  return stream_id;
-}
-
 void InProcessCommandBuffer::SetLock(base::Lock*) {
 }
 
@@ -1082,6 +1069,18 @@
   DCHECK(stream_texture_manager_);
   return stream_texture_manager_->GetSurfaceTexture(stream_id);
 }
+
+uint32 InProcessCommandBuffer::CreateStreamTexture(uint32 texture_id) {
+  base::WaitableEvent completion(true, false);
+  uint32 stream_id = 0;
+  base::Callback<uint32(void)> task =
+      base::Bind(&InProcessCommandBuffer::CreateStreamTextureOnGpuThread,
+                 base::Unretained(this), texture_id);
+  QueueTask(
+      base::Bind(&RunTaskWithResult<uint32>, task, &stream_id, &completion));
+  completion.Wait();
+  return stream_id;
+}
 #endif
 
 GpuInProcessThread::GpuInProcessThread(SyncPointManager* sync_point_manager)
diff --git a/gpu/command_buffer/service/in_process_command_buffer.h b/gpu/command_buffer/service/in_process_command_buffer.h
index 0c881c1..abd6e7a6 100644
--- a/gpu/command_buffer/service/in_process_command_buffer.h
+++ b/gpu/command_buffer/service/in_process_command_buffer.h
@@ -125,7 +125,6 @@
                        const base::Closure& callback) override;
   void SignalQuery(uint32 query_id, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
-  uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
   bool IsGpuChannelLost() override;
   CommandBufferNamespace GetNamespaceID() const override;
@@ -177,6 +176,7 @@
 #if defined(OS_ANDROID)
   scoped_refptr<gfx::SurfaceTexture> GetSurfaceTexture(
       uint32 stream_id);
+  uint32 CreateStreamTexture(uint32 texture_id);
 #endif
 
  private:
diff --git a/gpu/command_buffer/tests/gl_manager.cc b/gpu/command_buffer/tests/gl_manager.cc
index e06e096b..0c351e8 100644
--- a/gpu/command_buffer/tests/gl_manager.cc
+++ b/gpu/command_buffer/tests/gl_manager.cc
@@ -492,11 +492,6 @@
   NOTIMPLEMENTED();
 }
 
-uint32 GLManager::CreateStreamTexture(uint32 texture_id) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
 void GLManager::SetLock(base::Lock*) {
   NOTIMPLEMENTED();
 }
diff --git a/gpu/command_buffer/tests/gl_manager.h b/gpu/command_buffer/tests/gl_manager.h
index 19c066a..6031bf6 100644
--- a/gpu/command_buffer/tests/gl_manager.h
+++ b/gpu/command_buffer/tests/gl_manager.h
@@ -129,7 +129,6 @@
                        const base::Closure& callback) override;
   void SignalQuery(uint32 query, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
-  uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
diff --git a/gpu/gles2_conform_support/egl/display.cc b/gpu/gles2_conform_support/egl/display.cc
index fb43272..b610ced 100644
--- a/gpu/gles2_conform_support/egl/display.cc
+++ b/gpu/gles2_conform_support/egl/display.cc
@@ -332,11 +332,6 @@
   NOTIMPLEMENTED();
 }
 
-uint32 Display::CreateStreamTexture(uint32 texture_id) {
-  NOTIMPLEMENTED();
-  return 0;
-}
-
 void Display::SetLock(base::Lock*) {
   NOTIMPLEMENTED();
 }
diff --git a/gpu/gles2_conform_support/egl/display.h b/gpu/gles2_conform_support/egl/display.h
index 1500903..b6e6bf6 100644
--- a/gpu/gles2_conform_support/egl/display.h
+++ b/gpu/gles2_conform_support/egl/display.h
@@ -95,7 +95,6 @@
                        const base::Closure& callback) override;
   void SignalQuery(uint32 query, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
-  uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
diff --git a/ios/build/bots/tests/common_tests.json b/ios/build/bots/tests/common_tests.json
index 4a63145..f5aca97 100644
--- a/ios/build/bots/tests/common_tests.json
+++ b/ios/build/bots/tests/common_tests.json
@@ -22,6 +22,9 @@
       "app": "ios_net_unittests"
     },
     {
+      "app": "ios_web_inttests"
+    },
+    {
       "app": "ios_web_unittests"
     },
     {
diff --git a/ios/ios.gyp b/ios/ios.gyp
index 116f26a..182ea6a 100644
--- a/ios/ios.gyp
+++ b/ios/ios.gyp
@@ -22,6 +22,7 @@
         'provider/ios_provider_web.gyp:*',
         'testing/ios_testing.gyp:*',
         'web/ios_web.gyp:*',
+        'web/ios_web_inttests.gyp:*',
         'web/ios_web_shell.gyp:*',
         'web/ios_web_unittests.gyp:*',
       ],
diff --git a/ios/web/BUILD.gn b/ios/web/BUILD.gn
index dc48fa08..3701f47 100644
--- a/ios/web/BUILD.gn
+++ b/ios/web/BUILD.gn
@@ -411,7 +411,6 @@
     "net/request_tracker_impl_unittest.mm",
     "net/web_http_protocol_handler_delegate_unittest.mm",
     "public/referrer_util_unittest.cc",
-    "public/test/http_server_unittest.mm",
     "string_util_unittest.cc",
     "test/crw_fake_web_controller_observer_unittest.mm",
     "test/run_all_unittests.cc",
diff --git a/ios/web/browser_state_web_view_partition_inttest.mm b/ios/web/browser_state_web_view_partition_inttest.mm
new file mode 100644
index 0000000..14a470c
--- /dev/null
+++ b/ios/web/browser_state_web_view_partition_inttest.mm
@@ -0,0 +1,198 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include <string>
+#import <WebKit/WebKit.h>
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/test/ios/wait_util.h"
+#include "ios/web/public/browser_state.h"
+#import "ios/web/public/test/http_server.h"
+#include "ios/web/public/test/response_providers/string_response_provider.h"
+#include "ios/web/public/test/web_test_util.h"
+#import "ios/web/public/web_view_creation_util.h"
+#import "ios/web/test/web_int_test.h"
+#import "ios/web/web_state/ui/web_view_js_utils.h"
+#import "net/base/mac/url_conversions.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+
+// A WKNavigationDelegate that is used to check if a WKWebView has finished
+// a navigation. Used for testing purposes.
+@interface TestNavigationDelegate : NSObject <WKNavigationDelegate>
+// YES if a navigation has finished.
+@property (nonatomic, assign) BOOL didFinishNavigation;
+@end
+
+@implementation TestNavigationDelegate
+
+@synthesize didFinishNavigation = _didFinishNavigation;
+
+- (void)webView:(WKWebView*)webView
+    didFinishNavigation:(WKNavigation*)navigation {
+  self.didFinishNavigation = YES;
+}
+
+@end
+
+// A test fixture for testing that browsing data is partitioned between
+// web views created with a non-OTR BrowserState and web views created with an
+// OTR BrowserState.
+class BrowserStateWebViewPartitionTest : public web::WebIntTest {
+ protected:
+  void SetUp() override {
+    CR_TEST_REQUIRES_WK_WEB_VIEW();
+    web::WebIntTest::SetUp();
+
+    otr_browser_state_.SetOffTheRecord(true);
+
+    web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance();
+    ASSERT_TRUE(server.IsRunning());
+
+    provider_.reset(new web::StringResponseProvider("Hello World"));
+    server.AddResponseProvider(provider_.get());
+  }
+
+  void TearDown() override {
+    CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+    web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance();
+    server.RemoveResponseProvider(provider_.release());
+
+    web::WebIntTest::TearDown();
+  }
+
+  // Runs the given JavaScript on |web_view| and returns the result as a string.
+  NSString* EvaluateJavaScript(WKWebView* web_view,
+                               NSString* js) {
+    __block base::scoped_nsobject<NSString> result;
+    __block bool block_was_called = false;
+    web::EvaluateJavaScript(web_view, js, ^(NSString* js_result, NSError*) {
+      result.reset([js_result copy]);
+      block_was_called = true;
+    });
+    base::test::ios::WaitUntilCondition(^bool {
+      return block_was_called;
+    });
+    return [[result copy] autorelease];
+  }
+
+  // Sets a persistent cookie with key, value on |web_view|.
+  void SetCookie(NSString* key, NSString* value, WKWebView* web_view) {
+    NSString* set_cookie = [NSString
+        stringWithFormat:@"document.cookie='%@=%@;"
+                         @"Expires=Tue, 05-May-9999 02:18:23 GMT; Path=/'",
+                         key, value];
+    EvaluateJavaScript(web_view, set_cookie);
+  }
+
+  // Returns a csv list of all cookies from |web_view|.
+  NSString* GetCookies(WKWebView* web_view) {
+    return EvaluateJavaScript(web_view, @"document.cookie");
+  }
+
+  // Sets a localstorage key, value pair on |web_view|.
+  void SetLocalStorageItem(NSString* key,
+                           NSString* value,
+                           WKWebView* web_view) {
+    NSString* set_local_storage_item = [NSString
+        stringWithFormat:@"localStorage.setItem('%@', '%@')", key, value];
+    EvaluateJavaScript(web_view, set_local_storage_item);
+  }
+
+  // Returns the localstorage value associated with |key| from |web_view|.
+  NSString* GetLocalStorageItem(NSString* key, WKWebView* web_view) {
+    NSString* get_local_storage_value =
+        [NSString stringWithFormat:@"localStorage.getItem('%@');", key];
+    return EvaluateJavaScript(web_view, get_local_storage_value);
+  }
+
+  // Loads a test web page (that contains a small string) in |web_view| and
+  // waits until the web view has finished the navigation.
+  void LoadTestWebPage(WKWebView* web_view) {
+    DCHECK(web_view);
+
+    base::scoped_nsobject<TestNavigationDelegate> navigation_delegate(
+        [[TestNavigationDelegate alloc] init]);
+
+    id old_navigation_delegate = web_view.navigationDelegate;
+    web_view.navigationDelegate = navigation_delegate;
+
+    web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance();
+    ASSERT_TRUE(server.IsRunning());
+
+    NSURL* url = net::NSURLWithGURL(server.MakeUrl("http://whatever/"));
+    [web_view loadRequest:[NSURLRequest requestWithURL:url]];
+    base::test::ios::WaitUntilCondition(^bool {
+      return [navigation_delegate didFinishNavigation];
+    });
+
+    web_view.navigationDelegate = old_navigation_delegate;
+  }
+
+  // Returns the BrowserState that is used for testing.
+  web::BrowserState* GetOtrBrowserState() { return &otr_browser_state_; }
+
+ private:
+  // The ResponseProvider used to load a simple web page.
+  scoped_ptr<web::ResponseProvider> provider_;
+  // The OTR browser state used in tests.
+  web::TestBrowserState otr_browser_state_;
+};
+
+// Tests that cookies are partitioned between web views created with a
+// non-OTR BrowserState and an OTR BrowserState.
+TEST_F(BrowserStateWebViewPartitionTest, Cookies) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  base::scoped_nsobject<WKWebView> web_view_1(
+      web::CreateWKWebView(CGRectZero, GetBrowserState()));
+  LoadTestWebPage(web_view_1);
+  SetCookie(@"someCookieName1", @"someCookieValue1", web_view_1);
+  EXPECT_NSEQ(@"someCookieName1=someCookieValue1", GetCookies(web_view_1));
+
+  base::scoped_nsobject<WKWebView> web_view_2(
+      web::CreateWKWebView(CGRectZero, GetOtrBrowserState()));
+  LoadTestWebPage(web_view_2);
+
+  // Test that the cookie has not leaked over to |web_view_2|.
+  EXPECT_NSEQ(@"", GetCookies(web_view_2));
+
+  SetCookie(@"someCookieName2", @"someCookieValue2", web_view_2);
+  EXPECT_NSEQ(@"someCookieName2=someCookieValue2", GetCookies(web_view_2));
+
+  // Test that the cookie has not leaked over to |web_view_1|.
+  NSString* cookies = GetCookies(web_view_1);
+  EXPECT_FALSE([cookies containsString:@"someCookieName2"]);
+}
+
+// Tests that localStorage is partitioned between web views created with a
+// non-OTR BrowserState and an OTR BrowserState.
+TEST_F(BrowserStateWebViewPartitionTest, LocalStorage) {
+  CR_TEST_REQUIRES_WK_WEB_VIEW();
+
+  base::scoped_nsobject<WKWebView> web_view_1(
+      web::CreateWKWebView(CGRectZero, GetBrowserState()));
+  LoadTestWebPage(web_view_1);
+  SetLocalStorageItem(@"someKey1", @"someValue1", web_view_1);
+  EXPECT_NSEQ(@"someValue1", GetLocalStorageItem(@"someKey1", web_view_1));
+
+  base::scoped_nsobject<WKWebView> web_view_2(
+      web::CreateWKWebView(CGRectZero, GetOtrBrowserState()));
+  LoadTestWebPage(web_view_2);
+
+  // Test that LocalStorage has not leaked over to |web_view_2|.
+  EXPECT_NSEQ(@"", GetLocalStorageItem(@"someKey1", web_view_2));
+
+  SetLocalStorageItem(@"someKey2", @"someValue2", web_view_2);
+  // Due to platform limitation, it's not possible to actually set localStorage
+  // item on an OTR BrowserState. Therefore, it's not possible to verify that a
+  // localStorage item has been correctly set.
+  // Look at
+  // http://stackoverflow.com/questions/14555347/html5-localstorage-error-with-safari-quota-exceeded-err-dom-exception-22-an
+  // for more details.
+  // Test that LocalStorage has not leaked over to |web_view_1|.
+  EXPECT_NSEQ(@"", GetLocalStorageItem(@"someKey2", web_view_1));
+}
diff --git a/ios/web/ios_web.gyp b/ios/web/ios_web.gyp
index 25491a67..7d29a00 100644
--- a/ios/web/ios_web.gyp
+++ b/ios/web/ios_web.gyp
@@ -459,6 +459,8 @@
         'public/test/response_providers/file_based_response_provider_impl.h',
         'public/test/response_providers/response_provider.cc',
         'public/test/response_providers/response_provider.h',
+        'public/test/response_providers/string_response_provider.h',
+        'public/test/response_providers/string_response_provider.mm',
         'public/test/test_browser_state.cc',
         'public/test/test_browser_state.h',
         'public/test/test_web_client.h',
@@ -472,6 +474,8 @@
         'public/test/web_test_util.h',
         'test/crw_fake_web_controller_observer.h',
         'test/crw_fake_web_controller_observer.mm',
+        'test/web_int_test.h',
+        'test/web_int_test.mm',
         'test/test_web_thread.cc',
         'test/test_web_thread_bundle.cc',
         'test/web_test.h',
diff --git a/ios/web/ios_web_inttests.gyp b/ios/web/ios_web_inttests.gyp
new file mode 100644
index 0000000..771e2e7
--- /dev/null
+++ b/ios/web/ios_web_inttests.gyp
@@ -0,0 +1,28 @@
+# Copyright 2015 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+{
+  'variables': {
+    'chromium_code': 1,
+  },
+  'targets': [
+    {
+      'target_name': 'ios_web_inttests',
+      'type': '<(gtest_target_type)',
+      'dependencies': [
+        '../../base/base.gyp:base',
+        '../../base/base.gyp:test_support_base',
+        '../../net/net.gyp:net_test_support',
+        '../../testing/gtest.gyp:gtest',
+        '../../ui/base/ui_base.gyp:ui_base_test_support',
+        'ios_web.gyp:ios_web',
+        'ios_web.gyp:ios_web_test_support',
+      ],
+      'sources': [
+        'browser_state_web_view_partition_inttest.mm',
+        'public/test/http_server_inttest.mm',
+        'test/run_all_unittests.cc',
+      ],
+    },
+  ],
+}
diff --git a/ios/web/ios_web_unittests.gyp b/ios/web/ios_web_unittests.gyp
index db23ec1f..ddca72ad 100644
--- a/ios/web/ios_web_unittests.gyp
+++ b/ios/web/ios_web_unittests.gyp
@@ -47,7 +47,6 @@
         'net/request_tracker_impl_unittest.mm',
         'net/web_http_protocol_handler_delegate_unittest.mm',
         'public/referrer_util_unittest.cc',
-        'public/test/http_server_unittest.mm',
         'string_util_unittest.cc',
         'test/crw_fake_web_controller_observer_unittest.mm',
         'test/run_all_unittests.cc',
diff --git a/ios/web/public/test/http_server_inttest.mm b/ios/web/public/test/http_server_inttest.mm
new file mode 100644
index 0000000..faf7d66
--- /dev/null
+++ b/ios/web/public/test/http_server_inttest.mm
@@ -0,0 +1,50 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/public/test/http_server.h"
+
+#import <Foundation/Foundation.h>
+#include <string>
+
+#import "base/mac/scoped_nsobject.h"
+#include "base/memory/scoped_ptr.h"
+#include "base/strings/sys_string_conversions.h"
+#import "base/test/ios/wait_util.h"
+#include "ios/web/public/test/response_providers/string_response_provider.h"
+#import "ios/web/test/web_int_test.h"
+#import "net/base/mac/url_conversions.h"
+#include "net/http/http_response_headers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "testing/gtest_mac.h"
+
+// A test fixture for verifying the behavior of web::test::HttpServer.
+typedef web::WebIntTest HttpServerTest;
+
+// Tests that a web::test::HttpServer can be started and can send and receive
+// requests and response from |TestResponseProvider|.
+TEST_F(HttpServerTest, StartAndInterfaceWithResponseProvider) {
+  const std::string kHelloWorld = "Hello World";
+  scoped_ptr<web::StringResponseProvider> provider(
+      new web::StringResponseProvider(kHelloWorld));
+
+  web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance();
+  ASSERT_TRUE(server.IsRunning());
+  server.AddResponseProvider(provider.release());
+
+  __block base::scoped_nsobject<NSString> page_result;
+  id completion_handler =
+      ^(NSData* data, NSURLResponse* response, NSError* error) {
+          page_result.reset([[NSString alloc]
+              initWithData:data encoding:NSUTF8StringEncoding]);
+      };
+  NSURL* url = net::NSURLWithGURL(server.MakeUrl("http://whatever"));
+  NSURLSessionDataTask* data_task =
+      [[NSURLSession sharedSession] dataTaskWithURL:url
+                                  completionHandler:completion_handler];
+  [data_task resume];
+  base::test::ios::WaitUntilCondition(^bool() {
+    return page_result;
+  });
+  EXPECT_NSEQ(page_result, base::SysUTF8ToNSString(kHelloWorld));
+}
diff --git a/ios/web/public/test/http_server_unittest.mm b/ios/web/public/test/http_server_unittest.mm
deleted file mode 100644
index a2cd7ed4..0000000
--- a/ios/web/public/test/http_server_unittest.mm
+++ /dev/null
@@ -1,80 +0,0 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#import "ios/web/public/test/http_server.h"
-
-#import <Foundation/Foundation.h>
-
-#include <string>
-
-#import "base/ios/ios_util.h"
-#import "base/mac/scoped_nsobject.h"
-#include "base/memory/ref_counted.h"
-#include "base/memory/scoped_ptr.h"
-#include "base/strings/sys_string_conversions.h"
-#import "base/test/ios/wait_util.h"
-#include "ios/web/public/test/response_providers/data_response_provider.h"
-#include "net/http/http_response_headers.h"
-#include "testing/gtest/include/gtest/gtest.h"
-#include "testing/gtest_mac.h"
-
-namespace {
-
-// A response provider that returns a simple string for all requests. Used for
-// testing purposes.
-class TestResponseProvider : public web::DataResponseProvider {
- public:
-  bool CanHandleRequest(const Request& request) override {
-    return true;
-  }
-
-  void GetResponseHeadersAndBody(
-      const Request& request,
-      scoped_refptr<net::HttpResponseHeaders>* headers,
-      std::string* response_body) override {
-    *headers = GetDefaultResponseHeaders();
-    *response_body = response_body_;
-  }
-  // The string that is returned in the response body.
-  std::string response_body_;
-};
-
-}  // namespace
-
-// Tests that a web::test::HttpServer can be started and can send and receive
-// requests and response from |TestResponseProvider|
-TEST(HTTPServer, StartAndInterfaceWithResponseProvider) {
-  // Disabled on iOS 9 as it fails with App Transport Security error.
-  // Tracked by http://crbug.com/516600 issue.
-  if (base::ios::IsRunningOnIOS9OrLater())
-    return;
-
-  scoped_ptr<TestResponseProvider> provider(new TestResponseProvider());
-  const std::string kHelloWorld = "Hello World";
-  provider->response_body_ = kHelloWorld;
-  web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance();
-  const NSUInteger kPort = 8080;
-  server.StartOnPort(kPort);
-  EXPECT_TRUE(server.IsRunning());
-  server.AddResponseProvider(provider.release());
-
-  NSString* url =
-      [NSString stringWithFormat:@"http://localhost:%@/samp", @(kPort)];
-  __block base::scoped_nsobject<NSString> evaluation_result;
-  id completion_handler =
-      ^(NSData* data, NSURLResponse* response, NSError* error) {
-          evaluation_result.reset([[NSString alloc]
-              initWithData:data encoding:NSUTF8StringEncoding]);
-      };
-  NSURLSessionDataTask* data_task =
-      [[NSURLSession sharedSession] dataTaskWithURL:[NSURL URLWithString:url]
-                                  completionHandler:completion_handler];
-  [data_task resume];
-  base::test::ios::WaitUntilCondition(^bool() {
-    return evaluation_result;
-  });
-  EXPECT_NSEQ(evaluation_result, base::SysUTF8ToNSString(kHelloWorld));
-  server.Stop();
-  EXPECT_FALSE(server.IsRunning());
-}
diff --git a/ios/web/public/test/response_providers/string_response_provider.h b/ios/web/public/test/response_providers/string_response_provider.h
new file mode 100644
index 0000000..c3e985c
--- /dev/null
+++ b/ios/web/public/test/response_providers/string_response_provider.h
@@ -0,0 +1,36 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_PUBLIC_TEST_RESPONSE_PROVIDERS_STRING_RESPONSE_PROVIDER_
+#define IOS_WEB_PUBLIC_TEST_RESPONSE_PROVIDERS_STRING_RESPONSE_PROVIDER_
+
+#include <string>
+
+#include "base/macros.h"
+#include "ios/web/public/test/response_providers/data_response_provider.h"
+
+namespace web {
+
+// A response provider that returns a  string for all requests. Used for testing
+// purposes.
+class StringResponseProvider : public web::DataResponseProvider {
+ public:
+  explicit StringResponseProvider(const std::string& response_body);
+
+  // web::DataResponseProvider methods.
+  bool CanHandleRequest(const Request& request) override;
+  void GetResponseHeadersAndBody(
+      const Request& request,
+      scoped_refptr<net::HttpResponseHeaders>* headers,
+      std::string* response_body) override;
+
+ private:
+  // The string that is returned in the response body.
+  std::string response_body_;
+  DISALLOW_COPY_AND_ASSIGN(StringResponseProvider);
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_PUBLIC_TEST_RESPONSE_PROVIDERS_STRING_RESPONSE_PROVIDER_
diff --git a/ios/web/public/test/response_providers/string_response_provider.mm b/ios/web/public/test/response_providers/string_response_provider.mm
new file mode 100644
index 0000000..85756529
--- /dev/null
+++ b/ios/web/public/test/response_providers/string_response_provider.mm
@@ -0,0 +1,24 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "ios/web/public/test/response_providers/string_response_provider.h"
+
+namespace web {
+
+StringResponseProvider::StringResponseProvider(const std::string& response_body)
+    : response_body_(response_body) {}
+
+bool StringResponseProvider::CanHandleRequest(const Request& request) {
+  return true;
+}
+
+void StringResponseProvider::GetResponseHeadersAndBody(
+    const Request& request,
+    scoped_refptr<net::HttpResponseHeaders>* headers,
+    std::string* response_body) {
+  *headers = GetDefaultResponseHeaders();
+  *response_body = response_body_;
+}
+
+}  // namespace web
diff --git a/ios/web/test/web_int_test.h b/ios/web/test/web_int_test.h
new file mode 100644
index 0000000..dc4e87446
--- /dev/null
+++ b/ios/web/test/web_int_test.h
@@ -0,0 +1,34 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef IOS_WEB_TEST_WEB_INT_TEST_H_
+#define IOS_WEB_TEST_WEB_INT_TEST_H_
+
+#import <WebKit/WebKit.h>
+
+#include "ios/web/test/web_test.h"
+
+namespace web {
+
+// A test fixture for integration tests that need to bring up the HttpServer.
+class WebIntTest : public WebTest {
+ protected:
+  WebIntTest();
+  ~WebIntTest() override;
+
+  // WebTest methods.
+  void SetUp() override;
+  void TearDown() override;
+
+  // Synchronously removes data from |data_store|.
+  // |websiteDataTypes| is from the constants defined in
+  // "WebKit/WKWebsiteDataRecord".
+  void RemoveWKWebViewCreatedData(WKWebsiteDataStore* data_store,
+                                  NSSet* websiteDataTypes);
+
+};
+
+}  // namespace web
+
+#endif  // IOS_WEB_TEST_WEB_TEST_H_
diff --git a/ios/web/test/web_int_test.mm b/ios/web/test/web_int_test.mm
new file mode 100644
index 0000000..cbfeaa7
--- /dev/null
+++ b/ios/web/test/web_int_test.mm
@@ -0,0 +1,79 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#import "ios/web/test/web_int_test.h"
+
+#include "base/ios/block_types.h"
+
+#include "base/test/ios/wait_util.h"
+#import "ios/web/public/test/http_server.h"
+#import "ios/web/public/web_view_creation_util.h"
+
+namespace web {
+
+WebIntTest::WebIntTest() {}
+WebIntTest::~WebIntTest() {}
+
+void WebIntTest::SetUp() {
+  WebTest::SetUp();
+
+  web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance();
+  ASSERT_FALSE(server.IsRunning());
+  server.StartOrDie();
+
+
+  if (IsWKWebViewSupported()) {
+    RemoveWKWebViewCreatedData([WKWebsiteDataStore defaultDataStore],
+                               [WKWebsiteDataStore allWebsiteDataTypes]);
+  }
+}
+
+void WebIntTest::TearDown() {
+  if (IsWKWebViewSupported()) {
+    RemoveWKWebViewCreatedData([WKWebsiteDataStore defaultDataStore],
+                               [WKWebsiteDataStore allWebsiteDataTypes]);
+  }
+
+  web::test::HttpServer& server = web::test::HttpServer::GetSharedInstance();
+  server.Stop();
+  EXPECT_FALSE(server.IsRunning());
+
+  WebTest::TearDown();
+}
+
+void WebIntTest::RemoveWKWebViewCreatedData(WKWebsiteDataStore* data_store,
+                                            NSSet* websiteDataTypes) {
+  __block bool data_removed = false;
+
+  ProceduralBlock remove_data = ^{
+    [data_store removeDataOfTypes:websiteDataTypes
+                    modifiedSince:[NSDate distantPast]
+                completionHandler:^{
+                  data_removed = true;
+                }];
+  };
+
+  if ([websiteDataTypes containsObject:WKWebsiteDataTypeCookies]) {
+    // TODO(crbug.com/554225): This approach of creating a WKWebView and
+    // executing JS to clear cookies is a workaround for
+    // https://bugs.webkit.org/show_bug.cgi?id=149078.
+    // Remove this, when that bug is fixed. The |markerWKWebView| will be
+    // released when cookies have been cleared.
+    WKWebView* marker_web_view =
+        web::CreateWKWebView(CGRectZero, GetBrowserState());
+    [marker_web_view evaluateJavaScript:@""
+                      completionHandler:^(id, NSError*) {
+                        [marker_web_view release];
+                        remove_data();
+                      }];
+  } else {
+    remove_data();
+  }
+
+  base::test::ios::WaitUntilCondition(^bool {
+    return data_removed;
+  });
+}
+
+}  // namespace web
diff --git a/mandoline/ui/desktop_ui/BUILD.gn b/mandoline/ui/desktop_ui/BUILD.gn
index 663e40b..e84c565 100644
--- a/mandoline/ui/desktop_ui/BUILD.gn
+++ b/mandoline/ui/desktop_ui/BUILD.gn
@@ -50,7 +50,7 @@
     "//ui/gfx/geometry",
     "//ui/mojo/init",
     "//ui/views",
-    "//ui/views/mus",
+    "//ui/views/mus:for_mojo_application",
     "//url",
   ]
 }
diff --git a/mandoline/ui/omnibox/BUILD.gn b/mandoline/ui/omnibox/BUILD.gn
index d28d989..d3d87bf6 100644
--- a/mandoline/ui/omnibox/BUILD.gn
+++ b/mandoline/ui/omnibox/BUILD.gn
@@ -37,6 +37,6 @@
     "//ui/gfx/geometry",
     "//ui/mojo/init",
     "//ui/views",
-    "//ui/views/mus",
+    "//ui/views/mus:for_mojo_application",
   ]
 }
diff --git a/mojo/gles2/command_buffer_client_impl.cc b/mojo/gles2/command_buffer_client_impl.cc
index 5aca7a4..c6990b26 100644
--- a/mojo/gles2/command_buffer_client_impl.cc
+++ b/mojo/gles2/command_buffer_client_impl.cc
@@ -362,12 +362,6 @@
   NOTIMPLEMENTED();
 }
 
-uint32_t CommandBufferClientImpl::CreateStreamTexture(uint32_t texture_id) {
-  // TODO(piman)
-  NOTIMPLEMENTED();
-  return 0;
-}
-
 void CommandBufferClientImpl::DidLoseContext(int32_t lost_reason) {
   last_state_.error = gpu::error::kLostContext;
   last_state_.context_lost_reason =
diff --git a/mojo/gles2/command_buffer_client_impl.h b/mojo/gles2/command_buffer_client_impl.h
index b0ce5706..c1e4231 100644
--- a/mojo/gles2/command_buffer_client_impl.h
+++ b/mojo/gles2/command_buffer_client_impl.h
@@ -72,7 +72,6 @@
                        const base::Closure& callback) override;
   void SignalQuery(uint32 query, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
-  uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.cc b/mojo/gpu/mojo_gles2_impl_autogen.cc
index 2413ba8..0e58f73 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.cc
+++ b/mojo/gpu/mojo_gles2_impl_autogen.cc
@@ -1447,10 +1447,6 @@
                                            void* info) {
   NOTREACHED() << "Unimplemented GetUniformsES3CHROMIUM.";
 }
-GLuint MojoGLES2Impl::CreateStreamTextureCHROMIUM(GLuint texture) {
-  MojoGLES2MakeCurrent(context_);
-  return glCreateStreamTextureCHROMIUM(texture);
-}
 GLuint MojoGLES2Impl::CreateImageCHROMIUM(ClientBuffer buffer,
                                           GLsizei width,
                                           GLsizei height,
diff --git a/mojo/gpu/mojo_gles2_impl_autogen.h b/mojo/gpu/mojo_gles2_impl_autogen.h
index c0b1c86..19ad386 100644
--- a/mojo/gpu/mojo_gles2_impl_autogen.h
+++ b/mojo/gpu/mojo_gles2_impl_autogen.h
@@ -668,7 +668,6 @@
                               GLsizei bufsize,
                               GLsizei* size,
                               void* info) override;
-  GLuint CreateStreamTextureCHROMIUM(GLuint texture) override;
   GLuint CreateImageCHROMIUM(ClientBuffer buffer,
                              GLsizei width,
                              GLsizei height,
diff --git a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
index 576a322..4a6d4ba0 100644
--- a/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
+++ b/mojo/public/c/gles2/gles2_call_visitor_chromium_extension_autogen.h
@@ -153,7 +153,6 @@
               void,
               (GLuint program, GLsizei bufsize, GLsizei* size, void* info),
               (program, bufsize, size, info))
-VISIT_GL_CALL(CreateStreamTextureCHROMIUM, GLuint, (GLuint texture), (texture))
 VISIT_GL_CALL(
     CreateImageCHROMIUM,
     GLuint,
diff --git a/mojo/runner/child/BUILD.gn b/mojo/runner/child/BUILD.gn
index 028c1d72..e10de5e 100644
--- a/mojo/runner/child/BUILD.gn
+++ b/mojo/runner/child/BUILD.gn
@@ -23,7 +23,6 @@
     ":interfaces",
     "//base",
     "//mojo/application/public/interfaces",
-    "//mojo/gles2",
     "//mojo/message_pump",
     "//mojo/platform_handle:platform_handle_impl",
     "//third_party/mojo/src/mojo/edk/system",
diff --git a/mojo/shell/application_manager.cc b/mojo/shell/application_manager.cc
index d011049..facade7 100644
--- a/mojo/shell/application_manager.cc
+++ b/mojo/shell/application_manager.cc
@@ -122,6 +122,9 @@
   // Instances created by others are considered unique, and thus have no
   // identity. As such they cannot be connected to by anyone else, and so we
   // never call ConnectToClient().
+  // TODO(beng): GetPermissiveCapabilityFilter() here obviously cannot make it
+  //             to production. See note in application_manager.mojom.
+  //             http://crbug.com/555392
   Identity target_id(url, qualifier, GetPermissiveCapabilityFilter());
   InterfaceRequest<Application> application_request =
       CreateInstance(target_id, base::Closure(), nullptr);
diff --git a/mojo/shell/application_manager.mojom b/mojo/shell/application_manager.mojom
index 3132da6c..5ba9416 100644
--- a/mojo/shell/application_manager.mojom
+++ b/mojo/shell/application_manager.mojom
@@ -11,5 +11,10 @@
   // channel to an implementation of ChildController and bind an Application
   // request there.
   // TODO(beng): we should probably have an Identity mojom struct.
+  // TODO(beng): for this to be used in production, it's going to have to take
+  //             a fully qualified Identity complete with CapabilityFilter,
+  //             otherwise child processes registered with the shell will be
+  //             able to request any application/service.
+  //             http://crbug.com/555392
   CreateInstanceForHandle(handle channel, string url, string qualifier);
 };
diff --git a/mojo/shell/application_manager_apptest_driver.cc b/mojo/shell/application_manager_apptest_driver.cc
index 06f2fad..51766cc 100644
--- a/mojo/shell/application_manager_apptest_driver.cc
+++ b/mojo/shell/application_manager_apptest_driver.cc
@@ -25,7 +25,6 @@
 #include "mojo/shell/application_manager_apptests.mojom.h"
 #include "third_party/mojo/src/mojo/edk/embedder/embedder.h"
 #include "third_party/mojo/src/mojo/edk/embedder/platform_channel_pair.h"
-#include "third_party/mojo/src/mojo/edk/embedder/process_delegate.h"
 #include "third_party/mojo/src/mojo/edk/embedder/scoped_platform_handle.h"
 
 using mojo::shell::test::mojom::Driver;
@@ -97,7 +96,8 @@
   #endif
     target_ = base::LaunchProcess(child_command_line, options);
   }
-  bool ConfigureIncomingConnection(mojo::ApplicationConnection* connection) {
+  bool ConfigureIncomingConnection(
+      mojo::ApplicationConnection* connection) override {
     connection->AddService<Driver>(this);
     return true;
   }
@@ -117,9 +117,9 @@
   void DidCreateChannel(mojo::embedder::ChannelInfo* channel_info) {}
 
   mojo::ApplicationImpl* app_;
-  base::WeakPtrFactory<TargetApplicationDelegate> weak_factory_;
   base::Process target_;
   mojo::WeakBindingSet<Driver> bindings_;
+  base::WeakPtrFactory<TargetApplicationDelegate> weak_factory_;
 
   DISALLOW_COPY_AND_ASSIGN(TargetApplicationDelegate);
 };
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.cc b/ppapi/proxy/ppapi_command_buffer_proxy.cc
index 789bb63..f999b733 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.cc
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.cc
@@ -170,11 +170,6 @@
       ppapi::API_ID_PPB_GRAPHICS_3D, resource_, id));
 }
 
-uint32 PpapiCommandBufferProxy::CreateStreamTexture(uint32 texture_id) {
-  NOTREACHED();
-  return 0;
-}
-
 void PpapiCommandBufferProxy::SetLock(base::Lock*) {
   NOTIMPLEMENTED();
 }
diff --git a/ppapi/proxy/ppapi_command_buffer_proxy.h b/ppapi/proxy/ppapi_command_buffer_proxy.h
index 3692c1b..072d91d 100644
--- a/ppapi/proxy/ppapi_command_buffer_proxy.h
+++ b/ppapi/proxy/ppapi_command_buffer_proxy.h
@@ -65,7 +65,6 @@
                        const base::Closure& callback) override;
   void SignalQuery(uint32 query, const base::Closure& callback) override;
   void SetSurfaceVisible(bool visible) override;
-  uint32 CreateStreamTexture(uint32 texture_id) override;
   void SetLock(base::Lock*) override;
   bool IsGpuChannelLost() override;
   gpu::CommandBufferNamespace GetNamespaceID() const override;
diff --git a/skia/config/SkUserConfig.h b/skia/config/SkUserConfig.h
index b7260d8..b60d29c 100644
--- a/skia/config/SkUserConfig.h
+++ b/skia/config/SkUserConfig.h
@@ -218,6 +218,10 @@
 #   define SK_IGNORE_ETC1_SUPPORT
 #endif
 
+#ifndef    SK_SUPPORT_LEGACY_LINEAR_GRADIENT_TABLE
+#   define SK_SUPPORT_LEGACY_LINEAR_GRADIENT_TABLE
+#endif
+
 #ifndef    SK_IGNORE_GPU_DITHER
 #   define SK_IGNORE_GPU_DITHER
 #endif
diff --git a/storage/browser/fileapi/async_file_util_adapter.cc b/storage/browser/fileapi/async_file_util_adapter.cc
index ed8f84f..0de0f611 100644
--- a/storage/browser/fileapi/async_file_util_adapter.cc
+++ b/storage/browser/fileapi/async_file_util_adapter.cc
@@ -116,8 +116,6 @@
     DirectoryEntry entry;
     entry.is_directory = file_enum->IsDirectory();
     entry.name = VirtualPath::BaseName(current).value();
-    entry.size = file_enum->Size();
-    entry.last_modified_time = file_enum->LastModifiedTime();
     entries.push_back(entry);
 
     if (entries.size() == kResultChunkSize) {
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job.cc b/storage/browser/fileapi/file_system_dir_url_request_job.cc
index 4236fec..ac2118a 100644
--- a/storage/browser/fileapi/file_system_dir_url_request_job.cc
+++ b/storage/browser/fileapi/file_system_dir_url_request_job.cc
@@ -143,15 +143,52 @@
     data_.append(net::GetDirectoryListingHeader(title));
   }
 
-  typedef std::vector<DirectoryEntry>::const_iterator EntryIterator;
-  for (EntryIterator it = entries.begin(); it != entries.end(); ++it) {
-    const base::string16& name = base::FilePath(it->name).LossyDisplayName();
-    data_.append(net::GetDirectoryListingEntry(
-        name, std::string(), it->is_directory, it->size,
-        it->last_modified_time));
-  }
+  entries_.insert(entries_.end(), entries.begin(), entries.end());
 
   if (!has_more) {
+    if (entries_.size()) {
+      GetMetadata(0);
+    } else {
+      set_expected_content_size(data_.size());
+      NotifyHeadersComplete();
+    }
+  }
+}
+
+void FileSystemDirURLRequestJob::GetMetadata(size_t index) {
+  const DirectoryEntry& entry = entries_[index];
+  const FileSystemURL url = file_system_context_->CreateCrackedFileSystemURL(
+      url_.origin(), url_.type(),
+      url_.path().Append(base::FilePath(entry.name)));
+  DCHECK(url.is_valid());
+  file_system_context_->operation_runner()->GetMetadata(
+      url,
+      base::Bind(&FileSystemDirURLRequestJob::DidGetMetadata, this, index));
+}
+
+void FileSystemDirURLRequestJob::DidGetMetadata(
+    size_t index,
+    base::File::Error result,
+    const base::File::Info& file_info) {
+  if (result != base::File::FILE_OK) {
+    int rv = net::ERR_FILE_NOT_FOUND;
+    if (result == base::File::FILE_ERROR_INVALID_URL)
+      rv = net::ERR_INVALID_URL;
+    NotifyDone(URLRequestStatus(URLRequestStatus::FAILED, rv));
+  }
+
+  if (!request_)
+    return;
+
+  const DirectoryEntry& entry = entries_[index];
+  const base::string16& name = base::FilePath(entry.name).LossyDisplayName();
+  data_.append(net::GetDirectoryListingEntry(name, std::string(),
+                                             entry.is_directory, file_info.size,
+                                             file_info.last_modified));
+
+  if (index < entries_.size() - 1) {
+    GetMetadata(index + 1);
+  } else {
     set_expected_content_size(data_.size());
     NotifyHeadersComplete();
   }
diff --git a/storage/browser/fileapi/file_system_dir_url_request_job.h b/storage/browser/fileapi/file_system_dir_url_request_job.h
index 0163535..01bd372 100644
--- a/storage/browser/fileapi/file_system_dir_url_request_job.h
+++ b/storage/browser/fileapi/file_system_dir_url_request_job.h
@@ -51,6 +51,14 @@
                         const std::vector<DirectoryEntry>& entries,
                         bool has_more);
 
+  // Reads metadata for the |index|-th entry in the directory. Must be called
+  // after |entries_| is filled.
+  void GetMetadata(size_t index);
+  void DidGetMetadata(size_t index,
+                      base::File::Error result,
+                      const base::File::Info& file_info);
+
+  std::vector<DirectoryEntry> entries_;
   std::string data_;
   FileSystemURL url_;
   const std::string storage_domain_;
diff --git a/storage/common/fileapi/directory_entry.cc b/storage/common/fileapi/directory_entry.cc
index 477ede8..f972745 100644
--- a/storage/common/fileapi/directory_entry.cc
+++ b/storage/common/fileapi/directory_entry.cc
@@ -6,16 +6,10 @@
 
 namespace storage {
 
-DirectoryEntry::DirectoryEntry() : is_directory(false), size(0) {}
+DirectoryEntry::DirectoryEntry() : is_directory(false) {}
 
-DirectoryEntry::DirectoryEntry(const std::string& name,
-                               DirectoryEntryType type,
-                               int64 size,
-                               const base::Time& last_modified_time)
+DirectoryEntry::DirectoryEntry(const std::string& name, DirectoryEntryType type)
     : name(base::FilePath::FromUTF8Unsafe(name).value()),
-      is_directory(type == DIRECTORY),
-      size(size),
-      last_modified_time(last_modified_time) {
-}
+      is_directory(type == DIRECTORY) {}
 
 }  // namespace storage
diff --git a/storage/common/fileapi/directory_entry.h b/storage/common/fileapi/directory_entry.h
index 1b06828..fab7fae1 100644
--- a/storage/common/fileapi/directory_entry.h
+++ b/storage/common/fileapi/directory_entry.h
@@ -22,15 +22,10 @@
   };
 
   DirectoryEntry();
-  DirectoryEntry(const std::string& name,
-                 DirectoryEntryType type,
-                 int64 size,
-                 const base::Time& last_modified_time);
+  DirectoryEntry(const std::string& name, DirectoryEntryType type);
 
   base::FilePath::StringType name;
   bool is_directory;
-  int64 size;
-  base::Time last_modified_time;
 };
 
 }  // namespace storage
diff --git a/third_party/WebKit/Source/core/animation/InterpolationComponent.h b/third_party/WebKit/Source/core/animation/InterpolationComponent.h
index 9933c61f..5f812e3 100644
--- a/third_party/WebKit/Source/core/animation/InterpolationComponent.h
+++ b/third_party/WebKit/Source/core/animation/InterpolationComponent.h
@@ -19,7 +19,7 @@
         , nonInterpolableValue(nonInterpolableValue)
     { }
 
-    InterpolationComponent(const void* null) { ASSERT(null == 0); }
+    InterpolationComponent(std::nullptr_t) { }
 
     InterpolationComponent(InterpolationComponent&& other)
         : interpolableValue(other.interpolableValue.release())
@@ -41,7 +41,7 @@
         , nonInterpolableValue(nonInterpolableValue)
     { }
 
-    PairwiseInterpolationComponent(const void* null) { ASSERT(null == 0); }
+    PairwiseInterpolationComponent(std::nullptr_t) { }
 
     PairwiseInterpolationComponent(PairwiseInterpolationComponent&& other)
         : startInterpolableValue(other.startInterpolableValue.release())
diff --git a/third_party/WebKit/Source/core/page/Page.cpp b/third_party/WebKit/Source/core/page/Page.cpp
index 6fde3ad..2377b94 100644
--- a/third_party/WebKit/Source/core/page/Page.cpp
+++ b/third_party/WebKit/Source/core/page/Page.cpp
@@ -592,13 +592,6 @@
 
     mainFrame->detach(FrameDetachType::Remove);
 
-    if (mainFrame->isLocalFrame()) {
-        toLocalFrame(mainFrame.get())->setView(nullptr);
-    } else {
-        ASSERT(m_mainFrame->isRemoteFrame());
-        toRemoteFrame(mainFrame.get())->setView(nullptr);
-    }
-
     ASSERT(allPages().contains(this));
     allPages().remove(this);
     ordinaryPages().remove(this);
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
index f8a7c9e..6df7fc3 100644
--- a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
+++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
@@ -537,7 +537,7 @@
 }
 
 .sidebar-pane.composite .metrics {
-    height: 190px;
+    min-height: 190px;
     display: flex;
     flex-direction: column;
     -webkit-align-items: center;
diff --git a/third_party/WebKit/Source/devtools/front_end/emulated_devices/module.json b/third_party/WebKit/Source/devtools/front_end/emulated_devices/module.json
index 7668fb2a..e75f9738 100644
--- a/third_party/WebKit/Source/devtools/front_end/emulated_devices/module.json
+++ b/third_party/WebKit/Source/devtools/front_end/emulated_devices/module.json
@@ -331,6 +331,68 @@
         {
             "type": "emulated-device",
             "device": {
+                "title": "Google Nexus 5X",
+                "type": "phone",
+                "user-agent": "Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36",
+                "capabilities": [
+                    "touch",
+                    "mobile"
+                ],
+                "show-by-default": true,
+                "screen": {
+                    "device-pixel-ratio": 2.6,
+                    "vertical": {
+                        "width": 411,
+                        "height": 731
+                    },
+                    "horizontal": {
+                        "width": 731,
+                        "height": 411
+                    }
+                },
+                "modes": [
+                    {
+                        "title": "default",
+                        "orientation": "vertical",
+                        "insets": { "left": 0, "top": 25, "right": 0, "bottom": 48 },
+                        "image": "@url(google-nexus-5-vertical-default-1x.png) 1x, @url(google-nexus-5-vertical-default-2x.png) 2x"
+                    },
+                    {
+                        "title": "navigation bar",
+                        "orientation": "vertical",
+                        "insets": { "left": 0, "top": 80, "right": 0, "bottom": 48 },
+                        "image": "@url(google-nexus-5-vertical-navigation-1x.png) 1x, @url(google-nexus-5-vertical-navigation-2x.png) 2x"
+                    },
+                    {
+                        "title": "keyboard",
+                        "orientation": "vertical",
+                        "insets": { "left": 0, "top": 80, "right": 0, "bottom": 312 },
+                        "image": "@url(google-nexus-5-vertical-keyboard-1x.png) 1x, @url(google-nexus-5-vertical-keyboard-2x.png) 2x"
+                    },
+                    {
+                        "title": "default",
+                        "orientation": "horizontal",
+                        "insets": { "left": 0, "top": 25, "right": 42, "bottom": 0 },
+                        "image": "@url(google-nexus-5-horizontal-default-1x.png) 1x, @url(google-nexus-5-horizontal-default-2x.png) 2x"
+                    },
+                    {
+                        "title": "navigation bar",
+                        "orientation": "horizontal",
+                        "insets": { "left": 0, "top": 80, "right": 42, "bottom": 0 },
+                        "image": "@url(google-nexus-5-horizontal-navigation-1x.png) 1x, @url(google-nexus-5-horizontal-navigation-2x.png) 2x"
+                    },
+                    {
+                        "title": "keyboard",
+                        "orientation": "horizontal",
+                        "insets": { "left": 0, "top": 80, "right": 42, "bottom": 202 },
+                        "image": "@url(google-nexus-5-horizontal-keyboard-1x.png) 1x, @url(google-nexus-5-horizontal-keyboard-2x.png) 2x"
+                    }
+                ]
+            }
+        },
+        {
+            "type": "emulated-device",
+            "device": {
                 "show-by-default": true,
                 "title": "Google Nexus 6",
                 "screen": {
@@ -388,6 +450,62 @@
             "type": "emulated-device",
             "device": {
                 "show-by-default": true,
+                "title": "Google Nexus 6P",
+                "screen": {
+                    "horizontal": {
+                        "width": 773,
+                        "height": 435
+                    },
+                    "device-pixel-ratio": 3.3,
+                    "vertical": {
+                        "width": 435,
+                        "height": 773
+                    }
+                },
+                "capabilities": [
+                    "touch",
+                    "mobile"
+                ],
+                "user-agent": "Mozilla/5.0 (Linux; Android 5.1.1; Nexus 6 Build/LYZ28E) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/46.0.2490.76 Mobile Safari/537.36",
+                "type": "phone",
+                "modes": [
+                    {
+                        "title": "default",
+                        "orientation": "vertical",
+                        "insets": { "left": 0, "top": 25, "right": 0, "bottom": 48 }
+                    },
+                    {
+                        "title": "navigation bar",
+                        "orientation": "vertical",
+                        "insets": { "left": 0, "top": 80, "right": 0, "bottom": 48 }
+                    },
+                    {
+                        "title": "keyboard",
+                        "orientation": "vertical",
+                        "insets": { "left": 0, "top": 80, "right": 0, "bottom": 343 }
+                    },
+                    {
+                        "title": "default",
+                        "orientation": "horizontal",
+                        "insets": { "left": 0, "top": 25, "right": 42, "bottom": 0 }
+                    },
+                    {
+                        "title": "navigation bar",
+                        "orientation": "horizontal",
+                        "insets": { "left": 0, "top": 80, "right": 42, "bottom": 0 }
+                    },
+                    {
+                        "title": "keyboard",
+                        "orientation": "horizontal",
+                        "insets": { "left": 0, "top": 80, "right": 42, "bottom": 222 }
+                    }
+                ]
+            }
+        },
+        {
+            "type": "emulated-device",
+            "device": {
+                "show-by-default": true,
                 "title": "LG Optimus L70",
                 "screen": {
                     "horizontal": {
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js b/third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js
index bbafb62..7d31463e 100644
--- a/third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js
+++ b/third_party/WebKit/Source/devtools/front_end/sdk/SourceMap.js
@@ -122,6 +122,7 @@
             callback(new WebInspector.SourceMap(baseURL, payload));
         } catch(e) {
             console.error(e.message);
+            WebInspector.console.error("Failed to parse SourceMap: " + sourceMapURL);
             callback(null);
         }
     }
diff --git a/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtils.cpp b/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtils.cpp
index b9be8eb..fc1059e 100644
--- a/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtils.cpp
+++ b/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtils.cpp
@@ -146,7 +146,7 @@
 {
 }
 
-PassOwnPtrWillBeRawPtr<NavigatorContentUtils> NavigatorContentUtils::create(PassOwnPtr<NavigatorContentUtilsClient> client)
+PassOwnPtrWillBeRawPtr<NavigatorContentUtils> NavigatorContentUtils::create(PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClient> client)
 {
     return adoptPtrWillBeNoop(new NavigatorContentUtils(client));
 }
@@ -230,7 +230,7 @@
     return "NavigatorContentUtils";
 }
 
-void provideNavigatorContentUtilsTo(LocalFrame& frame, PassOwnPtr<NavigatorContentUtilsClient> client)
+void provideNavigatorContentUtilsTo(LocalFrame& frame, PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClient> client)
 {
     NavigatorContentUtils::provideTo(frame, NavigatorContentUtils::supplementName(), NavigatorContentUtils::create(client));
 }
diff --git a/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtils.h b/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtils.h
index bb09796..96bf9ba 100644
--- a/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtils.h
+++ b/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtils.h
@@ -53,20 +53,25 @@
     static String isProtocolHandlerRegistered(Navigator&, const String& scheme, const String& url, ExceptionState&);
     static void unregisterProtocolHandler(Navigator&, const String& scheme, const String& url, ExceptionState&);
 
-    static PassOwnPtrWillBeRawPtr<NavigatorContentUtils> create(PassOwnPtr<NavigatorContentUtilsClient>);
+    static PassOwnPtrWillBeRawPtr<NavigatorContentUtils> create(PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClient>);
 
-    DEFINE_INLINE_VIRTUAL_TRACE() { WillBeHeapSupplement<LocalFrame>::trace(visitor); }
+    DEFINE_INLINE_VIRTUAL_TRACE()
+    {
+        visitor->trace(m_client);
+        WillBeHeapSupplement<LocalFrame>::trace(visitor);
+    }
 
-    void setClientForTest(PassOwnPtr<NavigatorContentUtilsClient> client) { m_client = client; }
+    void setClientForTest(PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClient> client) { m_client = client; }
 
 private:
-    explicit NavigatorContentUtils(PassOwnPtr<NavigatorContentUtilsClient> client)
+    explicit NavigatorContentUtils(PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClient> client)
         : m_client(client)
-    { }
+    {
+    }
 
     NavigatorContentUtilsClient* client() { return m_client.get(); }
 
-    OwnPtr<NavigatorContentUtilsClient> m_client;
+    OwnPtrWillBeMember<NavigatorContentUtilsClient> m_client;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtilsClient.h b/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtilsClient.h
index cb044ecc..cd272dd 100644
--- a/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtilsClient.h
+++ b/third_party/WebKit/Source/modules/navigatorcontentutils/NavigatorContentUtilsClient.h
@@ -27,6 +27,7 @@
 #define NavigatorContentUtilsClient_h
 
 #include "modules/ModulesExport.h"
+#include "platform/heap/Handle.h"
 #include "platform/weborigin/KURL.h"
 #include "wtf/Allocator.h"
 #include "wtf/text/WTFString.h"
@@ -35,8 +36,8 @@
 
 class LocalFrame;
 
-class NavigatorContentUtilsClient {
-    USING_FAST_MALLOC(NavigatorContentUtilsClient);
+class NavigatorContentUtilsClient : public NoBaseWillBeGarbageCollectedFinalized<NavigatorContentUtilsClient> {
+    USING_FAST_MALLOC_WILL_BE_REMOVED(NavigatorContentUtilsClient);
 public:
     virtual ~NavigatorContentUtilsClient() { }
     virtual void registerProtocolHandler(const String& scheme, const KURL&, const String& title) = 0;
@@ -49,10 +50,12 @@
 
     virtual CustomHandlersState isProtocolHandlerRegistered(const String& scheme, const KURL&) = 0;
     virtual void unregisterProtocolHandler(const String& scheme, const KURL&) = 0;
+
+    DEFINE_INLINE_VIRTUAL_TRACE() { }
 };
 
-MODULES_EXPORT void provideNavigatorContentUtilsTo(LocalFrame&, PassOwnPtr<NavigatorContentUtilsClient>);
+MODULES_EXPORT void provideNavigatorContentUtilsTo(LocalFrame&, PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClient>);
 
-}
+} // namespace blink
 
 #endif // NavigatorContentUtilsClient_h
diff --git a/third_party/WebKit/Source/modules/navigatorcontentutils/testing/InternalsNavigatorContentUtils.cpp b/third_party/WebKit/Source/modules/navigatorcontentutils/testing/InternalsNavigatorContentUtils.cpp
index e1a30e9..dd9cd83 100644
--- a/third_party/WebKit/Source/modules/navigatorcontentutils/testing/InternalsNavigatorContentUtils.cpp
+++ b/third_party/WebKit/Source/modules/navigatorcontentutils/testing/InternalsNavigatorContentUtils.cpp
@@ -16,7 +16,7 @@
 {
     ASSERT(document && document->page());
     NavigatorContentUtils* navigatorContentUtils = NavigatorContentUtils::from(*document->frame());
-    navigatorContentUtils->setClientForTest(adoptPtr(new NavigatorContentUtilsClientMock()));
+    navigatorContentUtils->setClientForTest(NavigatorContentUtilsClientMock::create());
 }
 
 } // namespace blink
diff --git a/third_party/WebKit/Source/modules/navigatorcontentutils/testing/NavigatorContentUtilsClientMock.h b/third_party/WebKit/Source/modules/navigatorcontentutils/testing/NavigatorContentUtilsClientMock.h
index c3fed52..e863546 100644
--- a/third_party/WebKit/Source/modules/navigatorcontentutils/testing/NavigatorContentUtilsClientMock.h
+++ b/third_party/WebKit/Source/modules/navigatorcontentutils/testing/NavigatorContentUtilsClientMock.h
@@ -6,6 +6,7 @@
 #define NavigatorContentUtilsClientMock_h
 
 #include "modules/navigatorcontentutils/NavigatorContentUtilsClient.h"
+#include "platform/heap/Handle.h"
 #include "wtf/HashSet.h"
 #include "wtf/text/WTFString.h"
 
@@ -16,7 +17,11 @@
 // Provides a mock object for the navigatorcontentutils client.
 class NavigatorContentUtilsClientMock final : public NavigatorContentUtilsClient {
 public:
-    NavigatorContentUtilsClientMock() { }
+    static PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClientMock> create()
+    {
+        return adoptPtrWillBeNoop(new NavigatorContentUtilsClientMock);
+    }
+
     ~NavigatorContentUtilsClientMock() override { }
 
     virtual void registerProtocolHandler(const String& scheme, const KURL&, const String& title);
@@ -25,6 +30,8 @@
     virtual void unregisterProtocolHandler(const String& scheme, const KURL&);
 
 private:
+    NavigatorContentUtilsClientMock() { }
+
     typedef struct {
         String scheme;
         KURL url;
diff --git a/third_party/WebKit/Source/web/NavigatorContentUtilsClientImpl.cpp b/third_party/WebKit/Source/web/NavigatorContentUtilsClientImpl.cpp
index b6d513d..f8eaf41 100644
--- a/third_party/WebKit/Source/web/NavigatorContentUtilsClientImpl.cpp
+++ b/third_party/WebKit/Source/web/NavigatorContentUtilsClientImpl.cpp
@@ -10,9 +10,9 @@
 
 namespace blink {
 
-PassOwnPtr<NavigatorContentUtilsClientImpl> NavigatorContentUtilsClientImpl::create(WebLocalFrameImpl* webFrame)
+PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClientImpl> NavigatorContentUtilsClientImpl::create(WebLocalFrameImpl* webFrame)
 {
-    return adoptPtr(new NavigatorContentUtilsClientImpl(webFrame));
+    return adoptPtrWillBeNoop(new NavigatorContentUtilsClientImpl(webFrame));
 }
 
 NavigatorContentUtilsClientImpl::NavigatorContentUtilsClientImpl(WebLocalFrameImpl* webFrame)
@@ -20,6 +20,12 @@
 {
 }
 
+DEFINE_TRACE(NavigatorContentUtilsClientImpl)
+{
+    visitor->trace(m_webFrame);
+    NavigatorContentUtilsClient::trace(visitor);
+}
+
 void NavigatorContentUtilsClientImpl::registerProtocolHandler(const String& scheme, const KURL& url, const String& title)
 {
     m_webFrame->client()->registerProtocolHandler(scheme, url, title);
@@ -36,4 +42,3 @@
 }
 
 } // namespace blink
-
diff --git a/third_party/WebKit/Source/web/NavigatorContentUtilsClientImpl.h b/third_party/WebKit/Source/web/NavigatorContentUtilsClientImpl.h
index c2f6dd6..13a8e536 100644
--- a/third_party/WebKit/Source/web/NavigatorContentUtilsClientImpl.h
+++ b/third_party/WebKit/Source/web/NavigatorContentUtilsClientImpl.h
@@ -6,6 +6,7 @@
 #define NavigatorContentUtilsClientImpl_h
 
 #include "modules/navigatorcontentutils/NavigatorContentUtilsClient.h"
+#include "platform/heap/Handle.h"
 #include "platform/weborigin/KURL.h"
 
 namespace blink {
@@ -14,17 +15,19 @@
 
 class NavigatorContentUtilsClientImpl final : public NavigatorContentUtilsClient {
 public:
-    static PassOwnPtr<NavigatorContentUtilsClientImpl> create(WebLocalFrameImpl*);
+    static PassOwnPtrWillBeRawPtr<NavigatorContentUtilsClientImpl> create(WebLocalFrameImpl*);
     ~NavigatorContentUtilsClientImpl() override { }
 
     void registerProtocolHandler(const String& scheme, const KURL&, const String& title) override;
     CustomHandlersState isProtocolHandlerRegistered(const String& scheme, const KURL&) override;
     void unregisterProtocolHandler(const String& scheme, const KURL&) override;
 
+    DECLARE_VIRTUAL_TRACE();
+
 private:
     explicit NavigatorContentUtilsClientImpl(WebLocalFrameImpl*);
 
-    WebLocalFrameImpl* m_webFrame;
+    RawPtrWillBeMember<WebLocalFrameImpl> m_webFrame;
 };
 
 } // namespace blink
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py
index 232ab386..49d122b 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp.py
@@ -1723,7 +1723,7 @@
        location_description: Used to indicate where the type is. This is either 'parameter' or 'return'.
        error: The function to call with any errors found.
     """
-    match_ref_or_own_ptr = '(?=\W|^)(Ref|Own)Ptr(?=\W)'
+    match_ref_or_own_ptr = '(?=\W|^)(Ref|Own)Ptr(WillBeRawPtr)?(?=\W)'
     exceptions = '(?:&|\*|\*\s*=\s*0)$'
     bad_type_usage = search(match_ref_or_own_ptr, type_text)
     exception_usage = search(exceptions, type_text)
diff --git a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
index e7b50543..eb2f12f 100644
--- a/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
+++ b/third_party/WebKit/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
@@ -3612,6 +3612,16 @@
             '{\n'
             '}',
             'The return type should use PassOwnPtr instead of OwnPtr.  [readability/pass_ptr] [5]')
+        self.assert_pass_ptr_check(
+            'RefPtrWillBeRawPtr<Type1> myFunction(int)\n'
+            '{\n'
+            '}',
+            'The return type should use PassRefPtrWillBeRawPtr instead of RefPtrWillBeRawPtr.  [readability/pass_ptr] [5]')
+        self.assert_pass_ptr_check(
+            'OwnPtrWillBeRawPtr<Type1> myFunction(int)\n'
+            '{\n'
+            '}',
+            'The return type should use PassOwnPtrWillBeRawPtr instead of OwnPtrWillBeRawPtr.  [readability/pass_ptr] [5]')
 
     def test_ref_ptr_parameter_value(self):
         self.assert_pass_ptr_check(
diff --git a/tools/luci-go/linux64/isolate.sha1 b/tools/luci-go/linux64/isolate.sha1
index f1c5b2b..be6eaee 100644
--- a/tools/luci-go/linux64/isolate.sha1
+++ b/tools/luci-go/linux64/isolate.sha1
@@ -1 +1 @@
-7dee8e088d4e235e52a20cd43b5c49d7dc6d31f2
+19c8b40bf2f18f58e748c42e8da71d558805014d
diff --git a/tools/luci-go/mac64/isolate.sha1 b/tools/luci-go/mac64/isolate.sha1
index 16e48a8..d31a0ef 100644
--- a/tools/luci-go/mac64/isolate.sha1
+++ b/tools/luci-go/mac64/isolate.sha1
@@ -1 +1 @@
-7a974e94a2f044fa836aeee6277a2a92342c871b
+fbc5e25238075b10f70eab6072dbeb9739e4e5ce
diff --git a/tools/luci-go/win64/isolate.exe.sha1 b/tools/luci-go/win64/isolate.exe.sha1
index 1a50bbd..51f3315 100644
--- a/tools/luci-go/win64/isolate.exe.sha1
+++ b/tools/luci-go/win64/isolate.exe.sha1
@@ -1 +1 @@
-a0a5f97cf572e81407cbbfa09d54ed5ecd28613d
+7a6fd72a5d7e9880546675088a6f2e94e09c5249
diff --git a/ui/views/mus/BUILD.gn b/ui/views/mus/BUILD.gn
index de94bab4..dd80c4a 100644
--- a/ui/views/mus/BUILD.gn
+++ b/ui/views/mus/BUILD.gn
@@ -5,6 +5,8 @@
 import("//tools/grit/repack.gni")
 
 component("mus") {
+  output_name = "ui_views_mus_lib"
+
   sources = [
     "aura_init.cc",
     "aura_init.h",
@@ -53,6 +55,8 @@
     "//mojo/converters/input_events",
     "//mojo/converters/network",
     "//mojo/converters/surfaces",
+    "//mojo/platform_handle:for_component",
+    "//mojo/public/c/system:for_component",
     "//mojo/public/cpp/bindings",
     "//third_party/icu",
     "//ui/aura",
@@ -69,14 +73,6 @@
     "//ui/wm",
   ]
 
-  if (is_component_build) {
-    deps += [
-      "//mojo/gles2",
-      "//mojo/platform_handle:platform_handle_impl",
-      "//third_party/mojo/src/mojo/edk/system",
-    ]
-  }
-
   data_deps = [
     "//components/resource_provider",
   ]
@@ -101,3 +97,29 @@
     "//ui/views/resources",
   ]
 }
+
+group("for_mojo_application") {
+  public_deps = [
+    ":mus",
+  ]
+}
+
+group("for_shared_library") {
+  public_deps = [
+    ":mus",
+  ]
+  if (!is_component_build) {
+    deps = [
+      "//mojo/gles2",
+    ]
+  }
+}
+
+group("for_component") {
+  public_deps = [
+    ":mus",
+  ]
+  deps = [
+    "//mojo/gles2",
+  ]
+}