diff --git a/DEPS b/DEPS index 6326fc8..0603f67 100644 --- a/DEPS +++ b/DEPS
@@ -184,10 +184,10 @@ Var('chromium_git') + '/webm/libvpx.git' + '@' + 'b520882f0eb2648e0d1e5090597ba43aa561e2f1', 'src/third_party/ffmpeg': - Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'a41fa511bc02a9b133b6c966cd950dbdf0dbbe56', + Var('chromium_git') + '/chromium/third_party/ffmpeg.git' + '@' + 'd1e9c4bbd95af9a089d224edf87fd0c3f33ece96', 'src/third_party/libjingle/source/talk': - Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '6bb37dbd87cce20774b1b4f18517c3f1ea4a9a3e', # commit position 11250 + Var('chromium_git') + '/external/webrtc/trunk/talk.git' + '@' + '1c16da383ac3d7a51088722fab024533efc9dbce', # commit position 11275 'src/third_party/usrsctp/usrsctplib': Var('chromium_git') + '/external/github.com/sctplab/usrsctp' + '@' + 'c60ec8b35c3fe6027d7a3faae89d1c8d7dd3ce98', @@ -211,7 +211,7 @@ Var('chromium_git') + '/native_client/src/third_party/scons-2.0.1.git' + '@' + '1c1550e17fc26355d08627fbdec13d8291227067', 'src/third_party/webrtc': - Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + '9a780c85b9fb01712fb7be76240c7b4b3bcdd1eb', # commit position 11252 + Var('chromium_git') + '/external/webrtc/trunk/webrtc.git' + '@' + 'ef78a80a92b3bfe0cb3e720b15174759a9d3d5e0', # commit position 11275 'src/third_party/openmax_dl': Var('chromium_git') + '/external/webrtc/deps/third_party/openmax.git' + '@' + Var('openmax_dl_revision'), @@ -271,7 +271,7 @@ 'src/third_party/catapult': Var('chromium_git') + '/external/github.com/catapult-project/catapult.git' + '@' + - '5c9b770cb18552d626aef802feda3a79cac1f9e3', + 'dc74f19fa849b17180f09cfdf3c5757a26e9a379', 'src/third_party/openh264/src': Var('chromium_git') + '/external/github.com/cisco/openh264' + '@' + 'b37cda248234162033e3e11b0335f3131cdfe488',
diff --git a/PRESUBMIT.py b/PRESUBMIT.py index c89fbfa2..96095b7 100644 --- a/PRESUBMIT.py +++ b/PRESUBMIT.py
@@ -166,6 +166,7 @@ ( r"^base[\\\/]process[\\\/]process_linux\.cc$", r"^base[\\\/]process[\\\/]process_metrics_linux\.cc$", + r"^blimp[\\\/]engine[\\\/]browser[\\\/]blimp_browser_main_parts\.cc$", r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]boot_times_recorder\.cc$", r"^chrome[\\\/]browser[\\\/]chromeos[\\\/]" "customization_document_browsertest\.cc$",
diff --git a/android_webview/android_webview.gyp b/android_webview/android_webview.gyp index 7272bf7..626d1b87 100644 --- a/android_webview/android_webview.gyp +++ b/android_webview/android_webview.gyp
@@ -227,6 +227,7 @@ '../components/components.gyp:breakpad_host', '../components/components.gyp:cdm_browser', '../components/components.gyp:cdm_renderer', + '../components/components.gyp:component_metrics_proto', '../components/components.gyp:crash_component', '../components/components.gyp:data_reduction_proxy_core_browser', '../components/components.gyp:devtools_discovery',
diff --git a/android_webview/browser/aw_browser_main_parts.cc b/android_webview/browser/aw_browser_main_parts.cc index ff72061..06a35e4 100644 --- a/android_webview/browser/aw_browser_main_parts.cc +++ b/android_webview/browser/aw_browser_main_parts.cc
@@ -17,6 +17,7 @@ #include "base/android/memory_pressure_listener_android.h" #include "base/command_line.h" #include "base/files/file_path.h" +#include "base/i18n/rtl.h" #include "base/path_service.h" #include "components/crash/content/browser/crash_micro_dump_manager_android.h" #include "content/public/browser/android/synchronous_compositor.h" @@ -65,6 +66,7 @@ LOG(WARNING) << "Failed to load locale .pak from the apk. " "Bringing up WebView without any locale"; } + base::i18n::SetICUDefaultLocale(locale); // Try to directly mmap the webviewchromium.pak from the apk. Fall back to // load from file, using PATH_SERVICE, otherwise.
diff --git a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java index 0ca81ae..8caf1e0b 100644 --- a/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java +++ b/android_webview/glue/java/src/com/android/webview/chromium/WebViewChromiumFactoryProvider.java
@@ -244,9 +244,12 @@ PathService.override(DIR_RESOURCE_PAKS_ANDROID, "/system/framework/webview/paks"); // Make sure that ResourceProvider is initialized before starting the browser process. - setUpResources(context); + final String webViewPackageName = WebViewFactory.getLoadedPackageInfo().packageName; + setUpResources(webViewPackageName, context); ResourceBundle.initializeLocalePaks(context, R.array.locale_paks); initPlatSupportLibrary(); + final int extraBindFlags = 0; + AwBrowserProcess.configureChildProcessLauncher(webViewPackageName, extraBindFlags); AwBrowserProcess.start(context); if (isBuildDebuggable()) { @@ -323,10 +326,9 @@ mDevToolsServer.setRemoteDebuggingEnabled(enable); } - private void setUpResources(Context context) { - final String packageName = WebViewFactory.getLoadedPackageInfo().packageName; + private void setUpResources(String webViewPackageName, Context context) { ResourceRewriter.rewriteRValues( - mWebViewDelegate.getPackageId(context.getResources(), packageName)); + mWebViewDelegate.getPackageId(context.getResources(), webViewPackageName)); AwResource.setResources(context.getResources()); AwResource.setConfigKeySystemUuidMapping(android.R.array.config_keySystemUuidMapping);
diff --git a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java index ead518f9..e7a6389d 100644 --- a/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java +++ b/android_webview/java/src/org/chromium/android_webview/AwBrowserProcess.java
@@ -15,6 +15,7 @@ import org.chromium.base.library_loader.LibraryProcessType; import org.chromium.base.library_loader.ProcessInitException; import org.chromium.content.browser.BrowserStartupController; +import org.chromium.content.browser.ChildProcessLauncher; import org.chromium.policy.CombinedPolicyProvider; import java.io.File; @@ -52,6 +53,15 @@ } /** + * Configures child process launcher. This is required only if child services are used in + * WebView. + */ + public static void configureChildProcessLauncher(String packageName, int extraBindFlags) { + ChildProcessLauncher.setChildProcessCreationParams( + new ChildProcessLauncher.ChildProcessCreationParams(packageName, extraBindFlags)); + } + + /** * Starts the chromium browser process running within this process. Creates threads * and performs other per-app resource allocations; must not be called from zygote. * Note: it is up to the caller to ensure this is only called once.
diff --git a/android_webview/renderer/aw_content_settings_client.cc b/android_webview/renderer/aw_content_settings_client.cc index 92652f6..5db1ab9 100644 --- a/android_webview/renderer/aw_content_settings_client.cc +++ b/android_webview/renderer/aw_content_settings_client.cc
@@ -35,7 +35,6 @@ bool AwContentSettingsClient::allowDisplayingInsecureContent( bool enabled_per_settings, - const blink::WebSecurityOrigin& origin, const blink::WebURL& url) { return enabled_per_settings ? true : AllowMixedContent(url); }
diff --git a/android_webview/renderer/aw_content_settings_client.h b/android_webview/renderer/aw_content_settings_client.h index 84ed95f..7f28960 100644 --- a/android_webview/renderer/aw_content_settings_client.h +++ b/android_webview/renderer/aw_content_settings_client.h
@@ -23,7 +23,6 @@ // blink::WebContentSettingsClient implementation. bool allowDisplayingInsecureContent( bool enabled_per_settings, - const blink::WebSecurityOrigin& origin, const blink::WebURL& url) override; bool allowRunningInsecureContent( bool enabled_per_settings,
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 7b0919c2..5479a4d 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -113,8 +113,8 @@ "accelerators/magnifier_key_scroller.h", "accelerators/spoken_feedback_toggler.cc", "accelerators/spoken_feedback_toggler.h", - "display/display_configurator_animation.cc", - "display/display_configurator_animation.h", + "display/display_animator.cc", + "display/display_animator.h", "display/resolution_notification_controller.cc", "display/resolution_notification_controller.h", "system/tray/media_security/media_capture_observer.h",
diff --git a/ash/ash.gyp b/ash/ash.gyp index 6b695b53..f87be98 100644 --- a/ash/ash.gyp +++ b/ash/ash.gyp
@@ -63,12 +63,12 @@ 'desktop_background/user_wallpaper_delegate.h', 'display/cursor_window_controller.cc', 'display/cursor_window_controller.h', + 'display/display_animator.cc', + 'display/display_animator.h', 'display/display_change_observer_chromeos.cc', 'display/display_change_observer_chromeos.h', 'display/display_color_manager_chromeos.cc', 'display/display_color_manager_chromeos.h', - 'display/display_configurator_animation.cc', - 'display/display_configurator_animation.h', 'display/window_tree_host_manager.cc', 'display/window_tree_host_manager.h', 'display/display_error_observer_chromeos.cc', @@ -1033,8 +1033,8 @@ 'accelerators/magnifier_key_scroller.h', 'accelerators/spoken_feedback_toggler.cc', 'accelerators/spoken_feedback_toggler.h', - 'display/display_configurator_animation.cc', - 'display/display_configurator_animation.h', + 'display/display_animator.cc', + 'display/display_animator.h', 'display/resolution_notification_controller.cc', 'display/resolution_notification_controller.h', 'system/tray/media_security/media_capture_observer.h',
diff --git a/ash/display/display_configurator_animation.cc b/ash/display/display_animator.cc similarity index 71% rename from ash/display/display_configurator_animation.cc rename to ash/display/display_animator.cc index dbbe00b4..8348302 100644 --- a/ash/display/display_configurator_animation.cc +++ b/ash/display/display_animator.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ash/display/display_configurator_animation.h" +#include "ash/display/display_animator.h" #include "ash/shell.h" #include "ash/shell_window_ids.h" @@ -28,9 +28,7 @@ class CallbackRunningObserver { public: CallbackRunningObserver(base::Closure callback) - : completed_counter_(0), - animation_aborted_(false), - callback_(callback) {} + : completed_counter_(0), animation_aborted_(false), callback_(callback) {} void AddNewAnimator(ui::LayerAnimator* animator) { Observer* observer = new Observer(animator, this); @@ -56,10 +54,8 @@ // The actual observer to listen each animation completion. class Observer : public ui::LayerAnimationObserver { public: - Observer(ui::LayerAnimator* animator, - CallbackRunningObserver* observer) - : animator_(animator), - observer_(observer) {} + Observer(ui::LayerAnimator* animator, CallbackRunningObserver* observer) + : animator_(animator), observer_(observer) {} protected: // ui::LayerAnimationObserver overrides: @@ -95,16 +91,13 @@ } // namespace -DisplayConfiguratorAnimation::DisplayConfiguratorAnimation() - : weak_ptr_factory_(this) { -} +DisplayAnimator::DisplayAnimator() : weak_ptr_factory_(this) {} -DisplayConfiguratorAnimation::~DisplayConfiguratorAnimation() { +DisplayAnimator::~DisplayAnimator() { ClearHidingLayers(); } -void DisplayConfiguratorAnimation::StartFadeOutAnimation( - base::Closure callback) { +void DisplayAnimator::StartFadeOutAnimation(base::Closure callback) { CallbackRunningObserver* observer = new CallbackRunningObserver(callback); ClearHidingLayers(); @@ -112,24 +105,20 @@ // hiding the root windows, we put a black layer over a root window for // safety. These layers remain to hide root windows and will be deleted // after the animation of OnDisplayModeChanged(). - aura::Window::Windows root_windows = - Shell::GetInstance()->GetAllRootWindows(); - for (aura::Window::Windows::const_iterator it = root_windows.begin(); - it != root_windows.end(); ++it) { - aura::Window* root_window = *it; + for (aura::Window* root_window : Shell::GetInstance()->GetAllRootWindows()) { ui::Layer* hiding_layer = new ui::Layer(ui::LAYER_SOLID_COLOR); hiding_layer->SetColor(SK_ColorBLACK); hiding_layer->SetBounds(root_window->bounds()); - ui::Layer* parent = - ash::Shell::GetContainer(root_window, - ash::kShellWindowId_OverlayContainer)->layer(); + ui::Layer* parent = ash::Shell::GetContainer( + root_window, ash::kShellWindowId_OverlayContainer) + ->layer(); parent->Add(hiding_layer); hiding_layer->SetOpacity(0.0); ui::ScopedLayerAnimationSettings settings(hiding_layer->GetAnimator()); - settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( - kFadingAnimationDurationInMS)); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kFadingAnimationDurationInMS)); observer->AddNewAnimator(hiding_layer->GetAnimator()); hiding_layer->SetOpacity(1.0f); hiding_layer->SetVisible(true); @@ -142,23 +131,20 @@ timer_.reset(new base::OneShotTimer()); timer_->Start(FROM_HERE, base::TimeDelta::FromSeconds(kFadingTimeoutDurationInSeconds), - this, - &DisplayConfiguratorAnimation::ClearHidingLayers); + this, &DisplayAnimator::ClearHidingLayers); } -void DisplayConfiguratorAnimation::StartFadeInAnimation() { +void DisplayAnimator::StartFadeInAnimation() { // We want to make sure clearing all of hiding layers after the animation // finished. Note that this callback can be canceled, but the cancel only // happens when the next animation is scheduled. Thus the hiding layers // should be deleted eventually. - CallbackRunningObserver* observer = new CallbackRunningObserver( - base::Bind(&DisplayConfiguratorAnimation::ClearHidingLayers, - weak_ptr_factory_.GetWeakPtr())); + CallbackRunningObserver* observer = new CallbackRunningObserver(base::Bind( + &DisplayAnimator::ClearHidingLayers, weak_ptr_factory_.GetWeakPtr())); // Ensure that layers are not animating. - for (std::map<aura::Window*, ui::Layer*>::iterator it = - hiding_layers_.begin(); it != hiding_layers_.end(); ++it) { - ui::LayerAnimator* animator = it->second->GetAnimator(); + for (std::map<aura::Window*, ui::Layer*>::value_type& e : hiding_layers_) { + ui::LayerAnimator* animator = e.second->GetAnimator(); if (animator->is_animating()) animator->StopAnimating(); } @@ -166,12 +152,8 @@ // Schedules the fade-in effect for all root windows. Because we put the // black layers for fade-out, here we actually turn those black layers // invisible. - aura::Window::Windows root_windows = - Shell::GetInstance()->GetAllRootWindows(); - for (aura::Window::Windows::const_iterator it = root_windows.begin(); - it != root_windows.end(); ++it) { - aura::Window* root_window = *it; - ui::Layer* hiding_layer = NULL; + for (aura::Window* root_window : Shell::GetInstance()->GetAllRootWindows()) { + ui::Layer* hiding_layer = nullptr; if (hiding_layers_.find(root_window) == hiding_layers_.end()) { // In case of the transition from mirroring->non-mirroring, new root // windows appear and we do not have the black layers for them. Thus @@ -179,9 +161,9 @@ hiding_layer = new ui::Layer(ui::LAYER_SOLID_COLOR); hiding_layer->SetColor(SK_ColorBLACK); hiding_layer->SetBounds(root_window->bounds()); - ui::Layer* parent = - ash::Shell::GetContainer( - root_window, ash::kShellWindowId_OverlayContainer)->layer(); + ui::Layer* parent = ash::Shell::GetContainer( + root_window, ash::kShellWindowId_OverlayContainer) + ->layer(); parent->Add(hiding_layer); hiding_layer->SetOpacity(1.0f); hiding_layer->SetVisible(true); @@ -193,34 +175,34 @@ } ui::ScopedLayerAnimationSettings settings(hiding_layer->GetAnimator()); - settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds( - kFadingAnimationDurationInMS)); + settings.SetTransitionDuration( + base::TimeDelta::FromMilliseconds(kFadingAnimationDurationInMS)); observer->AddNewAnimator(hiding_layer->GetAnimator()); hiding_layer->SetOpacity(0.0f); hiding_layer->SetVisible(false); } } -void DisplayConfiguratorAnimation::OnDisplayModeChanged( +void DisplayAnimator::OnDisplayModeChanged( const ui::DisplayConfigurator::DisplayStateList& displays) { if (!hiding_layers_.empty()) StartFadeInAnimation(); } -void DisplayConfiguratorAnimation::OnDisplayModeChangeFailed( +void DisplayAnimator::OnDisplayModeChangeFailed( const ui::DisplayConfigurator::DisplayStateList& displays, ui::MultipleDisplayState failed_new_state) { if (!hiding_layers_.empty()) StartFadeInAnimation(); } -void DisplayConfiguratorAnimation::ClearHidingLayers() { +void DisplayAnimator::ClearHidingLayers() { if (timer_) { timer_->Stop(); timer_.reset(); } - STLDeleteContainerPairSecondPointers( - hiding_layers_.begin(), hiding_layers_.end()); + STLDeleteContainerPairSecondPointers(hiding_layers_.begin(), + hiding_layers_.end()); hiding_layers_.clear(); }
diff --git a/ash/display/display_configurator_animation.h b/ash/display/display_animator.h similarity index 74% rename from ash/display/display_configurator_animation.h rename to ash/display/display_animator.h index 567c9f1..81c6005 100644 --- a/ash/display/display_configurator_animation.h +++ b/ash/display/display_animator.h
@@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef ASH_DISPLAY_DISPLAY_CONFIGURATOR_ANIMATION_H_ -#define ASH_DISPLAY_DISPLAY_CONFIGURATOR_ANIMATION_H_ +#ifndef ASH_DISPLAY_DISPLAY_ANIMATOR_H_ +#define ASH_DISPLAY_DISPLAY_ANIMATOR_H_ #include <map> @@ -25,14 +25,13 @@ namespace ash { -// DisplayConfiguratorAnimation provides the visual effects for +// DisplayAnimator provides the visual effects for // ui::DisplayConfigurator, such like fade-out/in during changing // the display mode. -class ASH_EXPORT DisplayConfiguratorAnimation - : public ui::DisplayConfigurator::Observer { +class ASH_EXPORT DisplayAnimator : public ui::DisplayConfigurator::Observer { public: - DisplayConfiguratorAnimation(); - ~DisplayConfiguratorAnimation() override; + DisplayAnimator(); + ~DisplayAnimator() override; // Starts the fade-out animation for the all root windows. It will // call |callback| once all of the animations have finished. @@ -58,11 +57,11 @@ std::map<aura::Window*, ui::Layer*> hiding_layers_; scoped_ptr<base::OneShotTimer> timer_; - base::WeakPtrFactory<DisplayConfiguratorAnimation> weak_ptr_factory_; + base::WeakPtrFactory<DisplayAnimator> weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(DisplayConfiguratorAnimation); + DISALLOW_COPY_AND_ASSIGN(DisplayAnimator); }; } // namespace ash -#endif // ASH_DISPLAY_DISPLAY_CONFIGURATION_CONTROLLER_H_ +#endif // ASH_DISPLAY_DISPLAY_ANIMATOR_H_
diff --git a/ash/display/display_manager.cc b/ash/display/display_manager.cc index fe7f243..5d47aba 100644 --- a/ash/display/display_manager.cc +++ b/ash/display/display_manager.cc
@@ -43,7 +43,7 @@ #endif #if defined(OS_CHROMEOS) -#include "ash/display/display_configurator_animation.h" +#include "ash/display/display_animator.h" #include "base/sys_info.h" #endif @@ -948,9 +948,8 @@ multi_display_mode_ = mirror ? MIRRORING : current_default_multi_display_mode_; ReconfigureDisplays(); - if (Shell::GetInstance()->display_configurator_animation()) { - Shell::GetInstance()->display_configurator_animation()-> - StartFadeInAnimation(); + if (Shell::GetInstance()->display_animator()) { + Shell::GetInstance()->display_animator()->StartFadeInAnimation(); } RunPendingTasksForTest(); #endif
diff --git a/ash/display/window_tree_host_manager.cc b/ash/display/window_tree_host_manager.cc index 8f2ba2eb..70dd1b9 100644 --- a/ash/display/window_tree_host_manager.cc +++ b/ash/display/window_tree_host_manager.cc
@@ -49,7 +49,7 @@ #include "ui/wm/public/activation_client.h" #if defined(OS_CHROMEOS) -#include "ash/display/display_configurator_animation.h" +#include "ash/display/display_animator.h" #include "base/sys_info.h" #include "base/time/time.h" #endif // defined(OS_CHROMEOS) @@ -438,8 +438,7 @@ } #if defined(OS_CHROMEOS) Shell* shell = Shell::GetInstance(); - DisplayConfiguratorAnimation* animation = - shell->display_configurator_animation(); + DisplayAnimator* animation = shell->display_animator(); animation->StartFadeOutAnimation(base::Bind( &WindowTreeHostManager::SetMirrorModeAfterAnimation, weak_ptr_factory_.GetWeakPtr(), !display_manager->IsInMirrorMode())); @@ -455,8 +454,7 @@ if (Shell::GetScreen()->GetNumDisplays() > 1) { #if defined(OS_CHROMEOS) - DisplayConfiguratorAnimation* animation = - Shell::GetInstance()->display_configurator_animation(); + DisplayAnimator* animation = Shell::GetInstance()->display_animator(); if (animation) { animation->StartFadeOutAnimation( base::Bind(&WindowTreeHostManager::OnFadeOutForSwapDisplayFinished, @@ -924,9 +922,7 @@ void WindowTreeHostManager::OnFadeOutForSwapDisplayFinished() { #if defined(OS_CHROMEOS) SetPrimaryDisplay(ScreenUtil::GetSecondaryDisplay()); - Shell::GetInstance() - ->display_configurator_animation() - ->StartFadeInAnimation(); + Shell::GetInstance()->display_animator()->StartFadeInAnimation(); #endif }
diff --git a/ash/shell.cc b/ash/shell.cc index 192d9d72..7c36c8e 100644 --- a/ash/shell.cc +++ b/ash/shell.cc
@@ -120,9 +120,9 @@ #include "ash/accelerators/magnifier_key_scroller.h" #include "ash/accelerators/spoken_feedback_toggler.h" #include "ash/ash_constants.h" +#include "ash/display/display_animator.h" #include "ash/display/display_change_observer_chromeos.h" #include "ash/display/display_color_manager_chromeos.h" -#include "ash/display/display_configurator_animation.h" #include "ash/display/display_error_observer_chromeos.h" #include "ash/display/projecting_observer_chromeos.h" #include "ash/display/resolution_notification_controller.h" @@ -814,9 +814,8 @@ display_color_manager_.reset(); if (display_change_observer_) display_configurator_->RemoveObserver(display_change_observer_.get()); - if (display_configurator_animation_) - display_configurator_->RemoveObserver( - display_configurator_animation_.get()); + if (display_animator_) + display_configurator_->RemoveObserver(display_animator_.get()); if (display_error_observer_) display_configurator_->RemoveObserver(display_error_observer_.get()); if (projecting_observer_) { @@ -840,8 +839,8 @@ bool display_initialized = display_manager_->InitFromCommandLine(); #if defined(OS_CHROMEOS) display_configurator_->Init(!gpu_support_->IsPanelFittingDisabled()); - display_configurator_animation_.reset(new DisplayConfiguratorAnimation()); - display_configurator_->AddObserver(display_configurator_animation_.get()); + display_animator_.reset(new DisplayAnimator()); + display_configurator_->AddObserver(display_animator_.get()); // The DBusThreadManager must outlive this Shell. See the DCHECK in ~Shell. chromeos::DBusThreadManager* dbus_thread_manager =
diff --git a/ash/shell.h b/ash/shell.h index 24f6176..8401a6c3c 100644 --- a/ash/shell.h +++ b/ash/shell.h
@@ -85,9 +85,9 @@ class BluetoothNotificationController; class CaptureController; class DesktopBackgroundController; +class DisplayAnimator; class DisplayChangeObserver; class DisplayColorManager; -class DisplayConfiguratorAnimation; class WindowTreeHostManager; class DisplayErrorObserver; class DisplayManager; @@ -523,9 +523,7 @@ ui::DisplayConfigurator* display_configurator() { return display_configurator_.get(); } - DisplayConfiguratorAnimation* display_configurator_animation() { - return display_configurator_animation_.get(); - } + DisplayAnimator* display_animator() { return display_animator_.get(); } DisplayErrorObserver* display_error_observer() { return display_error_observer_.get(); } @@ -726,7 +724,7 @@ // Controls video output device state. scoped_ptr<ui::DisplayConfigurator> display_configurator_; scoped_ptr<DisplayColorManager> display_color_manager_; - scoped_ptr<DisplayConfiguratorAnimation> display_configurator_animation_; + scoped_ptr<DisplayAnimator> display_animator_; scoped_ptr<DisplayErrorObserver> display_error_observer_; scoped_ptr<ProjectingObserver> projecting_observer_;
diff --git a/ash/test/ash_test_helper.cc b/ash/test/ash_test_helper.cc index 560f8ef..f5a27b4 100644 --- a/ash/test/ash_test_helper.cc +++ b/ash/test/ash_test_helper.cc
@@ -128,7 +128,7 @@ } test::DisplayManagerTestApi().DisableChangeDisplayUponHostResize(); - ShellTestApi(shell).DisableDisplayConfiguratorAnimation(); + ShellTestApi(shell).DisableDisplayAnimator(); test_screenshot_delegate_ = new TestScreenshotDelegate(); shell->accelerator_controller()->SetScreenshotDelegate(
diff --git a/ash/test/shell_test_api.cc b/ash/test/shell_test_api.cc index b85bcab9..c9a3bf46 100644 --- a/ash/test/shell_test_api.cc +++ b/ash/test/shell_test_api.cc
@@ -10,7 +10,7 @@ #include "ash/shell.h" #if defined(OS_CHROMEOS) -#include "ash/display/display_configurator_animation.h" +#include "ash/display/display_animator.h" #include "ui/display/chromeos/display_configurator.h" #endif @@ -51,12 +51,12 @@ return shell_->app_list_controller_.get(); } -void ShellTestApi::DisableDisplayConfiguratorAnimation() { +void ShellTestApi::DisableDisplayAnimator() { #if defined(OS_CHROMEOS) - if (shell_->display_configurator_animation_) { + if (shell_->display_animator_) { shell_->display_configurator_->RemoveObserver( - shell_->display_configurator_animation_.get()); - shell_->display_configurator_animation_.reset(); + shell_->display_animator_.get()); + shell_->display_animator_.reset(); } #endif // defined(OS_CHROMEOS) }
diff --git a/ash/test/shell_test_api.h b/ash/test/shell_test_api.h index 654e425..b144f0b 100644 --- a/ash/test/shell_test_api.h +++ b/ash/test/shell_test_api.h
@@ -37,7 +37,7 @@ DragDropController* drag_drop_controller(); AppListController* app_list_controller(); MaximizeModeWindowManager* maximize_mode_window_manager(); - void DisableDisplayConfiguratorAnimation(); + void DisableDisplayAnimator(); // Set ShelfDelegate. void SetShelfDelegate(ShelfDelegate* delegate);
diff --git a/base/BUILD.gn b/base/BUILD.gn index 5d8510f1..1265df8 100644 --- a/base/BUILD.gn +++ b/base/BUILD.gn
@@ -2057,9 +2057,10 @@ DEPRECATED_java_in_dir = "android/java/src" - # A new version of NativeLibraries.java (with the actual correct values) - # will be created when creating an apk. + # New versions of ChromiumMultiDex.java and NativeLibraries.java + # (with the actual correct values) will be created when creating an apk. jar_excluded_patterns = [ + "*/ChromiumMultiDex.class", "*/NativeLibraries.class", "*/NativeLibraries##*.class", ] @@ -2094,6 +2095,7 @@ "//third_party/robolectric:android-all-4.3_r2-robolectric-0", "//third_party/robolectric:robolectric_java", ] + srcjar_deps = [ ":base_multidex_gen" ] } # GYP: //base.gyp:base_junit_tests @@ -2128,9 +2130,6 @@ sources = [ "android/java/templates/ChromiumMultiDex.template", ] - if (is_debug) { - defines = [ "MULTIDEX_CONFIGURATION_Debug" ] - } package_name = "org/chromium/base/multidex" }
diff --git a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java index e4e6e20..f842a18f 100644 --- a/base/android/java/src/org/chromium/base/BaseChromiumApplication.java +++ b/base/android/java/src/org/chromium/base/BaseChromiumApplication.java
@@ -10,7 +10,7 @@ import android.os.Bundle; import android.view.Window; -import org.chromium.base.multidex.ChromiumMultiDex; +import org.chromium.base.multidex.ChromiumMultiDexInstaller; /** * Basic application functionality that should be shared among all browser applications. @@ -31,7 +31,7 @@ @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); - ChromiumMultiDex.install(this); + ChromiumMultiDexInstaller.install(this); } /**
diff --git a/base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java b/base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java new file mode 100644 index 0000000..e4b30b9 --- /dev/null +++ b/base/android/java/src/org/chromium/base/multidex/ChromiumMultiDexInstaller.java
@@ -0,0 +1,114 @@ +// 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.base.multidex; + +import android.app.ActivityManager; +import android.app.ActivityManager.RunningAppProcessInfo; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.support.multidex.MultiDex; + +import org.chromium.base.Log; +import org.chromium.base.VisibleForTesting; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +/** + * Performs multidex installation for non-isolated processes. + */ +public class ChromiumMultiDexInstaller { + + private static final String TAG = "base_multidex"; + + /** + * Suffix for the meta-data tag in the AndroidManifext.xml that determines whether loading + * secondary dexes should be skipped for a given process name. + */ + private static final String IGNORE_MULTIDEX_KEY = ".ignore_multidex"; + + /** + * Installs secondary dexes if possible/necessary. + * + * Isolated processes (e.g. renderer processes) can't load secondary dex files on + * K and below, so we don't even try in that case. + * + * In release builds of app apks (as opposed to test apks), this is a no-op because: + * - multidex isn't necessary in release builds because we run proguard there and + * thus aren't threatening to hit the dex limit; and + * - calling MultiDex.install, even in the absence of secondary dexes, causes a + * significant regression in start-up time (crbug.com/525695). + * + * @param context The application context. + */ + @VisibleForTesting + public static void install(Context context) { + if (!ChromiumMultiDex.isMultidexEnabled()) return; + + // TODO(jbudorick): Back out this version check once support for K & below works. + // http://crbug.com/512357 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP + && !shouldInstallMultiDex(context)) { + Log.i(TAG, "Skipping multidex installation: not needed for process."); + } else { + MultiDex.install(context); + Log.i(TAG, "Completed multidex installation."); + } + } + + private static String getProcessName(Context context) { + try { + String currentProcessName = null; + int pid = android.os.Process.myPid(); + + ActivityManager manager = + (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); + for (RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) { + if (processInfo.pid == pid) { + currentProcessName = processInfo.processName; + break; + } + } + + return currentProcessName; + } catch (SecurityException ex) { + return null; + } + } + + // Determines whether MultiDex should be installed for the current process. Isolated + // Processes should skip MultiDex as they can not actually access the files on disk. + // Privileged processes need ot have all of their dependencies in the MainDex for + // performance reasons. + private static boolean shouldInstallMultiDex(Context context) { + try { + Method isIsolatedMethod = + android.os.Process.class.getMethod("isIsolated"); + Object retVal = isIsolatedMethod.invoke(null); + if (retVal != null && retVal instanceof Boolean && ((Boolean) retVal)) { + return false; + } + } catch (IllegalAccessException | IllegalArgumentException + | InvocationTargetException | NoSuchMethodException e) { + // Ignore and fall back to checking the app processes. + } + + String currentProcessName = getProcessName(context); + if (currentProcessName == null) return true; + + PackageManager packageManager = context.getPackageManager(); + try { + ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(), + PackageManager.GET_META_DATA); + if (appInfo == null || appInfo.metaData == null) return true; + return !appInfo.metaData.getBoolean(currentProcessName + IGNORE_MULTIDEX_KEY, false); + } catch (PackageManager.NameNotFoundException e) { + return true; + } + } + +}
diff --git a/base/android/java/templates/ChromiumMultiDex.template b/base/android/java/templates/ChromiumMultiDex.template index 5580489..7e70701 100644 --- a/base/android/java/templates/ChromiumMultiDex.template +++ b/base/android/java/templates/ChromiumMultiDex.template
@@ -4,115 +4,22 @@ package org.chromium.base.multidex; -import android.app.ActivityManager; -import android.app.ActivityManager.RunningAppProcessInfo; -import android.content.Context; -import android.content.pm.ApplicationInfo; -import android.content.pm.PackageManager; -import android.os.Build; -import android.os.Process; -import android.support.multidex.MultiDex; - -import org.chromium.base.Log; -import org.chromium.base.VisibleForTesting; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - /** - * Performs multidex installation for non-isolated processes. + * Multidex configuration. Generated on a per-target basis. */ -public class ChromiumMultiDex { +class ChromiumMultiDex { - private static final String TAG = "base_multidex"; - - /** - * Suffix for the meta-data tag in the AndroidManifext.xml that determines whether loading - * secondary dexes should be skipped for a given process name. + /** Whether multidex is enabled for this target. + * + * This has to be a function instead of a static final boolean s.t. the initial false value + * doesn't get optimized into {@link ChromiumMultiDexInstaller} at base_java compile time. */ - private static final String IGNORE_MULTIDEX_KEY = ".ignore_multidex"; - - /** - * Installs secondary dexes if possible/necessary. - * - * Isolated processes (e.g. renderer processes) can't load secondary dex files on - * K and below, so we don't even try in that case. - * - * In release builds, this is a no-op because: - * - multidex isn't necessary in release builds because we run proguard there and - * thus aren't threatening to hit the dex limit; and - * - calling MultiDex.install, even in the absence of secondary dexes, causes a - * significant regression in start-up time (crbug.com/525695). - * - * @param context The application context. - */ - @VisibleForTesting -#if defined(MULTIDEX_CONFIGURATION_Debug) - public static void install(Context context) { - // TODO(jbudorick): Back out this version check once support for K & below works. - // http://crbug.com/512357 - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP - && !shouldInstallMultiDex(context)) { - Log.i(TAG, "Skipping multidex installation: not needed for process."); - } else { - MultiDex.install(context); - Log.i(TAG, "Completed multidex installation."); - } - } - - private static String getProcessName(Context context) { - try { - String currentProcessName = null; - int pid = android.os.Process.myPid(); - - ActivityManager manager = - (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE); - for (RunningAppProcessInfo processInfo : manager.getRunningAppProcesses()) { - if (processInfo.pid == pid) { - currentProcessName = processInfo.processName; - break; - } - } - - return currentProcessName; - } catch (SecurityException ex) { - return null; - } - } - - // Determines whether MultiDex should be installed for the current process. Isolated - // Processes should skip MultiDex as they can not actually access the files on disk. - // Privileged processes need ot have all of their dependencies in the MainDex for - // performance reasons. - private static boolean shouldInstallMultiDex(Context context) { - try { - Method isIsolatedMethod = - android.os.Process.class.getMethod("isIsolated"); - Object retVal = isIsolatedMethod.invoke(null); - if (retVal != null && retVal instanceof Boolean && ((Boolean) retVal)) { - return false; - } - } catch (IllegalAccessException | IllegalArgumentException - | InvocationTargetException | NoSuchMethodException e) { - // Ignore and fall back to checking the app processes. - } - - String currentProcessName = getProcessName(context); - if (currentProcessName == null) return true; - - PackageManager packageManager = context.getPackageManager(); - try { - ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(), - PackageManager.GET_META_DATA); - if (appInfo == null || appInfo.metaData == null) return true; - return !appInfo.metaData.getBoolean(currentProcessName + IGNORE_MULTIDEX_KEY, false); - } catch (PackageManager.NameNotFoundException e) { - return true; - } - } + static boolean isMultidexEnabled() { +#if defined(ENABLE_MULTIDEX) + return true; #else - public static void install(Context context) { - } + return false; #endif + } }
diff --git a/base/base.gyp b/base/base.gyp index dc484f4..94a1d4925 100644 --- a/base/base.gyp +++ b/base/base.gyp
@@ -1489,9 +1489,6 @@ 'variables': { 'package_name': 'org/chromium/base/multidex', 'template_deps': [], - 'additional_gcc_preprocess_options': [ - '--defines', 'MULTIDEX_CONFIGURATION_<(CONFIGURATION_NAME)', - ], }, 'includes': ['../build/android/java_cpp_template.gypi'], }, @@ -1510,7 +1507,10 @@ 'type': 'none', 'variables': { 'java_in_dir': 'android/java', - 'jar_excluded_classes': [ '*/NativeLibraries.class' ], + 'jar_excluded_classes': [ + '*/ChromiumMultiDex.class', + '*/NativeLibraries.class', + ], }, 'dependencies': [ 'base_java_application_state', @@ -1522,6 +1522,11 @@ '../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib', '../third_party/jsr-305/jsr-305.gyp:jsr_305_javalib', ], + 'all_dependent_settings': { + 'variables': { + 'generate_multidex_config': 1, + }, + }, 'includes': [ '../build/java.gypi' ], }, { @@ -1583,6 +1588,7 @@ 'target_name': 'base_junit_test_support', 'type': 'none', 'dependencies': [ + 'base_multidex_gen', '../testing/android/junit/junit_test.gyp:junit_test_support', '../third_party/android_tools/android_tools.gyp:android_support_multidex_javalib', ],
diff --git a/base/files/file_util_posix.cc b/base/files/file_util_posix.cc index 7e31bfb..802ed51 100644 --- a/base/files/file_util_posix.cc +++ b/base/files/file_util_posix.cc
@@ -356,7 +356,7 @@ return false; if (flags & O_NONBLOCK) return true; - if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) == -1) + if (HANDLE_EINTR(fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1) return false; return true; }
diff --git a/base/posix/safe_strerror.cc b/base/posix/safe_strerror.cc index e80e8f8..798658e 100644 --- a/base/posix/safe_strerror.cc +++ b/base/posix/safe_strerror.cc
@@ -20,7 +20,11 @@ namespace base { -#define USE_HISTORICAL_STRERRO_R (defined(__GLIBC__) || defined(OS_NACL)) +#if defined(__GLIBC__) || defined(OS_NACL) +#define USE_HISTORICAL_STRERRO_R 1 +#else +#define USE_HISTORICAL_STRERRO_R 0 +#endif #if USE_HISTORICAL_STRERRO_R && defined(__GNUC__) // GCC will complain about the unused second wrap function unless we tell it
diff --git a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java index 8bf3d0fb..669307c8 100644 --- a/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java +++ b/base/test/android/javatests/src/org/chromium/base/test/BaseInstrumentationTestRunner.java
@@ -18,7 +18,7 @@ import org.chromium.base.Log; import org.chromium.base.SysUtils; -import org.chromium.base.multidex.ChromiumMultiDex; +import org.chromium.base.multidex.ChromiumMultiDexInstaller; import org.chromium.base.test.util.CommandLineFlags; import org.chromium.base.test.util.DisableIfSkipCheck; import org.chromium.base.test.util.MinAndroidSdkLevel; @@ -37,7 +37,7 @@ @Override public void onCreate(Bundle arguments) { - ChromiumMultiDex.install(getTargetContext()); + ChromiumMultiDexInstaller.install(getTargetContext()); super.onCreate(arguments); }
diff --git a/blimp/client/input/blimp_input_handler_wrapper.cc b/blimp/client/input/blimp_input_handler_wrapper.cc index a06c92b..233e739 100644 --- a/blimp/client/input/blimp_input_handler_wrapper.cc +++ b/blimp/client/input/blimp_input_handler_wrapper.cc
@@ -44,7 +44,17 @@ ui::InputHandlerProxy::EventDisposition disposition = input_handler_proxy_->HandleInputEvent(*input_event); - bool consumed = disposition == ui::InputHandlerProxy::DID_NOT_HANDLE; + bool consumed = false; + + switch (disposition) { + case ui::InputHandlerProxy::EventDisposition::DID_HANDLE: + case ui::InputHandlerProxy::EventDisposition::DROP_EVENT: + consumed = true; + break; + case ui::InputHandlerProxy::EventDisposition::DID_NOT_HANDLE: + consumed = false; + break; + } main_task_runner_->PostTask( FROM_HERE,
diff --git a/blimp/docs/container.md b/blimp/docs/container.md index b8170726..36a5cee 100644 --- a/blimp/docs/container.md +++ b/blimp/docs/container.md
@@ -75,3 +75,15 @@ See the [blimp engine `Dockerfile`](../engine/Dockerfile) to find out what flags are passed by default. + +### Mapping Volumes into the Docker Container + +If you need to map a directory into the Docker container (eg. for necessary +files): + +```bash +docker run -v /path/to/srcdir:/path/to/docker/destdir blimp_engine +``` + +NB: The permissions of the directory and the files outside of the Docker +container will be carried over into the container.
diff --git a/blimp/docs/running.md b/blimp/docs/running.md index b8bba0f..9678a09 100644 --- a/blimp/docs/running.md +++ b/blimp/docs/running.md
@@ -42,3 +42,7 @@ client to talk to your computer. Follow the instructions [here](https://developer.chrome.com/devtools/docs/remote-debugging) to get started. You'll probably want to remap 25467 to "localhost:25467". + +### Required flags +* `--blimp-client-token-path=$PATH`: Path to a file containing a nonempty +token string. If this is not present, the engine will fail to boot.
diff --git a/blimp/engine/Dockerfile b/blimp/engine/Dockerfile index d939115..732ceae5 100644 --- a/blimp/engine/Dockerfile +++ b/blimp/engine/Dockerfile
@@ -18,8 +18,9 @@ USER blimp_user WORKDIR "/engine" -ENTRYPOINT ["/engine/blimp_engine_app", "--disable-gpu", \ - "--use-remote-compositing", \ - # Retains display items for - # serialization on the engine. - "--disable-cached-picture-raster"] +ENTRYPOINT ["/engine/blimp_engine_app", \ + "--disable-gpu", \ + "--use-remote-compositing", \ + # Retains display items for serialization on the engine. + "--disable-cached-picture-raster", \ + "--blimp-client-token-path=/engine/data/client_token"]
diff --git a/blimp/engine/browser/BUILD.gn b/blimp/engine/browser/BUILD.gn index 35398966..4fa99ba 100644 --- a/blimp/engine/browser/BUILD.gn +++ b/blimp/engine/browser/BUILD.gn
@@ -10,6 +10,8 @@ "blimp_browser_main_parts.h", "blimp_content_browser_client.cc", "blimp_content_browser_client.h", + "blimp_engine_config.cc", + "blimp_engine_config.h", "blimp_engine_session.cc", "blimp_engine_session.h", "blimp_network_delegate.cc", @@ -20,6 +22,8 @@ "blimp_url_request_context_getter.h", "engine_render_widget_feature.cc", "engine_render_widget_feature.h", + "switches.cc", + "switches.h", ] deps = [ @@ -44,6 +48,7 @@ testonly = true sources = [ + "blimp_engine_config_unittest.cc", "engine_render_widget_feature_unittest.cc", ]
diff --git a/blimp/engine/browser/blimp_browser_main_parts.cc b/blimp/engine/browser/blimp_browser_main_parts.cc index ad20a382..c35d694 100644 --- a/blimp/engine/browser/blimp_browser_main_parts.cc +++ b/blimp/engine/browser/blimp_browser_main_parts.cc
@@ -4,8 +4,11 @@ #include "blimp/engine/browser/blimp_browser_main_parts.h" +#include "base/command_line.h" +#include "base/threading/thread_restrictions.h" #include "blimp/common/proto/blimp_message.pb.h" #include "blimp/engine/browser/blimp_browser_context.h" +#include "blimp/engine/browser/blimp_engine_config.h" #include "blimp/engine/browser/blimp_engine_session.h" #include "blimp/net/blimp_connection.h" #include "content/public/browser/browser_thread.h" @@ -30,6 +33,15 @@ // TODO(haibinlu): Rename the method below. crbug/548330. ui::InitializeInputMethodForTesting(); #endif + // Fetch the engine config from the command line, and crash if invalid. Allow + // IO operations even though this is not in the FILE thread as this is + // necessary for Blimp startup and occurs before any user interaction. + { + const base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess(); + base::ThreadRestrictions::ScopedAllowIO allow_io; + engine_config_ = BlimpEngineConfig::Create(*cmd_line); + CHECK(engine_config_); + } } void BlimpBrowserMainParts::PreMainMessageLoopRun() {
diff --git a/blimp/engine/browser/blimp_browser_main_parts.h b/blimp/engine/browser/blimp_browser_main_parts.h index 3e42a3ae..803ac79 100644 --- a/blimp/engine/browser/blimp_browser_main_parts.h +++ b/blimp/engine/browser/blimp_browser_main_parts.h
@@ -22,6 +22,7 @@ namespace engine { class BlimpBrowserContext; +class BlimpEngineConfig; class BlimpEngineSession; class BlimpBrowserMainParts : public content::BrowserMainParts { @@ -37,6 +38,7 @@ BlimpBrowserContext* GetBrowserContext(); private: + scoped_ptr<BlimpEngineConfig> engine_config_; scoped_ptr<net::NetLog> net_log_; scoped_ptr<BlimpEngineSession> engine_session_;
diff --git a/blimp/engine/browser/blimp_engine_config.cc b/blimp/engine/browser/blimp_engine_config.cc new file mode 100644 index 0000000..da74bb7d --- /dev/null +++ b/blimp/engine/browser/blimp_engine_config.cc
@@ -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. + +#include "blimp/engine/browser/blimp_engine_config.h" + +#include <string> + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/string_util.h" +#include "blimp/engine/browser/switches.h" + +namespace blimp { +namespace engine { + +namespace { +// Gets the client token from the file provided by the command line. If a read +// does not succeed, or the switch is malformed, an empty string is returned. +std::string GetClientToken(const base::CommandLine& cmd_line) { + std::string file_contents; + const base::FilePath path = cmd_line.GetSwitchValuePath(kClientTokenPath); + if (!base::ReadFileToString(path, &file_contents)) { + LOG(ERROR) << "Could not read client token file at " + << (path.empty() ? "(not provided)" : path.AsUTF8Unsafe()); + } + return base::CollapseWhitespaceASCII(file_contents, true); +} +} // namespace + +BlimpEngineConfig::~BlimpEngineConfig() {} + +// static +scoped_ptr<BlimpEngineConfig> BlimpEngineConfig::Create( + const base::CommandLine& cmd_line) { + const std::string client_token = GetClientToken(cmd_line); + if (!client_token.empty()) { + return make_scoped_ptr(new BlimpEngineConfig(client_token)); + } + return nullptr; +} + +// static +scoped_ptr<BlimpEngineConfig> BlimpEngineConfig::CreateForTest( + const std::string& client_token) { + return make_scoped_ptr(new BlimpEngineConfig(client_token)); +} + +const std::string& BlimpEngineConfig::client_token() const { + return client_token_; +} + +BlimpEngineConfig::BlimpEngineConfig(const std::string& client_token) + : client_token_(client_token) {} + +} // namespace engine +} // namespace blimp
diff --git a/blimp/engine/browser/blimp_engine_config.h b/blimp/engine/browser/blimp_engine_config.h new file mode 100644 index 0000000..0c46b9f --- /dev/null +++ b/blimp/engine/browser/blimp_engine_config.h
@@ -0,0 +1,58 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BLIMP_ENGINE_BROWSER_BLIMP_ENGINE_CONFIG_H_ +#define BLIMP_ENGINE_BROWSER_BLIMP_ENGINE_CONFIG_H_ + +#include <string> + +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" + +namespace base { +class CommandLine; +} // namespace base + +namespace blimp { +namespace engine { + +// Class to hold all of the configuration bits necessary for the Blimp engine. +// +// The BlimpEngineConfig class is initialized from parameters provided on the +// command line. For the switches to pass verification: +// * A client token filepath must be provided and the file must have a +// non-empty token. +// +// The BlimpEngineConfig object is intended to live as long as the engine is +// running. It should also be one of the first things to be set up. +class BlimpEngineConfig { + public: + ~BlimpEngineConfig(); + + // Attempts to create a BlimpEngineConfig based on the parameters in the + // specified CommandLine. This validates all of the command line switches + // and parses all files specified. Returns a non-null scoped_ptr on success. + static scoped_ptr<BlimpEngineConfig> Create( + const base::CommandLine& cmd_line); + + // Creates a BlimpEngineConfig based on individual components. Should only + // be used for testing. + static scoped_ptr<BlimpEngineConfig> CreateForTest( + const std::string& client_token); + + // Returns the client token. + const std::string& client_token() const; + + private: + explicit BlimpEngineConfig(const std::string& client_token); + + const std::string client_token_; + + DISALLOW_COPY_AND_ASSIGN(BlimpEngineConfig); +}; + +} // namespace engine +} // namespace blimp + +#endif // BLIMP_ENGINE_BROWSER_BLIMP_ENGINE_CONFIG_H_
diff --git a/blimp/engine/browser/blimp_engine_config_unittest.cc b/blimp/engine/browser/blimp_engine_config_unittest.cc new file mode 100644 index 0000000..2268a567 --- /dev/null +++ b/blimp/engine/browser/blimp_engine_config_unittest.cc
@@ -0,0 +1,86 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "blimp/engine/browser/blimp_engine_config.h" + +#include <string> +#include <vector> + +#include "base/command_line.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" +#include "base/memory/scoped_ptr.h" +#include "base/strings/stringprintf.h" +#include "blimp/engine/browser/switches.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace blimp { +namespace engine { +namespace { + +// Reference client token. +static const char kTestClientToken[] = "Reference client token"; + +class BlimpEngineConfigTest : public testing::Test { + protected: + void SetUp() override { + // Create a temporary directory and populate it with all of the switches + // If a test requires a switch's file to be missing, call + // RemoveFileForSwitch(). + ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); + CreateFileForSwitch(kClientTokenPath, kTestClientToken); + } + + // Creates a file in the temp directory for a given filepath switch. + void CreateFileForSwitch(const std::string& filepath_switch, + const std::string& data) const { + ASSERT_TRUE(base::WriteFile(GetFilepathForSwitch(filepath_switch), + data.c_str(), data.size())); + } + + // Removes the associated file for a given filepath switch. + void RemoveFileForSwitch(const std::string& filepath_switch) const { + base::DeleteFile(GetFilepathForSwitch(filepath_switch), false); + } + + // Creates and returns a CommandLine object with specified filepath switches. + base::CommandLine CreateCommandLine( + const std::vector<std::string>& filepath_switches) { + base::CommandLine::StringVector cmd_vec = {"dummy_program"}; + for (const std::string& filepath_switch : filepath_switches) { + cmd_vec.push_back(base::StringPrintf( + "--%s=%s", filepath_switch.c_str(), + GetFilepathForSwitch(filepath_switch).AsUTF8Unsafe().c_str())); + } + return base::CommandLine(cmd_vec); + } + + base::FilePath GetFilepathForSwitch( + const std::string& filepath_switch) const { + return temp_dir_.path().Append(filepath_switch); + } + + const std::vector<std::string> all_filepath_switches_ = {kClientTokenPath}; + + base::ScopedTempDir temp_dir_; +}; + +TEST_F(BlimpEngineConfigTest, ClientTokenCorrect) { + auto cmd_line = CreateCommandLine(all_filepath_switches_); + auto engine_config = BlimpEngineConfig::Create(cmd_line); + EXPECT_NE(nullptr, engine_config); + EXPECT_EQ(kTestClientToken, engine_config->client_token()); +} + +TEST_F(BlimpEngineConfigTest, ClientTokenEmpty) { + RemoveFileForSwitch(kClientTokenPath); + CreateFileForSwitch(kClientTokenPath, " "); + auto cmd_line = CreateCommandLine(all_filepath_switches_); + auto engine_config = BlimpEngineConfig::Create(cmd_line); + EXPECT_EQ(nullptr, engine_config); +} + +} // namespace +} // namespace engine +} // namespace blimp
diff --git a/blimp/engine/browser/switches.cc b/blimp/engine/browser/switches.cc new file mode 100644 index 0000000..3aca1f7 --- /dev/null +++ b/blimp/engine/browser/switches.cc
@@ -0,0 +1,13 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "blimp/engine/browser/switches.h" + +namespace blimp { +namespace engine { + +const char kClientTokenPath[] = "blimp-client-token-path"; + +} // namespace engine +} // namespace blimp
diff --git a/blimp/engine/browser/switches.h b/blimp/engine/browser/switches.h new file mode 100644 index 0000000..07096ff5 --- /dev/null +++ b/blimp/engine/browser/switches.h
@@ -0,0 +1,17 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef BLIMP_ENGINE_BROWSER_SWITCHES_H_ +#define BLIMP_ENGINE_BROWSER_SWITCHES_H_ + +namespace blimp { +namespace engine { + +// Path to the client token/shared secret between the engine and the client. +extern const char kClientTokenPath[]; + +} // namespace engine +} // namespace blimp + +#endif // BLIMP_ENGINE_BROWSER_SWITCHES_H_
diff --git a/build/android/devil/android/logcat_monitor.py b/build/android/devil/android/logcat_monitor.py index 179002a..24430d4 100644 --- a/build/android/devil/android/logcat_monitor.py +++ b/build/android/devil/android/logcat_monitor.py
@@ -4,6 +4,7 @@ # pylint: disable=unused-argument +import errno import logging import os import re @@ -194,7 +195,11 @@ """ self._StopRecording() if self._record_file and self._output_file: - os.makedirs(os.path.dirname(self._output_file)) + try: + os.makedirs(os.path.dirname(self._output_file)) + except OSError as e: + if e.errno != errno.EEXIST: + raise shutil.copy(self._record_file.name, self._output_file) def Close(self):
diff --git a/build/android/gyp/configure_multidex.py b/build/android/gyp/configure_multidex.py index aa85d2f..9f3b7360f 100755 --- a/build/android/gyp/configure_multidex.py +++ b/build/android/gyp/configure_multidex.py
@@ -6,23 +6,33 @@ import argparse import json +import os import sys from util import build_utils +_GCC_PREPROCESS_PATH = os.path.join( + os.path.dirname(__file__), 'gcc_preprocess.py') + + def ParseArgs(): parser = argparse.ArgumentParser() parser.add_argument('--configuration-name', required=True, help='The build CONFIGURATION_NAME.') + parser.add_argument('--enable-multidex', action='store_true', default=False, + help='If passed, multidex may be enabled.') parser.add_argument('--enabled-configurations', default=[], help='The configuration(s) for which multidex should be ' 'enabled. If not specified and --enable-multidex is ' 'passed, multidex will be enabled for all ' - 'configurations.') + 'configurations.') parser.add_argument('--multidex-configuration-path', required=True, help='The path to which the multidex configuration JSON ' 'should be saved.') + parser.add_argument('--multidex-config-java-file', required=True) + parser.add_argument('--multidex-config-java-stamp', required=True) + parser.add_argument('--multidex-config-java-template', required=True) args = parser.parse_args() @@ -33,20 +43,42 @@ return args -def main(): - args = ParseArgs() - - multidex_enabled = ( - (not args.enabled_configurations - or args.configuration_name in args.enabled_configurations)) - +def _WriteConfigJson(multidex_enabled, multidex_configuration_path): config = { 'enabled': multidex_enabled, } - with open(args.multidex_configuration_path, 'w') as f: + with open(multidex_configuration_path, 'w') as f: f.write(json.dumps(config)) + +def _GenerateMultidexConfigJava(multidex_enabled, args): + gcc_preprocess_cmd = [ + sys.executable, _GCC_PREPROCESS_PATH, + '--include-path=', + '--template', args.multidex_config_java_template, + '--stamp', args.multidex_config_java_stamp, + '--output', args.multidex_config_java_file, + ] + if multidex_enabled: + gcc_preprocess_cmd += [ + '--defines', 'ENABLE_MULTIDEX', + ] + + build_utils.CheckOutput(gcc_preprocess_cmd) + + +def main(): + args = ParseArgs() + + multidex_enabled = ( + args.enable_multidex + and (not args.enabled_configurations + or args.configuration_name in args.enabled_configurations)) + + _WriteConfigJson(multidex_enabled, args.multidex_configuration_path) + _GenerateMultidexConfigJava(multidex_enabled, args) + return 0
diff --git a/build/android/java_cpp_template.gypi b/build/android/java_cpp_template.gypi index f4ea0a9..3296659 100644 --- a/build/android/java_cpp_template.gypi +++ b/build/android/java_cpp_template.gypi
@@ -34,7 +34,6 @@ { # Location where all generated Java sources will be placed. 'variables': { - 'additional_gcc_preprocess_options': [], 'include_path%': '<(DEPTH)', 'output_dir': '<(SHARED_INTERMEDIATE_DIR)/templates/<(_target_name)/<(package_name)', }, @@ -75,7 +74,6 @@ '--include-path=<(include_path)', '--output=<(output_path)', '--template=<(RULE_INPUT_PATH)', - '<@(additional_gcc_preprocess_options)', ], 'message': 'Generating Java from cpp template <(RULE_INPUT_PATH)', }
diff --git a/build/android/pylib/instrumentation/test_package.py b/build/android/pylib/instrumentation/test_package.py index d6469b2..e2e3b77 100644 --- a/build/android/pylib/instrumentation/test_package.py +++ b/build/android/pylib/instrumentation/test_package.py
@@ -19,14 +19,23 @@ raise Exception('%s not found, please build it' % apk_path) self._additional_apks = additional_apks or [] self._apk_name = os.path.splitext(os.path.basename(apk_path))[0] - self._apk_path = apk_path - self._apk_under_test = apk_under_test - self._package_name = apk_helper.GetPackageName(self._apk_path) + if apk_under_test: + self._apk_under_test = apk_helper.ApkHelper(apk_under_test) + else: + self._apk_under_test = None + self._test_apk = apk_helper.ApkHelper(apk_path) self._test_support_apk_path = test_support_apk_path def GetApkPath(self): """Returns the absolute path to the APK.""" - return self._apk_path + return self._test_apk.path + + def GetApkUnderTest(self): + """Returns an ApkHelper instance for the apk under test. + + Note that --apk-under-test is not required, so this can be None. + """ + return self._apk_under_test def GetApkName(self): """Returns the name of the apk without the suffix.""" @@ -34,12 +43,16 @@ def GetPackageName(self): """Returns the package name of this APK.""" - return self._package_name + return self._test_apk.GetPackageName() + + def GetTestApk(self): + """Returns an ApkHelper instance for the test apk.""" + return self._test_apk # Override. def Install(self, device): if self._apk_under_test: - device.Install(self._apk_under_test) + device.Install(self._apk_under_test.path) device.Install(self.GetApkPath()) if (self._test_support_apk_path and os.path.exists(self._test_support_apk_path)):
diff --git a/build/android/pylib/instrumentation/test_runner.py b/build/android/pylib/instrumentation/test_runner.py index 7579bee..b4bbb621 100644 --- a/build/android/pylib/instrumentation/test_runner.py +++ b/build/android/pylib/instrumentation/test_runner.py
@@ -230,7 +230,10 @@ self.device.RunShellCommand( 'rm -f %s' % self.coverage_device_file) elif self.package_info: - self.device.ClearApplicationState(self.package_info.package) + apk_under_test = self.test_pkg.GetApkUnderTest() + permissions = apk_under_test.GetPermissions() if apk_under_test else None + self.device.ClearApplicationState( + self.package_info.package, permissions=permissions) def TearDownPerfMonitoring(self, test): """Cleans up performance monitoring if the specified test required it.
diff --git a/build/android/pylib/remote/device/dummy/dummy.gyp b/build/android/pylib/remote/device/dummy/dummy.gyp index b003edc..46e2d484 100644 --- a/build/android/pylib/remote/device/dummy/dummy.gyp +++ b/build/android/pylib/remote/device/dummy/dummy.gyp
@@ -7,13 +7,18 @@ # APK, so we build a dummy APK to upload as the app. { + 'variables': { + 'remote_device_dummy_apk_name': 'remote_device_dummy', + 'remote_device_dummy_apk_path': '<(PRODUCT_DIR)/apks/<(remote_device_dummy_apk_name).apk', + }, 'targets': [ { # GN: //build/android/pylib/remote/device/dummy:remote_device_dummy_apk 'target_name': 'remote_device_dummy_apk', 'type': 'none', 'variables': { - 'apk_name': 'remote_device_dummy', + 'apk_name': '<(remote_device_dummy_apk_name)', + 'final_apk_path': '<(remote_device_dummy_apk_path)', 'java_in_dir': '.', 'android_manifest_path': '../../../../../../build/android/AndroidManifest.xml', }, @@ -21,5 +26,22 @@ '../../../../../../build/java_apk.gypi', ] }, + { + 'target_name': 'require_remote_device_dummy_apk', + 'message': 'Making sure <(remote_device_dummy_apk_path) has been built.', + 'type': 'none', + 'variables': { + 'required_file': '<(PRODUCT_DIR)/remote_device_dummy_apk/<(remote_device_dummy_apk_name).apk.required', + }, + 'inputs': [ + '<(remote_device_dummy_apk_path)', + ], + 'outputs': [ + '<(required_file)', + ], + 'action': [ + 'python', '../../build/android/gyp/touch.py', '<(required_file)', + ], + } ] }
diff --git a/build/apk_browsertest.gypi b/build/apk_browsertest.gypi index 8cbc413..52cb9e0 100644 --- a/build/apk_browsertest.gypi +++ b/build/apk_browsertest.gypi
@@ -21,7 +21,7 @@ 'dependencies': [ '<(DEPTH)/base/base.gyp:base_java', '<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands', - '<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:remote_device_dummy_apk', + '<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:require_remote_device_dummy_apk', '<(DEPTH)/testing/android/appurify_support.gyp:appurify_support_java', '<(DEPTH)/testing/android/native_test.gyp:native_test_java', '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
diff --git a/build/apk_test.gypi b/build/apk_test.gypi index e0d323f..6512b6d 100644 --- a/build/apk_test.gypi +++ b/build/apk_test.gypi
@@ -21,7 +21,7 @@ 'dependencies': [ '<(DEPTH)/base/base.gyp:base_java', '<(DEPTH)/build/android/pylib/device/commands/commands.gyp:chromium_commands', - '<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:remote_device_dummy_apk', + '<(DEPTH)/build/android/pylib/remote/device/dummy/dummy.gyp:require_remote_device_dummy_apk', '<(DEPTH)/testing/android/appurify_support.gyp:appurify_support_java', '<(DEPTH)/testing/android/on_device_instrumentation.gyp:reporter_java', '<(DEPTH)/tools/android/android_tools.gyp:android_tools',
diff --git a/build/config/android/rules.gni b/build/config/android/rules.gni index da9a853..1c65d215 100644 --- a/build/config/android/rules.gni +++ b/build/config/android/rules.gni
@@ -1484,6 +1484,21 @@ _srcjar_deps += [ ":${_template_name}__native_libraries_java" ] } + if (!defined(invoker.apk_under_test)) { + java_cpp_template("${_template_name}__multidex_config_java") { + package_name = "org/chromium/base/multidex" + sources = [ + "//base/android/java/templates/ChromiumMultiDex.template", + ] + + defines = [] + if (enable_multidex) { + defines += [ "ENABLE_MULTIDEX" ] + } + } + _srcjar_deps += [ ":${_template_name}__multidex_config_java" ] + } + java_target = "${_template_name}__java" java_library_impl(java_target) { forward_variables_from(invoker, [ "run_findbugs" ]) @@ -2018,11 +2033,13 @@ native_libs = [ unittests_binary ] deps += [ "//base:base_java", - "//build/android/pylib/remote/device/dummy:remote_device_dummy_apk", "//testing/android/appurify_support:appurify_support_java", "//testing/android/reporter:reporter_java", ] - data_deps += [ "//tools/android/md5sum" ] + data_deps += [ + "//build/android/pylib/remote/device/dummy:remote_device_dummy_apk", + "//tools/android/md5sum", + ] if (host_os == "linux") { data_deps += [ "//tools/android/forwarder2" ] }
diff --git a/build/java_apk.gypi b/build/java_apk.gypi index ab49dc6..f8e5231 100644 --- a/build/java_apk.gypi +++ b/build/java_apk.gypi
@@ -77,6 +77,7 @@ 'tested_apk_obfuscated_jar_path%': '/', 'tested_apk_dex_path%': '/', 'tested_apk_is_multidex%': 0, + 'tested_apk_generated_multidex_config%': 0, 'additional_input_paths': [], 'additional_locale_input_paths': [], 'create_density_splits%': 0, @@ -121,6 +122,11 @@ 'native_libraries_template_data_dir': '<(intermediate_dir)/native_libraries/', 'native_libraries_template_data_file': '<(native_libraries_template_data_dir)/native_libraries_array.h', 'native_libraries_template_version_file': '<(native_libraries_template_data_dir)/native_libraries_version.h', + 'generate_multidex_config%': 0, + 'multidex_config_template': '<(DEPTH)/base/android/java/templates/ChromiumMultiDex.template', + 'multidex_config_java_dir': '<(intermediate_dir)/multidex_config/', + 'multidex_config_java_file': '<(multidex_config_java_dir)/ChromiumMultiDex.java', + 'multidex_config_java_stamp': '<(intermediate_dir)/multidex_config_java.stamp', 'compile_stamp': '<(intermediate_dir)/compile.stamp', 'lint_stamp': '<(intermediate_dir)/lint.stamp', 'lint_result': '<(intermediate_dir)/lint_result.xml', @@ -266,6 +272,7 @@ 'tested_apk_obfuscated_jar_path': '<(obfuscated_jar_path)', 'tested_apk_dex_path': '<(dex_path)', 'tested_apk_is_multidex': '<(enable_multidex)', + 'tested_apk_generated_multidex_config': '>(generate_multidex_config)', } }] ], @@ -794,37 +801,58 @@ }, ], }], - ['enable_multidex == 1', { + ], + 'target_conditions': [ + ['generate_multidex_config == 1 and tested_apk_generated_multidex_config == 0', { + 'variables': { + 'generated_src_dirs': ['<(multidex_config_java_dir)'], + }, 'actions': [ { - 'action_name': 'main_dex_list_for_<(_target_name)', - 'variables': { - 'jar_paths': ['>@(input_jars_paths)', '<(javac_jar_path)'], - 'output_path': '<(main_dex_list_path)', - }, - 'includes': [ 'android/main_dex_action.gypi' ], - }, - { 'action_name': 'configure_multidex_for_<(_target_name)', 'inputs': [ '<(DEPTH)/build/android/gyp/configure_multidex.py', + '<(multidex_config_template)', ], 'outputs': [ '<(multidex_configuration_path)', + '<(multidex_config_java_stamp)', ], 'variables': { 'additional_multidex_config_options': [], - 'enabled_configurations': ['>@(enable_multidex_configurations)'], + 'enabled_configurations': '>(enable_multidex_configurations)', + 'conditions': [ + ['enable_multidex == 1', { + 'additional_multidex_config_options': ['--enable-multidex'], + }], + ], }, 'action': [ 'python', '<(DEPTH)/build/android/gyp/configure_multidex.py', '--configuration-name', '<(CONFIGURATION_NAME)', '--enabled-configurations', '<(enabled_configurations)', '--multidex-configuration-path', '<(multidex_configuration_path)', + '--multidex-config-java-template', '<(multidex_config_template)', + '--multidex-config-java-file', '<(multidex_config_java_file)', + '--multidex-config-java-stamp', '<(multidex_config_java_stamp)', '>@(additional_multidex_config_options)', ], }, ], + 'conditions': [ + ['enable_multidex == 1', { + 'actions': [ + { + 'action_name': 'main_dex_list_for_<(_target_name)', + 'variables': { + 'jar_paths': ['>@(input_jars_paths)', '<(javac_jar_path)'], + 'output_path': '<(main_dex_list_path)', + }, + 'includes': [ 'android/main_dex_action.gypi' ], + }, + ] + }] + ], }], ], 'dependencies': [ @@ -956,6 +984,11 @@ 'inputs': [ '<(native_libraries_java_stamp)' ], }], ], + 'target_conditions': [ + ['generate_multidex_config == 1 and tested_apk_generated_multidex_config == 0', { + 'inputs': [ '<(multidex_config_java_stamp)' ], + }], + ], 'outputs': [ '<(compile_stamp)', '<(javac_jar_path)',
diff --git a/build/toolchain/win/BUILD.gn b/build/toolchain/win/BUILD.gn index 0233353..4fb7279 100644 --- a/build/toolchain/win/BUILD.gn +++ b/build/toolchain/win/BUILD.gn
@@ -235,6 +235,12 @@ } } +if (host_os == "win") { + clang_cl = "clang-cl.exe" +} else { + clang_cl = "clang-cl" +} + # 32-bit toolchains. Only define these when the target architecture is 32-bit # since we don't do any 32-bit cross compiles when targeting 64-bit (the # build does generate some 64-bit stuff from 32-bit target builds). @@ -261,7 +267,7 @@ toolchain_cpu = "x86" prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", root_build_dir) - cl = "${goma_prefix}$prefix/clang-cl.exe" + cl = "${goma_prefix}$prefix/${clang_cl}" toolchain_os = "win" is_clang = true } @@ -290,7 +296,7 @@ toolchain_cpu = "x64" prefix = rebase_path("//third_party/llvm-build/Release+Asserts/bin", root_build_dir) - cl = "${goma_prefix}$prefix/clang-cl.exe" + cl = "${goma_prefix}$prefix/${clang_cl}" toolchain_os = "win" is_clang = true }
diff --git a/build/vs_toolchain.py b/build/vs_toolchain.py index ed0042b..6a0e6c95 100755 --- a/build/vs_toolchain.py +++ b/build/vs_toolchain.py
@@ -21,6 +21,10 @@ import gyp +# Use MSVS2013 as the default toolchain. +CURRENT_DEFAULT_TOOLCHAIN_VERSION = '2013' + + def SetEnvironmentAndGetRuntimeDllDirs(): """Sets up os.environ to use the depot_tools VS toolchain with gyp, and returns the location of the VS runtime DLLs so they can be copied into @@ -33,7 +37,7 @@ # been downloaded before (in which case json_data_file will exist). if ((sys.platform in ('win32', 'cygwin') or os.path.exists(json_data_file)) and depot_tools_win_toolchain): - if not os.path.exists(json_data_file): + if ShouldUpdateToolchain(): Update() with open(json_data_file, 'r') as tempf: toolchain_data = json.load(tempf) @@ -99,9 +103,9 @@ def GetVisualStudioVersion(): - """Return GYP_MSVS_VERSION of Visual Studio, default to 2013 for now. + """Return GYP_MSVS_VERSION of Visual Studio. """ - return os.environ.get('GYP_MSVS_VERSION', '2013') + return os.environ.get('GYP_MSVS_VERSION', CURRENT_DEFAULT_TOOLCHAIN_VERSION) def DetectVisualStudioPath(): @@ -184,6 +188,9 @@ suffix = "d.dll" if debug else ".dll" if GetVisualStudioVersion() == '2015': _CopyRuntime2015(target_dir, source_dir, '%s140' + suffix) + if debug: + _CopyRuntimeImpl(os.path.join(target_dir, 'ucrtbased.dll'), + os.path.join(source_dir, 'ucrtbased.dll')) else: _CopyRuntime2013(target_dir, source_dir, 'msvc%s120' + suffix) @@ -262,12 +269,26 @@ """Load a list of SHA1s corresponding to the toolchains that we want installed to build with.""" if GetVisualStudioVersion() == '2015': - return ['17c7ddb3595be5c6b9c98b6f930adad7e4456671'] # Update 1 + # Update 1 with Debuggers, UCRT installers and ucrtbased.dll + return ['524956ec6e64e68fead3773e3ce318537657b404'] else: # Default to VS2013. return ['9ff97c632ae1fee0c98bcd53e71770eb3a0d8deb'] +def ShouldUpdateToolchain(): + """Check if the toolchain should be upgraded.""" + if not os.path.exists(json_data_file): + return True + with open(json_data_file, 'r') as tempf: + toolchain_data = json.load(tempf) + version = toolchain_data['version'] + env_version = GetVisualStudioVersion() + # If there's a mismatch between the version set in the environment and the one + # in the json file then the toolchain should be updated. + return version != env_version + + def Update(force=False): """Requests an update of the toolchain to the specific hashes we have at this revision. The update outputs a .json of the various configuration
diff --git a/cc/BUILD.gn b/cc/BUILD.gn index 353958d..50f7858f 100644 --- a/cc/BUILD.gn +++ b/cc/BUILD.gn
@@ -317,6 +317,8 @@ "playback/largest_display_item.h", "playback/transform_display_item.cc", "playback/transform_display_item.h", + "proto/base_conversions.cc", + "proto/base_conversions.h", "proto/cc_conversions.cc", "proto/cc_conversions.h", "proto/gfx_conversions.cc", @@ -838,6 +840,7 @@ "playback/display_item_list_unittest.cc", "playback/display_list_raster_source_unittest.cc", "playback/display_list_recording_source_unittest.cc", + "proto/base_conversions_unittest.cc", "proto/cc_conversions_unittest.cc", "proto/gfx_conversions_unittest.cc", "proto/gpu_conversions_unittest.cc", @@ -900,6 +903,7 @@ "trees/occlusion_tracker_unittest.cc", "trees/occlusion_unittest.cc", "trees/property_tree_unittest.cc", + "trees/proxy_common_unittest.cc", "trees/proxy_impl_unittest.cc", "trees/threaded_channel_unittest.cc", "trees/tree_synchronizer_unittest.cc",
diff --git a/cc/animation/animation_delegate.h b/cc/animation/animation_delegate.h index 8c736b5..6064c7e 100644 --- a/cc/animation/animation_delegate.h +++ b/cc/animation/animation_delegate.h
@@ -20,6 +20,10 @@ Animation::TargetProperty target_property, int group) = 0; + virtual void NotifyAnimationAborted(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) = 0; + protected: virtual ~AnimationDelegate() {} };
diff --git a/cc/animation/animation_host.cc b/cc/animation/animation_host.cc index 59ce274..1df11d09 100644 --- a/cc/animation/animation_host.cc +++ b/cc/animation/animation_host.cc
@@ -114,6 +114,9 @@ DCHECK(animation_host_->mutator_host_client()); animation_host_->mutator_host_client()->ScrollOffsetAnimationFinished(); } + void NotifyAnimationAborted(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) override {} private: void ReattachScrollOffsetPlayerIfNeeded(int layer_id) {
diff --git a/cc/animation/animation_player.cc b/cc/animation/animation_player.cc index dd7cb1f..52fa9a8 100644 --- a/cc/animation/animation_player.cc +++ b/cc/animation/animation_player.cc
@@ -203,6 +203,15 @@ target_property, group); } +void AnimationPlayer::NotifyAnimationAborted( + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) { + if (layer_animation_delegate_) + layer_animation_delegate_->NotifyAnimationAborted(monotonic_time, + target_property, group); +} + void AnimationPlayer::SetNeedsCommit() { DCHECK(animation_host_); animation_host_->SetNeedsCommit();
diff --git a/cc/animation/animation_player.h b/cc/animation/animation_player.h index 396d977c..4902ec4 100644 --- a/cc/animation/animation_player.h +++ b/cc/animation/animation_player.h
@@ -80,6 +80,9 @@ void NotifyAnimationFinished(base::TimeTicks monotonic_time, Animation::TargetProperty target_property, int group); + void NotifyAnimationAborted(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group); private: friend class base::RefCounted<AnimationPlayer>;
diff --git a/cc/animation/element_animations.cc b/cc/animation/element_animations.cc index 1264718..cd3a736 100644 --- a/cc/animation/element_animations.cc +++ b/cc/animation/element_animations.cc
@@ -259,6 +259,17 @@ } } +void ElementAnimations::NotifyAnimationAborted( + base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) { + for (PlayersListNode* node = players_list_->head(); + node != players_list_->end(); node = node->next()) { + AnimationPlayer* player = node->value(); + player->NotifyAnimationAborted(monotonic_time, target_property, group); + } +} + gfx::ScrollOffset ElementAnimations::ScrollOffsetForAnimation() const { DCHECK(layer_animation_controller_); if (animation_host()) {
diff --git a/cc/animation/element_animations.h b/cc/animation/element_animations.h index de76291..7a9cd93 100644 --- a/cc/animation/element_animations.h +++ b/cc/animation/element_animations.h
@@ -100,6 +100,9 @@ void NotifyAnimationFinished(base::TimeTicks monotonic_time, Animation::TargetProperty target_property, int group) override; + void NotifyAnimationAborted(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) override; // LayerAnimationValueProvider implementation. gfx::ScrollOffset ScrollOffsetForAnimation() const override;
diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc index e4e4513..8d779515 100644 --- a/cc/animation/layer_animation_controller.cc +++ b/cc/animation/layer_animation_controller.cc
@@ -461,6 +461,9 @@ animations_[i]->target_property() == event.target_property) { animations_[i]->SetRunState(Animation::ABORTED, event.monotonic_time); animations_[i]->set_received_finished_event(true); + if (layer_animation_delegate_) + layer_animation_delegate_->NotifyAnimationAborted( + event.monotonic_time, event.target_property, event.group_id); if (event.target_property == Animation::TRANSFORM) aborted_transform_animation = true; }
diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc index 850123c..2f5f37e 100644 --- a/cc/animation/layer_animation_controller_unittest.cc +++ b/cc/animation/layer_animation_controller_unittest.cc
@@ -1018,7 +1018,10 @@ class FakeAnimationDelegate : public AnimationDelegate { public: FakeAnimationDelegate() - : started_(false), finished_(false), start_time_(base::TimeTicks()) {} + : started_(false), + finished_(false), + aborted_(false), + start_time_(base::TimeTicks()) {} void NotifyAnimationStarted(TimeTicks monotonic_time, Animation::TargetProperty target_property, @@ -1033,15 +1036,24 @@ finished_ = true; } + void NotifyAnimationAborted(TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) override { + aborted_ = true; + } + bool started() { return started_; } bool finished() { return finished_; } + bool aborted() { return aborted_; } + TimeTicks start_time() { return start_time_; } private: bool started_; bool finished_; + bool aborted_; TimeTicks start_time_; }; @@ -1843,6 +1855,8 @@ scoped_refptr<LayerAnimationController> controller( LayerAnimationController::Create(0)); controller->AddValueObserver(&dummy); + FakeAnimationDelegate delegate; + controller->set_layer_animation_delegate(&delegate); int animation_id = AddOpacityTransitionToController(controller.get(), 1.0, 0.f, 1.f, false); @@ -1869,6 +1883,7 @@ controller->NotifyAnimationAborted(events.events_[0]); EXPECT_EQ(Animation::ABORTED, controller->GetAnimation(Animation::OPACITY)->run_state()); + EXPECT_TRUE(delegate.aborted()); controller->Animate(kInitialTickTime + TimeDelta::FromMilliseconds(500)); controller->UpdateState(true, nullptr);
diff --git a/cc/blink/web_compositor_animation_player_unittest.cc b/cc/blink/web_compositor_animation_player_unittest.cc index 8a3b1544..ec355b1 100644 --- a/cc/blink/web_compositor_animation_player_unittest.cc +++ b/cc/blink/web_compositor_animation_player_unittest.cc
@@ -25,6 +25,7 @@ MOCK_METHOD2(notifyAnimationStarted, void(double, int)); MOCK_METHOD2(notifyAnimationFinished, void(double, int)); + MOCK_METHOD2(notifyAnimationAborted, void(double, int)); }; // Test that when the animation delegate is null, the animation player
diff --git a/cc/blink/web_to_cc_animation_delegate_adapter.cc b/cc/blink/web_to_cc_animation_delegate_adapter.cc index fcec11f..3bdf0d4 100644 --- a/cc/blink/web_to_cc_animation_delegate_adapter.cc +++ b/cc/blink/web_to_cc_animation_delegate_adapter.cc
@@ -40,4 +40,12 @@ #endif } +void WebToCCAnimationDelegateAdapter::NotifyAnimationAborted( + base::TimeTicks monotonic_time, + cc::Animation::TargetProperty target_property, + int group) { + delegate_->notifyAnimationAborted( + (monotonic_time - base::TimeTicks()).InSecondsF(), group); +} + } // namespace cc_blink
diff --git a/cc/blink/web_to_cc_animation_delegate_adapter.h b/cc/blink/web_to_cc_animation_delegate_adapter.h index 72e79e6..343afa5 100644 --- a/cc/blink/web_to_cc_animation_delegate_adapter.h +++ b/cc/blink/web_to_cc_animation_delegate_adapter.h
@@ -27,6 +27,9 @@ void NotifyAnimationFinished(base::TimeTicks monotonic_time, cc::Animation::TargetProperty target_property, int group) override; + void NotifyAnimationAborted(base::TimeTicks monotonic_time, + cc::Animation::TargetProperty target_property, + int group) override; blink::WebCompositorAnimationDelegate* delegate_;
diff --git a/cc/cc.gyp b/cc/cc.gyp index 7ad323a6..8c23643 100644 --- a/cc/cc.gyp +++ b/cc/cc.gyp
@@ -379,6 +379,8 @@ 'playback/largest_display_item.h', 'playback/transform_display_item.cc', 'playback/transform_display_item.h', + 'proto/base_conversions.cc', + 'proto/base_conversions.h', 'proto/cc_conversions.cc', 'proto/cc_conversions.h', 'proto/gfx_conversions.cc', @@ -605,6 +607,7 @@ 'target_name': 'cc_proto', 'type': '<(component)', 'sources': [ + 'proto/begin_main_frame_and_commit_state.proto', 'proto/commit_earlyout_reason.proto', 'proto/compositor_message.proto', 'proto/display_item.proto', @@ -632,6 +635,7 @@ 'proto/skrrect.proto', 'proto/skxfermode.proto', 'proto/transform.proto', + 'proto/vector2d.proto', 'proto/vector2df.proto', ], 'defines': [
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp index 0d5f6b1..646c907 100644 --- a/cc/cc_tests.gyp +++ b/cc/cc_tests.gyp
@@ -90,6 +90,7 @@ 'playback/display_item_list_unittest.cc', 'playback/display_list_raster_source_unittest.cc', 'playback/display_list_recording_source_unittest.cc', + 'proto/base_conversions_unittest.cc', 'proto/cc_conversions_unittest.cc', 'proto/gfx_conversions_unittest.cc', 'proto/gpu_conversions_unittest.cc', @@ -152,6 +153,7 @@ 'trees/occlusion_tracker_unittest.cc', 'trees/occlusion_unittest.cc', 'trees/property_tree_unittest.cc', + 'trees/proxy_common_unittest.cc', 'trees/proxy_impl_unittest.cc', 'trees/threaded_channel_unittest.cc', 'trees/tree_synchronizer_unittest.cc',
diff --git a/cc/layers/heads_up_display_layer.cc b/cc/layers/heads_up_display_layer.cc index 388c2ad2..158186f 100644 --- a/cc/layers/heads_up_display_layer.cc +++ b/cc/layers/heads_up_display_layer.cc
@@ -8,6 +8,7 @@ #include "base/trace_event/trace_event.h" #include "cc/layers/heads_up_display_layer_impl.h" +#include "cc/proto/layer.pb.h" #include "cc/trees/layer_tree_host.h" namespace cc { @@ -61,4 +62,9 @@ return HeadsUpDisplayLayerImpl::Create(tree_impl, layer_id_); } +void HeadsUpDisplayLayer::SetTypeForProtoSerialization( + proto::LayerNode* proto) const { + proto->set_type(proto::LayerType::HEADS_UP_DISPLAY_LAYER); +} + } // namespace cc
diff --git a/cc/layers/heads_up_display_layer.h b/cc/layers/heads_up_display_layer.h index 5ffa31aa..554d33e 100644 --- a/cc/layers/heads_up_display_layer.h +++ b/cc/layers/heads_up_display_layer.h
@@ -14,6 +14,10 @@ namespace cc { +namespace proto { +class LayerNode; +} // namespace proto + class CC_EXPORT HeadsUpDisplayLayer : public Layer { public: static scoped_refptr<HeadsUpDisplayLayer> Create( @@ -24,6 +28,8 @@ scoped_ptr<LayerImpl> CreateLayerImpl(LayerTreeImpl* tree_impl) override; + void SetTypeForProtoSerialization(proto::LayerNode* proto) const override; + protected: explicit HeadsUpDisplayLayer(const LayerSettings& settings); bool HasDrawableContent() const override;
diff --git a/cc/layers/layer.cc b/cc/layers/layer.cc index 238c234..cc2cbbb 100644 --- a/cc/layers/layer.cc +++ b/cc/layers/layer.cc
@@ -1162,6 +1162,7 @@ } void Layer::PushPropertiesTo(LayerImpl* layer) { + TRACE_EVENT0("cc", "Layer::PushPropertiesTo"); DCHECK(layer_tree_host_); // If we did not SavePaintProperties() for the layer this frame, then push the @@ -1284,26 +1285,28 @@ layer->PushScrollOffsetFromMainThread(scroll_offset_); layer->SetScrollCompensationAdjustment(ScrollCompensationAdjustment()); - // Wrap the copy_requests_ in a PostTask to the main thread. - std::vector<scoped_ptr<CopyOutputRequest>> main_thread_copy_requests; - for (auto it = copy_requests_.begin(); it != copy_requests_.end(); ++it) { - scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner = - layer_tree_host()->task_runner_provider()->MainThreadTaskRunner(); - scoped_ptr<CopyOutputRequest> original_request = std::move(*it); - const CopyOutputRequest& original_request_ref = *original_request; - scoped_ptr<CopyOutputRequest> main_thread_request = - CopyOutputRequest::CreateRelayRequest( - original_request_ref, - base::Bind(&PostCopyCallbackToMainThread, - main_thread_task_runner, - base::Passed(&original_request))); - main_thread_copy_requests.push_back(std::move(main_thread_request)); - } - if (!copy_requests_.empty() && layer_tree_host_) - layer_tree_host_->property_trees()->needs_rebuild = true; + { + TRACE_EVENT0("cc", "Layer::PushPropertiesTo::CopyOutputRequests"); + // Wrap the copy_requests_ in a PostTask to the main thread. + std::vector<scoped_ptr<CopyOutputRequest>> main_thread_copy_requests; + for (auto it = copy_requests_.begin(); it != copy_requests_.end(); ++it) { + scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner = + layer_tree_host()->task_runner_provider()->MainThreadTaskRunner(); + scoped_ptr<CopyOutputRequest> original_request = std::move(*it); + const CopyOutputRequest& original_request_ref = *original_request; + scoped_ptr<CopyOutputRequest> main_thread_request = + CopyOutputRequest::CreateRelayRequest( + original_request_ref, + base::Bind(&PostCopyCallbackToMainThread, main_thread_task_runner, + base::Passed(&original_request))); + main_thread_copy_requests.push_back(std::move(main_thread_request)); + } + if (!copy_requests_.empty() && layer_tree_host_) + layer_tree_host_->property_trees()->needs_rebuild = true; - copy_requests_.clear(); - layer->PassCopyRequests(&main_thread_copy_requests); + copy_requests_.clear(); + layer->PassCopyRequests(&main_thread_copy_requests); + } // If the main thread commits multiple times before the impl thread actually // draws, then damage tracking will become incorrect if we simply clobber the
diff --git a/cc/layers/layer_impl.h b/cc/layers/layer_impl.h index 990a384..4dca350 100644 --- a/cc/layers/layer_impl.h +++ b/cc/layers/layer_impl.h
@@ -125,6 +125,9 @@ void NotifyAnimationFinished(base::TimeTicks monotonic_time, Animation::TargetProperty target_property, int group) override; + void NotifyAnimationAborted(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) override{}; // Tree structure. LayerImpl* parent() { return parent_; }
diff --git a/cc/layers/layer_proto_converter.cc b/cc/layers/layer_proto_converter.cc index 086ad99..399985c 100644 --- a/cc/layers/layer_proto_converter.cc +++ b/cc/layers/layer_proto_converter.cc
@@ -6,6 +6,7 @@ #include "base/stl_util.h" #include "cc/layers/empty_content_layer_client.h" +#include "cc/layers/heads_up_display_layer.h" #include "cc/layers/layer.h" #include "cc/layers/layer_settings.h" #include "cc/layers/picture_layer.h" @@ -116,6 +117,8 @@ case proto::PICTURE_LAYER: return PictureLayer::Create(LayerSettings(), EmptyContentLayerClient::GetInstance()); + case proto::HEADS_UP_DISPLAY_LAYER: + return HeadsUpDisplayLayer::Create(LayerSettings()); } // TODO(nyquist): Add the rest of the necessary LayerTypes. This function // should not return null.
diff --git a/cc/layers/layer_proto_converter_unittest.cc b/cc/layers/layer_proto_converter_unittest.cc index 3aa74d3..fbd13e1 100644 --- a/cc/layers/layer_proto_converter_unittest.cc +++ b/cc/layers/layer_proto_converter_unittest.cc
@@ -5,6 +5,7 @@ #include "cc/layers/layer_proto_converter.h" #include "cc/layers/empty_content_layer_client.h" +#include "cc/layers/heads_up_display_layer.h" #include "cc/layers/layer.h" #include "cc/layers/layer_settings.h" #include "cc/layers/picture_layer.h" @@ -403,5 +404,37 @@ EXPECT_EQ(proto::LayerType::PICTURE_LAYER, layer_node.type()); } +TEST_F(LayerProtoConverterTest, HudLayerTypeSerialization) { + // Make sure that PictureLayers serialize to the + // proto::LayerType::HEADS_UP_DISPLAY_LAYER type. + scoped_refptr<HeadsUpDisplayLayer> layer = + HeadsUpDisplayLayer::Create(LayerSettings()); + + proto::LayerNode layer_hierarchy; + LayerProtoConverter::SerializeLayerHierarchy(layer.get(), &layer_hierarchy); + EXPECT_EQ(proto::LayerType::HEADS_UP_DISPLAY_LAYER, layer_hierarchy.type()); +} + +TEST_F(LayerProtoConverterTest, HudLayerTypeDeserialization) { + // Make sure that proto::LayerType::HEADS_UP_DISPLAY_LAYER ends up building a + // HeadsUpDisplayLayer. + scoped_refptr<Layer> old_root = HeadsUpDisplayLayer::Create(LayerSettings()); + proto::LayerNode root_node; + root_node.set_id(old_root->id()); + root_node.set_type(proto::LayerType::HEADS_UP_DISPLAY_LAYER); + + scoped_refptr<Layer> new_root = + LayerProtoConverter::DeserializeLayerHierarchy(old_root, root_node); + + // Validate that the ids are equal. + EXPECT_EQ(old_root->id(), new_root->id()); + + // Check that the layer type is equal by using the type this layer would + // serialize to. + proto::LayerNode layer_node; + new_root->SetTypeForProtoSerialization(&layer_node); + EXPECT_EQ(proto::LayerType::HEADS_UP_DISPLAY_LAYER, layer_node.type()); +} + } // namespace } // namespace cc
diff --git a/cc/layers/nine_patch_layer.cc b/cc/layers/nine_patch_layer.cc index 575090c..26bb584 100644 --- a/cc/layers/nine_patch_layer.cc +++ b/cc/layers/nine_patch_layer.cc
@@ -4,6 +4,7 @@ #include "cc/layers/nine_patch_layer.h" +#include "base/trace_event/trace_event.h" #include "cc/layers/nine_patch_layer_impl.h" #include "cc/resources/scoped_ui_resource.h" #include "cc/resources/ui_resource_bitmap.h" @@ -52,6 +53,7 @@ void NinePatchLayer::PushPropertiesTo(LayerImpl* layer) { UIResourceLayer::PushPropertiesTo(layer); + TRACE_EVENT0("cc", "NinePatchLayer::PushPropertiesTo"); NinePatchLayerImpl* layer_impl = static_cast<NinePatchLayerImpl*>(layer); if (!ui_resource_holder_) {
diff --git a/cc/layers/painted_scrollbar_layer.cc b/cc/layers/painted_scrollbar_layer.cc index 13826e7..aabde35 100644 --- a/cc/layers/painted_scrollbar_layer.cc +++ b/cc/layers/painted_scrollbar_layer.cc
@@ -7,7 +7,6 @@ #include <algorithm> #include "base/auto_reset.h" -#include "base/trace_event/trace_event.h" #include "cc/base/math_util.h" #include "cc/layers/painted_scrollbar_layer_impl.h" #include "cc/resources/ui_resource_bitmap.h"
diff --git a/cc/layers/picture_layer.cc b/cc/layers/picture_layer.cc index 284f2a3..f9df22cd 100644 --- a/cc/layers/picture_layer.cc +++ b/cc/layers/picture_layer.cc
@@ -5,6 +5,7 @@ #include "cc/layers/picture_layer.h" #include "base/auto_reset.h" +#include "base/trace_event/trace_event.h" #include "cc/layers/content_layer_client.h" #include "cc/layers/picture_layer_impl.h" #include "cc/playback/display_list_recording_source.h" @@ -50,6 +51,7 @@ void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) { Layer::PushPropertiesTo(base_layer); + TRACE_EVENT0("cc", "PictureLayer::PushPropertiesTo"); PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer); // TODO(danakj): Make is_mask_ a constructor parameter for PictureLayer. DCHECK_EQ(layer_impl->is_mask(), is_mask_);
diff --git a/cc/layers/surface_layer.cc b/cc/layers/surface_layer.cc index 21f9273..71ceb46 100644 --- a/cc/layers/surface_layer.cc +++ b/cc/layers/surface_layer.cc
@@ -7,6 +7,7 @@ #include <stdint.h> #include "base/macros.h" +#include "base/trace_event/trace_event.h" #include "cc/layers/surface_layer_impl.h" #include "cc/output/swap_promise.h" #include "cc/trees/layer_tree_host.h" @@ -94,6 +95,7 @@ void SurfaceLayer::PushPropertiesTo(LayerImpl* layer) { Layer::PushPropertiesTo(layer); + TRACE_EVENT0("cc", "SurfaceLayer::PushPropertiesTo"); SurfaceLayerImpl* layer_impl = static_cast<SurfaceLayerImpl*>(layer); layer_impl->SetSurfaceId(surface_id_);
diff --git a/cc/layers/texture_layer.cc b/cc/layers/texture_layer.cc index 952078d5..85df0f2 100644 --- a/cc/layers/texture_layer.cc +++ b/cc/layers/texture_layer.cc
@@ -8,6 +8,7 @@ #include "base/callback_helpers.h" #include "base/location.h" #include "base/synchronization/lock.h" +#include "base/trace_event/trace_event.h" #include "cc/base/simple_enclosed_region.h" #include "cc/layers/texture_layer_client.h" #include "cc/layers/texture_layer_impl.h" @@ -226,6 +227,7 @@ void TextureLayer::PushPropertiesTo(LayerImpl* layer) { Layer::PushPropertiesTo(layer); + TRACE_EVENT0("cc", "TextureLayer::PushPropertiesTo"); TextureLayerImpl* texture_layer = static_cast<TextureLayerImpl*>(layer); texture_layer->SetFlipped(flipped_);
diff --git a/cc/layers/ui_resource_layer.cc b/cc/layers/ui_resource_layer.cc index 87512ebd..6b5f8779 100644 --- a/cc/layers/ui_resource_layer.cc +++ b/cc/layers/ui_resource_layer.cc
@@ -4,6 +4,7 @@ #include "cc/layers/ui_resource_layer.h" +#include "base/trace_event/trace_event.h" #include "cc/layers/ui_resource_layer_impl.h" #include "cc/resources/scoped_ui_resource.h" #include "cc/resources/ui_resource_bitmap.h" @@ -149,6 +150,7 @@ void UIResourceLayer::PushPropertiesTo(LayerImpl* layer) { Layer::PushPropertiesTo(layer); + TRACE_EVENT0("cc", "UIResourceLayer::PushPropertiesTo"); UIResourceLayerImpl* layer_impl = static_cast<UIResourceLayerImpl*>(layer); if (!ui_resource_holder_) {
diff --git a/cc/output/begin_frame_args.cc b/cc/output/begin_frame_args.cc index 216eb52..c50d5f83 100644 --- a/cc/output/begin_frame_args.cc +++ b/cc/output/begin_frame_args.cc
@@ -5,6 +5,8 @@ #include "cc/output/begin_frame_args.h" #include "base/trace_event/trace_event_argument.h" +#include "cc/proto/base_conversions.h" +#include "cc/proto/begin_main_frame_and_commit_state.pb.h" namespace cc { @@ -23,6 +25,44 @@ return "???"; } +void BeginFrameArgs::BeginFrameArgsTypeToProtobuf( + proto::BeginFrameArgs* proto) const { + switch (type) { + case BeginFrameArgs::INVALID: + proto->set_type(proto::BeginFrameArgs::INVALID); + return; + case BeginFrameArgs::NORMAL: + proto->set_type(proto::BeginFrameArgs::NORMAL); + return; + case BeginFrameArgs::MISSED: + proto->set_type(proto::BeginFrameArgs::MISSED); + return; + case BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX: + proto->set_type(proto::BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX); + return; + } + NOTREACHED(); +} + +void BeginFrameArgs::BeginFrameArgsTypeFromProtobuf( + const proto::BeginFrameArgs& proto) { + switch (proto.type()) { + case proto::BeginFrameArgs::INVALID: + type = BeginFrameArgs::INVALID; + return; + case proto::BeginFrameArgs::NORMAL: + type = BeginFrameArgs::NORMAL; + return; + case proto::BeginFrameArgs::MISSED: + type = BeginFrameArgs::MISSED; + return; + case proto::BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX: + type = BeginFrameArgs::BEGIN_FRAME_ARGS_TYPE_MAX; + return; + } + NOTREACHED(); +} + BeginFrameArgs::BeginFrameArgs() : frame_time(base::TimeTicks()), deadline(base::TimeTicks()), @@ -78,6 +118,22 @@ state->SetBoolean("on_critical_path", on_critical_path); } +void BeginFrameArgs::ToProtobuf(proto::BeginFrameArgs* proto) const { + proto->set_frame_time(TimeTicksToProto(frame_time)); + proto->set_deadline(TimeTicksToProto(deadline)); + proto->set_interval(interval.ToInternalValue()); + BeginFrameArgsTypeToProtobuf(proto); + proto->set_on_critical_path(on_critical_path); +} + +void BeginFrameArgs::FromProtobuf(const proto::BeginFrameArgs& proto) { + frame_time = ProtoToTimeTicks(proto.frame_time()); + deadline = ProtoToTimeTicks(proto.deadline()); + interval = base::TimeDelta::FromInternalValue(proto.interval()); + BeginFrameArgsTypeFromProtobuf(proto); + on_critical_path = proto.on_critical_path(); +} + // This is a hard-coded deadline adjustment that assumes 60Hz, to be used in // cases where a good estimated draw time is not known. Using 1/3 of the vsync // as the default adjustment gives the Browser the last 1/3 of a frame to
diff --git a/cc/output/begin_frame_args.h b/cc/output/begin_frame_args.h index 1a7ae5f9..1f6bc36 100644 --- a/cc/output/begin_frame_args.h +++ b/cc/output/begin_frame_args.h
@@ -36,6 +36,10 @@ namespace cc { +namespace proto { +class BeginFrameArgs; +} + struct CC_EXPORT BeginFrameArgs { enum BeginFrameArgsType { INVALID, @@ -46,6 +50,8 @@ BEGIN_FRAME_ARGS_TYPE_MAX, }; static const char* TypeToString(BeginFrameArgsType type); + void BeginFrameArgsTypeToProtobuf(proto::BeginFrameArgs* proto) const; + void BeginFrameArgsTypeFromProtobuf(const proto::BeginFrameArgs& proto); // Creates an invalid set of values. BeginFrameArgs(); @@ -79,6 +85,9 @@ scoped_refptr<base::trace_event::ConvertableToTraceFormat> AsValue() const; void AsValueInto(base::trace_event::TracedValue* dict) const; + void ToProtobuf(proto::BeginFrameArgs* proto) const; + void FromProtobuf(const proto::BeginFrameArgs& proto); + base::TimeTicks frame_time; base::TimeTicks deadline; base::TimeDelta interval;
diff --git a/cc/output/begin_frame_args_unittest.cc b/cc/output/begin_frame_args_unittest.cc index eb63cc7..60972017 100644 --- a/cc/output/begin_frame_args_unittest.cc +++ b/cc/output/begin_frame_args_unittest.cc
@@ -5,6 +5,7 @@ #include <string> #include "cc/output/begin_frame_args.h" +#include "cc/proto/begin_main_frame_and_commit_state.pb.h" #include "cc/test/begin_frame_args_test.h" #include "testing/gtest/include/gtest/gtest-spi.h" #include "testing/gtest/include/gtest/gtest.h" @@ -84,6 +85,37 @@ EXPECT_EQ(BeginFrameArgs::NORMAL, args2.type) << args2; } +TEST(BeginFrameArgsSerializationTest, BeginFrameArgsType) { + for (size_t i = 0; + i < BeginFrameArgs::BeginFrameArgsType::BEGIN_FRAME_ARGS_TYPE_MAX; ++i) { + BeginFrameArgs::BeginFrameArgsType type = + static_cast<BeginFrameArgs::BeginFrameArgsType>(i); + BeginFrameArgs args; + args.type = type; + + proto::BeginFrameArgs proto; + args.BeginFrameArgsTypeToProtobuf(&proto); + + BeginFrameArgs new_args; + new_args.BeginFrameArgsTypeFromProtobuf(proto); + EXPECT_EQ(args.type, new_args.type); + } +} + +TEST(BeginFrameArgsSerializationTest, BeginFrameArgs) { + BeginFrameArgs args = BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, base::TimeTicks::FromInternalValue(1), + base::TimeTicks::FromInternalValue(2), + base::TimeDelta::FromInternalValue(3), BeginFrameArgs::NORMAL); + proto::BeginFrameArgs proto; + args.ToProtobuf(&proto); + + BeginFrameArgs new_args; + new_args.FromProtobuf(proto); + + EXPECT_EQ(args, new_args); +} + #ifndef NDEBUG TEST(BeginFrameArgsTest, Location) { tracked_objects::Location expected_location = BEGINFRAME_FROM_HERE;
diff --git a/cc/proto/BUILD.gn b/cc/proto/BUILD.gn index 60952ac..7a68e166 100644 --- a/cc/proto/BUILD.gn +++ b/cc/proto/BUILD.gn
@@ -29,6 +29,7 @@ sources = [ # TODO(dtrainor): Move protos to their correct packages once it's possible # to include protos from other directories/targets (crbug.com/542423). + "begin_main_frame_and_commit_state.proto", "commit_earlyout_reason.proto", "compositor_message.proto", "display_item.proto", @@ -56,6 +57,7 @@ "skrrect.proto", "skxfermode.proto", "transform.proto", + "vector2d.proto", "vector2df.proto", ]
diff --git a/cc/proto/base_conversions.cc b/cc/proto/base_conversions.cc new file mode 100644 index 0000000..119903b --- /dev/null +++ b/cc/proto/base_conversions.cc
@@ -0,0 +1,23 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/proto/base_conversions.h" + +namespace base { +class TimeDelta; +} + +namespace cc { + +int64_t TimeTicksToProto(base::TimeTicks ticks) { + base::TimeDelta diff = ticks - base::TimeTicks::UnixEpoch(); + return diff.InMicroseconds(); +} + +CC_EXPORT base::TimeTicks ProtoToTimeTicks(int64_t ticks) { + base::TimeDelta diff = base::TimeDelta::FromMicroseconds(ticks); + return base::TimeTicks::UnixEpoch() + diff; +} + +} // namespace cc
diff --git a/cc/proto/base_conversions.h b/cc/proto/base_conversions.h new file mode 100644 index 0000000..b862e3a --- /dev/null +++ b/cc/proto/base_conversions.h
@@ -0,0 +1,21 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CC_PROTO_BASE_CONVERSIONS_H_ +#define CC_PROTO_BASE_CONVERSIONS_H_ + +#include "base/time/time.h" +#include "cc/base/cc_export.h" + +namespace cc { + +// TODO(dtrainor): Move these to a class and make them static +// (crbug.com/548432). +// We should probably have a better way for sending these. +CC_EXPORT int64_t TimeTicksToProto(base::TimeTicks ticks); +CC_EXPORT base::TimeTicks ProtoToTimeTicks(int64_t ticks); + +} // namespace cc + +#endif // CC_PROTO_BASE_CONVERSIONS_H_
diff --git a/cc/proto/base_conversions_unittest.cc b/cc/proto/base_conversions_unittest.cc new file mode 100644 index 0000000..57dd807 --- /dev/null +++ b/cc/proto/base_conversions_unittest.cc
@@ -0,0 +1,30 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/proto/base_conversions.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +TEST(BaseProtoConversionsTest, SerializeTimeTicks) { + base::TimeTicks ticks; + base::TimeTicks new_ticks; + + ticks = base::TimeTicks::FromInternalValue(2); + new_ticks = ProtoToTimeTicks(TimeTicksToProto(ticks)); + EXPECT_EQ(ticks, new_ticks); + + ticks = base::TimeTicks::Now(); + new_ticks = ProtoToTimeTicks(TimeTicksToProto(ticks)); + EXPECT_EQ(ticks, new_ticks); + + ticks = base::TimeTicks::FromInternalValue(0); + new_ticks = ProtoToTimeTicks(TimeTicksToProto(ticks)); + EXPECT_EQ(ticks, new_ticks); +} + +} // namespace +} // namespace cc
diff --git a/cc/proto/begin_main_frame_and_commit_state.proto b/cc/proto/begin_main_frame_and_commit_state.proto new file mode 100644 index 0000000..9881131 --- /dev/null +++ b/cc/proto/begin_main_frame_and_commit_state.proto
@@ -0,0 +1,50 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +import "vector2d.proto"; +import "vector2df.proto"; + +option optimize_for = LITE_RUNTIME; + +package cc.proto; + +message ScrollUpdateInfo { + optional int64 layer_id = 1; + optional Vector2d scroll_delta = 2; +} + +message ScrollAndScaleSet { + repeated ScrollUpdateInfo scrolls = 1; + optional float page_scale_delta = 2; + optional Vector2dF elastic_overscroll_delta = 3; + optional float top_controls_delta = 4; + + // TODO(khushalsagar): Do we need to send swap promises? + // See crbug/576999. +} + +message BeginFrameArgs { + enum BeginFrameArgsType { + INVALID = 1; + NORMAL = 2; + MISSED = 3; + BEGIN_FRAME_ARGS_TYPE_MAX = 100; + } + + optional int64 frame_time = 1; + optional int64 deadline = 2; + optional int64 interval = 3; + optional BeginFrameArgsType type = 4; + optional bool on_critical_path = 5; +} + +message BeginMainFrameAndCommitState { + optional int64 begin_frame_id = 1; + optional BeginFrameArgs begin_frame_args = 2; + optional ScrollAndScaleSet scroll_info = 3; + optional int64 memory_allocation_limit_bytes = 4; + optional bool evicted_ui_resources = 5; +} \ No newline at end of file
diff --git a/cc/proto/gfx_conversions.cc b/cc/proto/gfx_conversions.cc index 8dac00c..3abc59f 100644 --- a/cc/proto/gfx_conversions.cc +++ b/cc/proto/gfx_conversions.cc
@@ -13,6 +13,7 @@ #include "cc/proto/size.pb.h" #include "cc/proto/sizef.pb.h" #include "cc/proto/transform.pb.h" +#include "cc/proto/vector2d.pb.h" #include "cc/proto/vector2df.pb.h" #include "ui/gfx/geometry/point.h" #include "ui/gfx/geometry/point3_f.h" @@ -22,6 +23,7 @@ #include "ui/gfx/geometry/scroll_offset.h" #include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size_f.h" +#include "ui/gfx/geometry/vector2d.h" #include "ui/gfx/transform.h" namespace cc { @@ -137,4 +139,13 @@ return gfx::ScrollOffset(proto.x(), proto.y()); } +void Vector2dToProto(const gfx::Vector2d& vector, proto::Vector2d* proto) { + proto->set_x(vector.x()); + proto->set_y(vector.y()); +} + +gfx::Vector2d ProtoToVector2d(const proto::Vector2d& proto) { + return gfx::Vector2d(proto.x(), proto.y()); +} + } // namespace cc
diff --git a/cc/proto/gfx_conversions.h b/cc/proto/gfx_conversions.h index b5caa3a3..52a2c118 100644 --- a/cc/proto/gfx_conversions.h +++ b/cc/proto/gfx_conversions.h
@@ -17,6 +17,7 @@ class Size; class SizeF; class Transform; +class Vector2d; class Vector2dF; } // namespace gfx @@ -32,6 +33,7 @@ class Size; class SizeF; class Transform; +class Vector2d; class Vector2dF; } // namespace proto @@ -71,6 +73,10 @@ CC_EXPORT gfx::ScrollOffset ProtoToScrollOffset( const proto::ScrollOffset& proto); +CC_EXPORT void Vector2dToProto(const gfx::Vector2d& vector, + proto::Vector2d* proto); +CC_EXPORT gfx::Vector2d ProtoToVector2d(const proto::Vector2d& proto); + } // namespace cc #endif // CC_PROTO_GFX_CONVERSIONS_H_
diff --git a/cc/proto/gfx_conversions_unittest.cc b/cc/proto/gfx_conversions_unittest.cc index cf46be8..1132304 100644 --- a/cc/proto/gfx_conversions_unittest.cc +++ b/cc/proto/gfx_conversions_unittest.cc
@@ -13,6 +13,7 @@ #include "cc/proto/size.pb.h" #include "cc/proto/sizef.pb.h" #include "cc/proto/transform.pb.h" +#include "cc/proto/vector2d.pb.h" #include "cc/proto/vector2df.pb.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/gfx/geometry/point.h" @@ -269,5 +270,18 @@ EXPECT_EQ(scroll_offset3, ProtoToScrollOffset(proto3)); } +TEST(GfxProtoConversionsTest, SerializeDeserializeVector2d) { + const gfx::Vector2d vector(5, 10); + + // Test Vector2dToProto + proto::Vector2d proto; + Vector2dToProto(vector, &proto); + EXPECT_EQ(vector.x(), proto.x()); + EXPECT_EQ(vector.y(), proto.y()); + + // Test ProtoToVector2d + EXPECT_EQ(vector, ProtoToVector2d(proto)); +} + } // namespace } // namespace cc
diff --git a/cc/proto/layer.proto b/cc/proto/layer.proto index 41b3f2d..bc1255d 100644 --- a/cc/proto/layer.proto +++ b/cc/proto/layer.proto
@@ -26,6 +26,7 @@ UNKNOWN = 0; LAYER = 1; PICTURE_LAYER = 2; + HEADS_UP_DISPLAY_LAYER = 3; // TODO(nyquist): Add the rest of the necessary LayerTypes. }; @@ -138,4 +139,4 @@ optional bool nearest_neighbor = 5; optional int64 update_source_frame_number = 6; -} \ No newline at end of file +}
diff --git a/cc/proto/vector2d.proto b/cc/proto/vector2d.proto new file mode 100644 index 0000000..15171844 --- /dev/null +++ b/cc/proto/vector2d.proto
@@ -0,0 +1,14 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +syntax = "proto2"; + +option optimize_for = LITE_RUNTIME; + +package cc.proto; + +message Vector2d { + optional int64 x = 1; + optional int64 y = 2; +}
diff --git a/cc/test/animation_timelines_test_common.h b/cc/test/animation_timelines_test_common.h index 518929d6..1733ca8 100644 --- a/cc/test/animation_timelines_test_common.h +++ b/cc/test/animation_timelines_test_common.h
@@ -151,6 +151,9 @@ void NotifyAnimationFinished(base::TimeTicks monotonic_time, Animation::TargetProperty target_property, int group) override; + void NotifyAnimationAborted(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) override {} bool started_; bool finished_; };
diff --git a/cc/test/test_hooks.h b/cc/test/test_hooks.h index fd45cbc..8caec7f 100644 --- a/cc/test/test_hooks.h +++ b/cc/test/test_hooks.h
@@ -130,6 +130,9 @@ void NotifyAnimationFinished(base::TimeTicks monotonic_time, Animation::TargetProperty target_property, int group) override {} + void NotifyAnimationAborted(base::TimeTicks monotonic_time, + Animation::TargetProperty target_property, + int group) override {} virtual void RequestNewOutputSurface() = 0; };
diff --git a/cc/trees/layer_tree_host.cc b/cc/trees/layer_tree_host.cc index 5489dd4..cb9619b1 100644 --- a/cc/trees/layer_tree_host.cc +++ b/cc/trees/layer_tree_host.cc
@@ -382,6 +382,7 @@ TreeSynchronizer::PushProperties(root_layer(), sync_tree->root_layer()); if (animation_host_) { + TRACE_EVENT0("cc", "LayerTreeHost::AnimationHost::PushProperties"); DCHECK(host_impl->animation_host()); animation_host_->PushPropertiesTo(host_impl->animation_host()); }
diff --git a/cc/trees/layer_tree_host_common.cc b/cc/trees/layer_tree_host_common.cc index 8f66145..d329041 100644 --- a/cc/trees/layer_tree_host_common.cc +++ b/cc/trees/layer_tree_host_common.cc
@@ -16,6 +16,8 @@ #include "cc/layers/layer_iterator.h" #include "cc/layers/render_surface_draw_properties.h" #include "cc/layers/render_surface_impl.h" +#include "cc/proto/begin_main_frame_and_commit_state.pb.h" +#include "cc/proto/gfx_conversions.h" #include "cc/trees/draw_property_utils.h" #include "cc/trees/layer_tree_host.h" #include "cc/trees/layer_tree_impl.h" @@ -149,12 +151,56 @@ render_surface_layer_list, current_render_surface_layer_list_id) {} +bool LayerTreeHostCommon::ScrollUpdateInfo::operator==( + const LayerTreeHostCommon::ScrollUpdateInfo& other) const { + return layer_id == other.layer_id && scroll_delta == other.scroll_delta; +} + +void LayerTreeHostCommon::ScrollUpdateInfo::ToProtobuf( + proto::ScrollUpdateInfo* proto) const { + proto->set_layer_id(layer_id); + Vector2dToProto(scroll_delta, proto->mutable_scroll_delta()); +} + +void LayerTreeHostCommon::ScrollUpdateInfo::FromProtobuf( + const proto::ScrollUpdateInfo& proto) { + layer_id = proto.layer_id(); + scroll_delta = ProtoToVector2d(proto.scroll_delta()); +} + ScrollAndScaleSet::ScrollAndScaleSet() : page_scale_delta(1.f), top_controls_delta(0.f) { } ScrollAndScaleSet::~ScrollAndScaleSet() {} +bool ScrollAndScaleSet::EqualsForTesting(const ScrollAndScaleSet& other) const { + return scrolls == other.scrolls && + page_scale_delta == other.page_scale_delta && + elastic_overscroll_delta == other.elastic_overscroll_delta && + top_controls_delta == other.top_controls_delta; +} + +void ScrollAndScaleSet::ToProtobuf(proto::ScrollAndScaleSet* proto) const { + for (const auto& scroll : scrolls) + scroll.ToProtobuf(proto->add_scrolls()); + proto->set_page_scale_delta(page_scale_delta); + Vector2dFToProto(elastic_overscroll_delta, + proto->mutable_elastic_overscroll_delta()); + proto->set_top_controls_delta(top_controls_delta); +} + +void ScrollAndScaleSet::FromProtobuf(const proto::ScrollAndScaleSet& proto) { + DCHECK_EQ(scrolls.size(), 0u); + for (int i = 0; i < proto.scrolls_size(); ++i) { + scrolls.push_back(LayerTreeHostCommon::ScrollUpdateInfo()); + scrolls[i].FromProtobuf(proto.scrolls(i)); + } + page_scale_delta = proto.page_scale_delta(); + elastic_overscroll_delta = ProtoToVector2dF(proto.elastic_overscroll_delta()); + top_controls_delta = proto.top_controls_delta(); +} + static gfx::Vector2dF GetEffectiveScrollDelta(LayerImpl* layer) { // Layer's scroll offset can have an integer part and fractional part. // Due to Blink's limitation, it only counter-scrolls the position-fixed
diff --git a/cc/trees/layer_tree_host_common.h b/cc/trees/layer_tree_host_common.h index df747215..4a09194 100644 --- a/cc/trees/layer_tree_host_common.h +++ b/cc/trees/layer_tree_host_common.h
@@ -22,6 +22,11 @@ namespace cc { +namespace proto { +class ScrollUpdateInfo; +class ScrollAndScaleSet; +} + class LayerImpl; class Layer; class SwapPromise; @@ -154,11 +159,16 @@ return layers[index]; } - struct ScrollUpdateInfo { + struct CC_EXPORT ScrollUpdateInfo { int layer_id; // TODO(miletus): Use ScrollOffset once LayerTreeHost/Blink fully supports // franctional scroll offset. gfx::Vector2d scroll_delta; + + bool operator==(const ScrollUpdateInfo& other) const; + + void ToProtobuf(proto::ScrollUpdateInfo* proto) const; + void FromProtobuf(const proto::ScrollUpdateInfo& proto); }; }; @@ -172,6 +182,10 @@ float top_controls_delta; std::vector<scoped_ptr<SwapPromise>> swap_promises; + bool EqualsForTesting(const ScrollAndScaleSet& other) const; + void ToProtobuf(proto::ScrollAndScaleSet* proto) const; + void FromProtobuf(const proto::ScrollAndScaleSet& proto); + private: DISALLOW_COPY_AND_ASSIGN(ScrollAndScaleSet); };
diff --git a/cc/trees/layer_tree_host_common_unittest.cc b/cc/trees/layer_tree_host_common_unittest.cc index a2c41fb7..c65a2cf5 100644 --- a/cc/trees/layer_tree_host_common_unittest.cc +++ b/cc/trees/layer_tree_host_common_unittest.cc
@@ -24,6 +24,8 @@ #include "cc/layers/render_surface_impl.h" #include "cc/output/copy_output_request.h" #include "cc/output/copy_output_result.h" +#include "cc/proto/begin_main_frame_and_commit_state.pb.h" +#include "cc/proto/gfx_conversions.h" #include "cc/test/animation_test_common.h" #include "cc/test/fake_content_layer_client.h" #include "cc/test/fake_impl_task_runner_provider.h" @@ -9638,5 +9640,42 @@ EXPECT_FALSE(render_surface2_in_rsll); } +TEST_F(LayerTreeHostCommonTest, SerializeScrollUpdateInfo) { + LayerTreeHostCommon::ScrollUpdateInfo scroll; + scroll.layer_id = 2; + scroll.scroll_delta = gfx::Vector2d(5, 10); + + proto::ScrollUpdateInfo proto; + scroll.ToProtobuf(&proto); + LayerTreeHostCommon::ScrollUpdateInfo new_scroll; + new_scroll.FromProtobuf(proto); + + EXPECT_EQ(scroll, new_scroll); +} + +TEST_F(LayerTreeHostCommonTest, SerializeScrollAndScale) { + ScrollAndScaleSet scroll_and_scale_set; + + LayerTreeHostCommon::ScrollUpdateInfo scroll1; + scroll1.layer_id = 1; + scroll1.scroll_delta = gfx::Vector2d(5, 10); + LayerTreeHostCommon::ScrollUpdateInfo scroll2; + scroll2.layer_id = 2; + scroll2.scroll_delta = gfx::Vector2d(1, 5); + scroll_and_scale_set.scrolls.push_back(scroll1); + scroll_and_scale_set.scrolls.push_back(scroll2); + + scroll_and_scale_set.page_scale_delta = 0.3f; + scroll_and_scale_set.elastic_overscroll_delta = gfx::Vector2dF(0.5f, 0.6f); + scroll_and_scale_set.top_controls_delta = 0.9f; + + proto::ScrollAndScaleSet proto; + scroll_and_scale_set.ToProtobuf(&proto); + ScrollAndScaleSet new_scroll_and_scale_set; + new_scroll_and_scale_set.FromProtobuf(proto); + + EXPECT_TRUE(scroll_and_scale_set.EqualsForTesting(new_scroll_and_scale_set)); +} + } // namespace } // namespace cc
diff --git a/cc/trees/layer_tree_host_unittest_serialization.cc b/cc/trees/layer_tree_host_unittest_serialization.cc index 2f662b6e..085b84c 100644 --- a/cc/trees/layer_tree_host_unittest_serialization.cc +++ b/cc/trees/layer_tree_host_unittest_serialization.cc
@@ -107,6 +107,19 @@ if (layer_tree_host_src_->hud_layer_) { EXPECT_EQ(layer_tree_host_src_->hud_layer_->id(), layer_tree_host_dst_->hud_layer_->id()); + // The HUD layer member is a HeadsUpDisplayLayer instead of Layer, so + // inspect the proto to see if it contains the the right layer type. + bool found_hud_layer_type = false; + for (int i = 0; i < proto.root_layer().children_size(); ++i) { + if (proto.root_layer().children(i).id() == + layer_tree_host_src_->hud_layer_->id()) { + EXPECT_EQ(proto::HEADS_UP_DISPLAY_LAYER, + proto.root_layer().children(i).type()); + found_hud_layer_type = true; + break; + } + } + EXPECT_TRUE(found_hud_layer_type); } else { EXPECT_EQ(nullptr, layer_tree_host_dst_->hud_layer_); }
diff --git a/cc/trees/proxy_common.cc b/cc/trees/proxy_common.cc index f047e8e..c96af7b 100644 --- a/cc/trees/proxy_common.cc +++ b/cc/trees/proxy_common.cc
@@ -3,6 +3,8 @@ // found in the LICENSE file. #include "cc/trees/proxy_common.h" + +#include "cc/proto/begin_main_frame_and_commit_state.pb.h" #include "cc/trees/layer_tree_host.h" namespace cc { @@ -12,4 +14,23 @@ BeginMainFrameAndCommitState::~BeginMainFrameAndCommitState() {} +void BeginMainFrameAndCommitState::ToProtobuf( + proto::BeginMainFrameAndCommitState* proto) const { + proto->set_begin_frame_id(begin_frame_id); + begin_frame_args.ToProtobuf(proto->mutable_begin_frame_args()); + scroll_info->ToProtobuf(proto->mutable_scroll_info()); + proto->set_memory_allocation_limit_bytes(memory_allocation_limit_bytes); + proto->set_evicted_ui_resources(evicted_ui_resources); +} + +void BeginMainFrameAndCommitState::FromProtobuf( + const proto::BeginMainFrameAndCommitState& proto) { + begin_frame_id = proto.begin_frame_id(); + begin_frame_args.FromProtobuf(proto.begin_frame_args()); + scroll_info.reset(new ScrollAndScaleSet()); + scroll_info->FromProtobuf(proto.scroll_info()); + memory_allocation_limit_bytes = proto.memory_allocation_limit_bytes(); + evicted_ui_resources = proto.evicted_ui_resources(); +} + } // namespace cc
diff --git a/cc/trees/proxy_common.h b/cc/trees/proxy_common.h index a9e991c..046f105 100644 --- a/cc/trees/proxy_common.h +++ b/cc/trees/proxy_common.h
@@ -12,6 +12,11 @@ #include "cc/trees/layer_tree_host_common.h" namespace cc { + +namespace proto { +class BeginMainFrameAndCommitState; +} + class LayerTreeHost; struct CC_EXPORT BeginMainFrameAndCommitState { @@ -23,6 +28,9 @@ scoped_ptr<ScrollAndScaleSet> scroll_info; size_t memory_allocation_limit_bytes; bool evicted_ui_resources; + + void ToProtobuf(proto::BeginMainFrameAndCommitState* proto) const; + void FromProtobuf(const proto::BeginMainFrameAndCommitState& proto); }; } // namespace cc
diff --git a/cc/trees/proxy_common_unittest.cc b/cc/trees/proxy_common_unittest.cc new file mode 100644 index 0000000..c0caf1d --- /dev/null +++ b/cc/trees/proxy_common_unittest.cc
@@ -0,0 +1,61 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/trees/proxy_common.h" + +#include "cc/proto/begin_main_frame_and_commit_state.pb.h" +#include "cc/test/begin_frame_args_test.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace cc { +namespace { + +TEST(ProxyCommonUnittest, SerializeBeginMainFrameAndCommitState) { + BeginMainFrameAndCommitState begin_main_frame_state; + begin_main_frame_state.begin_frame_id = 5; + + begin_main_frame_state.begin_frame_args = BeginFrameArgs::Create( + BEGINFRAME_FROM_HERE, base::TimeTicks::FromInternalValue(4), + base::TimeTicks::FromInternalValue(7), + base::TimeDelta::FromInternalValue(9), BeginFrameArgs::NORMAL); + begin_main_frame_state.begin_frame_args.on_critical_path = false; + + LayerTreeHostCommon::ScrollUpdateInfo scroll1; + scroll1.layer_id = 1; + scroll1.scroll_delta = gfx::Vector2d(5, 10); + LayerTreeHostCommon::ScrollUpdateInfo scroll2; + scroll2.layer_id = 2; + scroll2.scroll_delta = gfx::Vector2d(1, 5); + begin_main_frame_state.scroll_info.reset(new ScrollAndScaleSet()); + begin_main_frame_state.scroll_info->scrolls.push_back(scroll1); + begin_main_frame_state.scroll_info->scrolls.push_back(scroll2); + + begin_main_frame_state.scroll_info->page_scale_delta = 0.3f; + begin_main_frame_state.scroll_info->elastic_overscroll_delta = + gfx::Vector2dF(0.5f, 0.6f); + begin_main_frame_state.scroll_info->top_controls_delta = 0.9f; + + begin_main_frame_state.memory_allocation_limit_bytes = 16; + begin_main_frame_state.evicted_ui_resources = false; + + proto::BeginMainFrameAndCommitState proto; + begin_main_frame_state.ToProtobuf(&proto); + + BeginMainFrameAndCommitState new_begin_main_frame_state; + new_begin_main_frame_state.FromProtobuf(proto); + + EXPECT_EQ(new_begin_main_frame_state.begin_frame_id, + begin_main_frame_state.begin_frame_id); + EXPECT_EQ(new_begin_main_frame_state.begin_frame_args, + begin_main_frame_state.begin_frame_args); + EXPECT_TRUE(begin_main_frame_state.scroll_info->EqualsForTesting( + *new_begin_main_frame_state.scroll_info.get())); + EXPECT_EQ(new_begin_main_frame_state.memory_allocation_limit_bytes, + begin_main_frame_state.memory_allocation_limit_bytes); + EXPECT_EQ(new_begin_main_frame_state.evicted_ui_resources, + begin_main_frame_state.evicted_ui_resources); +} + +} // namespace +} // namespace cc
diff --git a/chrome/android/java/res/drawable-v21/icon_most_visited_item_highlight.xml b/chrome/android/java/res/drawable-v21/most_visited_item_highlight.xml similarity index 83% rename from chrome/android/java/res/drawable-v21/icon_most_visited_item_highlight.xml rename to chrome/android/java/res/drawable-v21/most_visited_item_highlight.xml index 871e449..c8c76cf 100644 --- a/chrome/android/java/res/drawable-v21/icon_most_visited_item_highlight.xml +++ b/chrome/android/java/res/drawable-v21/most_visited_item_highlight.xml
@@ -9,6 +9,6 @@ <item android:id="@android:id/mask" - android:drawable="@drawable/icon_most_visited_item_highlight_mask"/> + android:drawable="@drawable/most_visited_item_highlight_mask"/> </ripple> \ No newline at end of file
diff --git a/chrome/android/java/res/drawable/icon_most_visited_item_highlight.xml b/chrome/android/java/res/drawable/most_visited_item_highlight.xml similarity index 88% rename from chrome/android/java/res/drawable/icon_most_visited_item_highlight.xml rename to chrome/android/java/res/drawable/most_visited_item_highlight.xml index 5a41a41..a3f673f 100644 --- a/chrome/android/java/res/drawable/icon_most_visited_item_highlight.xml +++ b/chrome/android/java/res/drawable/most_visited_item_highlight.xml
@@ -5,5 +5,5 @@ found in the LICENSE file. --> <selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_pressed="true" android:drawable="@drawable/icon_most_visited_item_highlight_plain" /> + <item android:state_pressed="true" android:drawable="@drawable/most_visited_item_highlight_plain" /> </selector>
diff --git a/chrome/android/java/res/drawable/icon_most_visited_item_highlight_mask.xml b/chrome/android/java/res/drawable/most_visited_item_highlight_mask.xml similarity index 100% rename from chrome/android/java/res/drawable/icon_most_visited_item_highlight_mask.xml rename to chrome/android/java/res/drawable/most_visited_item_highlight_mask.xml
diff --git a/chrome/android/java/res/drawable/icon_most_visited_item_highlight_plain.xml b/chrome/android/java/res/drawable/most_visited_item_highlight_plain.xml similarity index 100% rename from chrome/android/java/res/drawable/icon_most_visited_item_highlight_plain.xml rename to chrome/android/java/res/drawable/most_visited_item_highlight_plain.xml
diff --git a/chrome/android/java/res/layout/icon_most_visited_layout.xml b/chrome/android/java/res/layout/icon_most_visited_layout.xml deleted file mode 100644 index 6edb416..0000000 --- a/chrome/android/java/res/layout/icon_most_visited_layout.xml +++ /dev/null
@@ -1,11 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- Copyright 2015 The Chromium Authors. All rights reserved. - Use of this source code is governed by a BSD-style license that can be - found in the LICENSE file. --> - -<org.chromium.chrome.browser.ntp.IconMostVisitedLayout - xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="0dp" - android:layout_height="0dp" - android:paddingTop="@dimen/icon_most_visited_layout_padding_top" - android:paddingBottom="@dimen/icon_most_visited_layout_padding_bottom" /> \ No newline at end of file
diff --git a/chrome/android/java/res/layout/icon_most_visited_item.xml b/chrome/android/java/res/layout/most_visited_item.xml similarity index 69% rename from chrome/android/java/res/layout/icon_most_visited_item.xml rename to chrome/android/java/res/layout/most_visited_item.xml index 3e942f03..8fefe88 100644 --- a/chrome/android/java/res/layout/icon_most_visited_item.xml +++ b/chrome/android/java/res/layout/most_visited_item.xml
@@ -4,17 +4,17 @@ found in the LICENSE file. --> <!-- A most visited item, for display on the new tab page. --> -<org.chromium.chrome.browser.ntp.IconMostVisitedItemView +<org.chromium.chrome.browser.ntp.MostVisitedItemView xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="@dimen/icon_most_visited_tile_width" + android:layout_width="@dimen/most_visited_tile_width" android:layout_height="wrap_content" android:paddingStart="4dp" android:paddingEnd="4dp" > <ImageView android:id="@+id/most_visited_icon" - android:layout_width="@dimen/icon_most_visited_icon_size" - android:layout_height="@dimen/icon_most_visited_icon_size" + android:layout_width="@dimen/most_visited_icon_size" + android:layout_height="@dimen/most_visited_icon_size" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" android:layout_marginTop="12dp" @@ -22,8 +22,8 @@ <ImageView android:id="@+id/offline_badge" - android:layout_width="@dimen/icon_most_visited_offline_badge_size" - android:layout_height="@dimen/icon_most_visited_offline_badge_size" + android:layout_width="@dimen/most_visited_offline_badge_size" + android:layout_height="@dimen/most_visited_offline_badge_size" android:layout_marginStart="48dp" android:visibility="gone" android:background="@drawable/offline_badge_background" @@ -31,12 +31,12 @@ android:src="@drawable/eb_filter_offline_pages" /> <View - android:layout_width="@dimen/icon_most_visited_icon_size" - android:layout_height="@dimen/icon_most_visited_icon_size" + android:layout_width="@dimen/most_visited_icon_size" + android:layout_height="@dimen/most_visited_icon_size" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" android:layout_marginTop="12dp" - android:background="@drawable/icon_most_visited_item_highlight" /> + android:background="@drawable/most_visited_item_highlight" /> <TextView android:id="@+id/most_visited_title" @@ -50,4 +50,4 @@ android:textColor="#787878" android:textSize="12sp" /> -</org.chromium.chrome.browser.ntp.IconMostVisitedItemView> +</org.chromium.chrome.browser.ntp.MostVisitedItemView>
diff --git a/chrome/android/java/res/layout/new_tab_page.xml b/chrome/android/java/res/layout/new_tab_page.xml index 6de4dc17..8af21286 100644 --- a/chrome/android/java/res/layout/new_tab_page.xml +++ b/chrome/android/java/res/layout/new_tab_page.xml
@@ -103,19 +103,17 @@ android:inflatedId="@+id/opt_out_promo" android:layout="@layout/opt_out_promo" /> - <!-- Most visited items. - TODO(newt): inline the most visited items layout, instead of using a ViewStub, - once the layout is no longer controlled by a finch experiment. --> - <ViewStub - android:id="@+id/most_visited_layout_stub" - android:inflatedId="@+id/most_visited_layout" + <!-- Most visited items --> + <org.chromium.chrome.browser.ntp.MostVisitedLayout + android:id="@+id/most_visited_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:layout_marginStart="12dp" android:layout_marginEnd="12dp" android:layout_gravity="center_horizontal" - android:paddingTop="16dp" /> + android:paddingTop="@dimen/most_visited_layout_padding_top" + android:paddingBottom="4dp" /> <!-- Most visited items placeholder --> <ViewStub
diff --git a/chrome/android/java/res/values/dimens.xml b/chrome/android/java/res/values/dimens.xml index 4a6421d..3788660e 100644 --- a/chrome/android/java/res/values/dimens.xml +++ b/chrome/android/java/res/values/dimens.xml
@@ -250,17 +250,16 @@ <!-- NTP dimensions --> <dimen name="most_visited_bg_corner_radius">2dp</dimen> - <dimen name="icon_most_visited_layout_max_width">504dp</dimen> - <dimen name="icon_most_visited_layout_padding_top">8dp</dimen> - <dimen name="icon_most_visited_layout_padding_bottom">4dp</dimen> - <dimen name="icon_most_visited_layout_no_logo_padding_top">20dp</dimen> - <dimen name="icon_most_visited_layout_bleed">8dp</dimen> - <dimen name="icon_most_visited_vertical_spacing">3dp</dimen> - <dimen name="icon_most_visited_min_horizontal_spacing">4dp</dimen> - <dimen name="icon_most_visited_max_horizontal_spacing">16dp</dimen> - <dimen name="icon_most_visited_tile_width">80dp</dimen> - <dimen name="icon_most_visited_icon_size">48dp</dimen> - <dimen name="icon_most_visited_offline_badge_size">24dp</dimen> + <dimen name="most_visited_layout_max_width">504dp</dimen> + <dimen name="most_visited_layout_padding_top">8dp</dimen> + <dimen name="most_visited_layout_no_logo_padding_top">20dp</dimen> + <dimen name="most_visited_layout_bleed">8dp</dimen> + <dimen name="most_visited_vertical_spacing">3dp</dimen> + <dimen name="most_visited_min_horizontal_spacing">4dp</dimen> + <dimen name="most_visited_max_horizontal_spacing">16dp</dimen> + <dimen name="most_visited_tile_width">80dp</dimen> + <dimen name="most_visited_icon_size">48dp</dimen> + <dimen name="most_visited_offline_badge_size">24dp</dimen> <dimen name="ntp_logo_height">116dp</dimen> <dimen name="ntp_list_item_padding">16dp</dimen> <dimen name="ntp_list_item_min_height">48dp</dimen>
diff --git a/chrome/android/java/src/android/support/customtabs/CustomTabsIntent.java b/chrome/android/java/src/android/support/customtabs/CustomTabsIntent.java index e8ad81d7..952be0d 100644 --- a/chrome/android/java/src/android/support/customtabs/CustomTabsIntent.java +++ b/chrome/android/java/src/android/support/customtabs/CustomTabsIntent.java
@@ -58,6 +58,14 @@ "android.support.customtabs.extra.ACTION_BUTTON_BUNDLE"; /** + * List<Bundle> used for adding items to the top and bottom action bars. The client should + * provide an ID, a description, an icon {@link Bitmap} for each item. They may also provide a + * {@link PendingIntent} if the item is a button. + */ + public static final String EXTRA_ACTION_BAR_ITEMS = + "android.support.customtabs.extra.ACTION_BAR_ITEMS"; + + /** * Key that specifies the {@link Bitmap} to be used as the image source for the action button. */ public static final String KEY_ICON = "android.support.customtabs.customaction.ICON";
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java index 83ac1ceb..b4426f9 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFieldTrial.java
@@ -21,28 +21,41 @@ private static final String DISABLED_PARAM = "disabled"; private static final String ENABLED_VALUE = "true"; - static final String PEEK_PROMO_FORCED = "peek_promo_forced"; - static final String PEEK_PROMO_ENABLED = "peek_promo_enabled"; - static final String PEEK_PROMO_MAX_SHOW_COUNT = "peek_promo_max_show_count"; - static final int PEEK_PROMO_DEFAULT_MAX_SHOW_COUNT = 10; - - static final String DISABLE_SEARCH_TERM_RESOLUTION = "disable_search_term_resolution"; - static final String DISABLE_EXTRA_SEARCH_BAR_ANIMATIONS = "disable_extra_search_bar_animations"; - static final String ENABLE_DIGIT_BLACKLIST = "enable_digit_blacklist"; - - // Translation. + private static final String PEEK_PROMO_FORCED = "peek_promo_forced"; @VisibleForTesting - static final String ENABLE_TRANSLATION_FOR_TESTING = "enable_translation_for_testing"; + static final String PEEK_PROMO_ENABLED = "peek_promo_enabled"; + private static final String PEEK_PROMO_MAX_SHOW_COUNT = "peek_promo_max_show_count"; + private static final int PEEK_PROMO_DEFAULT_MAX_SHOW_COUNT = 10; + + private static final String DISABLE_SEARCH_TERM_RESOLUTION = "disable_search_term_resolution"; + private static final String DISABLE_EXTRA_SEARCH_BAR_ANIMATIONS = + "disable_extra_search_bar_animations"; + private static final String ENABLE_DIGIT_BLACKLIST = "enable_digit_blacklist"; + + // Translation. All these members are private, except for usage by testing. + // Master switch, needed to enable any translate code for Contextual Search. + @VisibleForTesting + static final String ENABLE_TRANSLATION = "enable_translation"; + // Switch to disable translation, but not logging, used for experiment comparison. @VisibleForTesting static final String DISABLE_FORCE_TRANSLATION_ONEBOX = "disable_force_translation_onebox"; + // Disables translation when we need to auto-detect the source language (when we don't resolve). @VisibleForTesting static final String DISABLE_AUTO_DETECT_TRANSLATION_ONEBOX = "disable_auto_detect_translation_onebox"; - static final String DISABLE_KEYBOARD_LANGUAGES_FOR_TRANSLATION = + // Disables using the keyboard languages to determine the target language. + private static final String DISABLE_KEYBOARD_LANGUAGES_FOR_TRANSLATION = "disable_keyboard_languages_for_translation"; - static final String DISABLE_ACCEPT_LANGUAGES_FOR_TRANSLATION = + // Disables using the accept-languages list to determine the target language. + private static final String DISABLE_ACCEPT_LANGUAGES_FOR_TRANSLATION = "disable_accept_languages_for_translation"; - static final String ENABLE_ENGLISH_TARGET_TRANSLATION = "enable_english_target_translation"; + // Enables usage of English as the target language even when it's the primary UI language. + private static final String ENABLE_ENGLISH_TARGET_TRANSLATION = + "enable_english_target_translation"; + // Enables relying on the server to control whether the onebox is actually shown, rather + // than checking if translation is needed client-side based on source/target languages. + @VisibleForTesting + static final String ENABLE_SERVER_CONTROLLED_ONEBOX = "enable_server_controlled_onebox"; // Quick Answers. private static final String ENABLE_QUICK_ANSWERS = "enable_quick_answers"; @@ -52,12 +65,13 @@ private static Boolean sDisableSearchTermResolution; private static Boolean sIsPeekPromoEnabled; private static Integer sPeekPromoMaxCount; - private static Boolean sIsTranslationForTestingEnabled; + private static Boolean sIsTranslationEnabled; private static Boolean sIsForceTranslationOneboxDisabled; private static Boolean sIsAutoDetectTranslationOneboxDisabled; private static Boolean sIsAcceptLanguagesForTranslationDisabled; private static Boolean sIsKeyboardLanguagesForTranslationDisabled; private static Boolean sIsEnglishTargetTranslationEnabled; + private static Boolean sIsServerControlledOneboxEnabled; private static Boolean sIsQuickAnswersEnabled; /** @@ -169,13 +183,13 @@ } /** - * @return Whether any translate is enabled, used for testing only. + * @return Whether any translate code is enabled. */ - static boolean isTranslationForTestingEnabled() { - if (sIsTranslationForTestingEnabled == null) { - sIsTranslationForTestingEnabled = getBooleanParam(ENABLE_TRANSLATION_FOR_TESTING); + static boolean isTranslationEnabled() { + if (sIsTranslationEnabled == null) { + sIsTranslationEnabled = getBooleanParam(ENABLE_TRANSLATION); } - return sIsTranslationForTestingEnabled.booleanValue(); + return sIsTranslationEnabled.booleanValue(); } /** @@ -233,6 +247,16 @@ } /** + * @return Whether relying on server-control of showing the translation one-box is enabled. + */ + static boolean isServerControlledOneboxEnabled() { + if (sIsServerControlledOneboxEnabled == null) { + sIsServerControlledOneboxEnabled = getBooleanParam(ENABLE_SERVER_CONTROLLED_ONEBOX); + } + return sIsServerControlledOneboxEnabled.booleanValue(); + } + + /** * @return Whether showing "quick answers" in the Bar is enabled. */ static boolean isQuickAnswersEnabled() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java index 63c0759..23af4b76a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchPolicy.java
@@ -484,9 +484,7 @@ * @return Whether any translation feature for Contextual Search is enabled. */ boolean isTranslationEnabled() { - // For M-48 CS translation features are completely disabled except for testing. - // TODO(donnd): fallback onto non-testing flags when ready. - return ContextualSearchFieldTrial.isTranslationForTestingEnabled(); + return ContextualSearchFieldTrial.isTranslationEnabled(); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java index 277d1219..90d7aec8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchRequest.java
@@ -207,25 +207,22 @@ /** * Makes the given {@code Uri} into a similar Uri that triggers a Translate one-box. * @param baseUri The base Uri to build off of. - * @param sourceLanguage The language of the original search term. - * @param targetLanguage The language the that the user prefers. + * @param sourceLanguage The language of the original search term, or an empty string to + * auto-detect the source language. + * @param targetLanguage The language that the user prefers, or an empty string to + * use server-side heuristics for the target language. * @return A {@link Uri} that has additional parameters for Translate appropriately set. */ private Uri makeTranslateUri(Uri baseUri, String sourceLanguage, String targetLanguage) { - Uri resultUri = baseUri; - if (!sourceLanguage.isEmpty() || !targetLanguage.isEmpty()) { - Uri.Builder builder = baseUri.buildUpon(); - if (!sourceLanguage.isEmpty()) { - builder.appendQueryParameter(TLITE_SOURCE_LANGUAGE_PARAM, sourceLanguage); - } - if (!targetLanguage.isEmpty()) { - builder.appendQueryParameter(TLITE_TARGET_LANGUAGE_PARAM, targetLanguage); - } - builder.appendQueryParameter( - TLITE_QUERY_PARAM, baseUri.getQueryParameter(GWS_QUERY_PARAM)); - builder.appendQueryParameter(CTXSL_TRANS_PARAM, CTXSL_TRANS_PARAM_VALUE); - resultUri = builder.build(); + Uri.Builder builder = baseUri.buildUpon(); + builder.appendQueryParameter(CTXSL_TRANS_PARAM, CTXSL_TRANS_PARAM_VALUE); + if (!sourceLanguage.isEmpty()) { + builder.appendQueryParameter(TLITE_SOURCE_LANGUAGE_PARAM, sourceLanguage); } - return resultUri; + if (!targetLanguage.isEmpty()) { + builder.appendQueryParameter(TLITE_TARGET_LANGUAGE_PARAM, targetLanguage); + } + builder.appendQueryParameter(TLITE_QUERY_PARAM, baseUri.getQueryParameter(GWS_QUERY_PARAM)); + return builder.build(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTranslateController.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTranslateController.java index 9eb040a..df0f0f75 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTranslateController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTranslateController.java
@@ -46,18 +46,19 @@ String sourceLanguage) { if (!mPolicy.isTranslationEnabled()) return; - if (!TextUtils.isEmpty(sourceLanguage)) { - if (mPolicy.needsTranslation(sourceLanguage, getReadableLanguages())) { - boolean doForceTranslate = !mPolicy.isForceTranslationOneboxDisabled(); - if (doForceTranslate && searchRequest != null) { - searchRequest.forceTranslation(sourceLanguage, - mPolicy.bestTargetLanguage(getProficientLanguageList())); - } - // Log that conditions were right for translation, even though it may be disabled - // for an experiment so we can compare with the counter factual data. - ContextualSearchUma.logTranslateOnebox(doForceTranslate); - } + // Force translation if not disabled and server controlled or client logic says required. + boolean doForceTranslate = !mPolicy.isForceTranslationOneboxDisabled() + && (ContextualSearchFieldTrial.isServerControlledOneboxEnabled() + || !TextUtils.isEmpty(sourceLanguage) + && mPolicy.needsTranslation( + sourceLanguage, getReadableLanguages())); + if (doForceTranslate && searchRequest != null) { + searchRequest.forceTranslation( + sourceLanguage, mPolicy.bestTargetLanguage(getProficientLanguageList())); } + // Log that conditions were right for translation, even though it may be disabled + // for an experiment so we can compare with the counter factual data. + ContextualSearchUma.logTranslateOnebox(doForceTranslate); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomButtonParams.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomButtonParams.java index aa28292..c842698 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomButtonParams.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomButtonParams.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.customtabs; import android.app.PendingIntent; -import android.app.PendingIntent.CanceledException; import android.content.Context; import android.content.Intent; import android.content.res.Resources; @@ -16,8 +15,11 @@ import android.support.annotation.NonNull; import android.support.customtabs.CustomTabsIntent; import android.text.TextUtils; +import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.widget.ImageButton; @@ -25,6 +27,7 @@ import org.chromium.chrome.R; import org.chromium.chrome.browser.util.IntentUtils; import org.chromium.chrome.browser.widget.TintedDrawable; +import org.chromium.ui.widget.Toast; import java.util.ArrayList; import java.util.HashSet; @@ -108,9 +111,10 @@ * Builds an {@link ImageButton} from the data in this params. Generated buttons should be * placed on the bottom bar. The button's tag will be its id. * @param parent The parent that the inflated {@link ImageButton}. + * @param listener {@link OnClickListener} that should be used with the button. * @return Parsed list of {@link CustomButtonParams}, which is empty if the input is invalid. */ - ImageButton buildBottomBarButton(Context context, ViewGroup parent) { + ImageButton buildBottomBarButton(Context context, ViewGroup parent, OnClickListener listener) { if (mIsOnToolbar) return null; ImageButton button = (ImageButton) LayoutInflater.from(context) @@ -121,18 +125,26 @@ if (mPendingIntent == null) { button.setEnabled(false); } else { - // TODO(ianwen): add UMA for button clicking. - button.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - try { - mPendingIntent.send(); - } catch (CanceledException e) { - Log.e(TAG, "CanceledException while sending pending intent in custom tab"); - } - } - }); + button.setOnClickListener(listener); } + button.setOnLongClickListener(new OnLongClickListener() { + @Override + public boolean onLongClick(View view) { + final int screenWidth = view.getResources().getDisplayMetrics().widthPixels; + final int[] screenPos = new int[2]; + view.getLocationOnScreen(screenPos); + final int width = view.getWidth(); + + Toast toast = Toast.makeText( + view.getContext(), view.getContentDescription(), Toast.LENGTH_SHORT); + toast.setGravity(Gravity.BOTTOM | Gravity.END, + screenWidth - screenPos[0] - width / 2, + view.getResources().getDimensionPixelSize( + R.dimen.toolbar_height_no_shadow)); + toast.show(); + return true; + } + }); return button; } @@ -148,13 +160,11 @@ Bundle singleBundle = IntentUtils.safeGetBundleExtra(intent, CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE); ArrayList<Bundle> bundleList = IntentUtils.getParcelableArrayListExtra(intent, - CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE); + CustomTabsIntent.EXTRA_ACTION_BAR_ITEMS); boolean tinted = IntentUtils.safeGetBooleanExtra(intent, CustomTabsIntent.EXTRA_TINT_ACTION_BUTTON, false); - if (singleBundle != null) { - CustomButtonParams params = fromBundle(context, singleBundle, tinted, false); - paramsList.add(params); - } else if (bundleList != null) { + if (singleBundle != null) paramsList.add(fromBundle(context, singleBundle, tinted, false)); + if (bundleList != null) { Set<Integer> ids = new HashSet<>(); for (Bundle bundle : bundleList) { CustomButtonParams params = fromBundle(context, bundle, tinted, true);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java index 162e346..e3a49c7d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/customtabs/CustomTabActivity.java
@@ -4,6 +4,8 @@ package org.chromium.chrome.browser.customtabs; +import android.app.PendingIntent; +import android.app.PendingIntent.CanceledException; import android.content.Intent; import android.graphics.Bitmap; import android.net.Uri; @@ -482,6 +484,7 @@ * Inflates the bottom bar {@link ViewStub} and its shadow, and populates it with items. */ private void showBottomBarIfNecessary() { + // TODO (yusufo): Find a better place for the layout code here and in CustomButtonParams. // TODO (ianwen): if button icon is too wide, show them in overflow menu instead. If button // id is not specified, the overflow sequence should be toolbar -> bottom bar -> menu. if (!mIntentDataProvider.shouldShowBottomBar()) return; @@ -501,7 +504,24 @@ List<CustomButtonParams> items = mIntentDataProvider.getCustomButtonsOnBottombar(); for (CustomButtonParams params : items) { if (params.showOnToolbar()) continue; - ImageButton button = params.buildBottomBarButton(this, bottomBar); + final PendingIntent pendingIntent = params.getPendingIntent(); + OnClickListener clickListener = null; + if (pendingIntent != null) { + clickListener = new OnClickListener() { + @Override + public void onClick(View v) { + Intent addedIntent = new Intent(); + addedIntent.setData(Uri.parse(getActivityTab().getUrl())); + try { + pendingIntent.send(CustomTabActivity.this, 0, addedIntent, null, null); + } catch (CanceledException e) { + Log.e(TAG, + "CanceledException while sending pending intent in custom tab"); + } + } + }; + } + ImageButton button = params.buildBottomBarButton(this, bottomBar, clickListener); bottomBar.addView(button); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java index ccd29eeb..660f96e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/fullscreen/ChromeFullscreenManager.java
@@ -26,6 +26,7 @@ import org.chromium.base.ApplicationStatus.ActivityStateListener; import org.chromium.base.BaseChromiumApplication; import org.chromium.base.BaseChromiumApplication.WindowFocusChangedListener; +import org.chromium.base.ThreadUtils; import org.chromium.base.TraceEvent; import org.chromium.base.VisibleForTesting; import org.chromium.chrome.browser.fullscreen.FullscreenHtmlApiHandler.FullscreenHtmlApiDelegate; @@ -275,6 +276,8 @@ */ @VisibleForTesting public void disableBrowserOverrideForTest() { + ThreadUtils.assertOnUiThread(); + mDisableBrowserOverride = true; mPersistentControlTokens.clear(); mHandler.removeMessages(MSG_ID_HIDE_CONTROLS);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IconMostVisitedItemView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java similarity index 84% rename from chrome/android/java/src/org/chromium/chrome/browser/ntp/IconMostVisitedItemView.java rename to chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java index 21703a4..e7ce17d 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IconMostVisitedItemView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedItemView.java
@@ -15,15 +15,15 @@ import org.chromium.chrome.R; /** - * A new-fangled most visited item. Displays the title of the page beneath a large icon. If a large + * The view for a most visited item. Displays the title of the page beneath a large icon. If a large * icon isn't available, displays a rounded rectangle with a single letter in its place. */ -public class IconMostVisitedItemView extends FrameLayout { +public class MostVisitedItemView extends FrameLayout { /** * Constructor for inflating from XML. */ - public IconMostVisitedItemView(Context context, AttributeSet attrs) { + public MostVisitedItemView(Context context, AttributeSet attrs) { super(context, attrs); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IconMostVisitedLayout.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java similarity index 89% rename from chrome/android/java/src/org/chromium/chrome/browser/ntp/IconMostVisitedLayout.java rename to chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java index 02854ce..2f570b7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/IconMostVisitedLayout.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/MostVisitedLayout.java
@@ -16,10 +16,8 @@ /** * A layout that arranges most visited items in a grid. - * - * Intended for use with the new icon-based most visited items. */ -public class IconMostVisitedLayout extends FrameLayout { +public class MostVisitedLayout extends FrameLayout { private static final int MAX_COLUMNS = 4; @@ -33,16 +31,16 @@ * @param context The view context in which this item will be shown. * @param attrs The attributes of the XML tag that is inflating the view. */ - public IconMostVisitedLayout(Context context, AttributeSet attrs) { + public MostVisitedLayout(Context context, AttributeSet attrs) { super(context, attrs); Resources res = getResources(); - mVerticalSpacing = res.getDimensionPixelOffset(R.dimen.icon_most_visited_vertical_spacing); + mVerticalSpacing = res.getDimensionPixelOffset(R.dimen.most_visited_vertical_spacing); mMinHorizontalSpacing = res.getDimensionPixelOffset( - R.dimen.icon_most_visited_min_horizontal_spacing); + R.dimen.most_visited_min_horizontal_spacing); mMaxHorizontalSpacing = res.getDimensionPixelOffset( - R.dimen.icon_most_visited_max_horizontal_spacing); - mMaxWidth = res.getDimensionPixelOffset(R.dimen.icon_most_visited_layout_max_width); + R.dimen.most_visited_max_horizontal_spacing); + mMaxWidth = res.getDimensionPixelOffset(R.dimen.most_visited_layout_max_width); } /**
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java index c8216caf8..05cab6e2 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ntp/NewTabPageView.java
@@ -77,7 +77,7 @@ private View mSearchBoxView; private TextView mSearchBoxTextView; private ImageView mVoiceSearchButton; - private ViewGroup mMostVisitedLayout; + private MostVisitedLayout mMostVisitedLayout; private View mMostVisitedPlaceholder; private View mOptOutView; private View mNoSearchLogoSpacer; @@ -259,9 +259,7 @@ mContentView = (ViewGroup) findViewById(R.id.ntp_content); mMostVisitedDesign = new MostVisitedDesign(getContext()); - ViewStub mostVisitedLayoutStub = (ViewStub) findViewById(R.id.most_visited_layout_stub); - mostVisitedLayoutStub.setLayoutResource(R.layout.icon_most_visited_layout); - mMostVisitedLayout = (ViewGroup) mostVisitedLayoutStub.inflate(); + mMostVisitedLayout = (MostVisitedLayout) findViewById(R.id.most_visited_layout); mMostVisitedDesign.initMostVisitedLayout(mMostVisitedLayout, searchProviderHasLogo); mSearchProviderLogoView = (LogoView) findViewById(R.id.search_provider_logo); @@ -878,7 +876,7 @@ } /** - * The new-fangled design for most visited tiles, where each tile shows a large icon and title. + * The design for most visited tiles: each tile shows a large icon and the site's title. */ private class MostVisitedDesign { @@ -900,8 +898,8 @@ MostVisitedDesign(Context context) { Resources res = context.getResources(); mMostVisitedLayoutBleed = res.getDimensionPixelSize( - R.dimen.icon_most_visited_layout_bleed); - mDesiredIconSize = res.getDimensionPixelSize(R.dimen.icon_most_visited_icon_size); + R.dimen.most_visited_layout_bleed); + mDesiredIconSize = res.getDimensionPixelSize(R.dimen.most_visited_icon_size); // On ldpi devices, mDesiredIconSize could be even smaller than ICON_MIN_SIZE_PX. mMinIconSize = Math.min(mDesiredIconSize, ICON_MIN_SIZE_PX); int desiredIconSizeDp = Math.round( @@ -919,16 +917,15 @@ return mMostVisitedLayoutBleed; } - public void initMostVisitedLayout(ViewGroup mostVisitedLayout, + public void initMostVisitedLayout(MostVisitedLayout mostVisitedLayout, boolean searchProviderHasLogo) { - ((IconMostVisitedLayout) mostVisitedLayout).setMaxRows( - searchProviderHasLogo ? MAX_ROWS : MAX_ROWS_NO_LOGO); + mostVisitedLayout.setMaxRows(searchProviderHasLogo ? MAX_ROWS : MAX_ROWS_NO_LOGO); } public void setSearchProviderHasLogo(View mostVisitedLayout, boolean hasLogo) { int paddingTop = getResources().getDimensionPixelSize(hasLogo - ? R.dimen.icon_most_visited_layout_padding_top - : R.dimen.icon_most_visited_layout_no_logo_padding_top); + ? R.dimen.most_visited_layout_padding_top + : R.dimen.most_visited_layout_no_logo_padding_top); mostVisitedLayout.setPadding(0, paddingTop, 0, mMostVisitedLayout.getPaddingBottom()); } @@ -943,7 +940,7 @@ @Override public void onLargeIconAvailable(Bitmap icon, int fallbackColor) { - IconMostVisitedItemView view = (IconMostVisitedItemView) mItem.getView(); + MostVisitedItemView view = (MostVisitedItemView) mItem.getView(); if (icon == null) { mIconGenerator.setBackgroundColor(fallbackColor); icon = mIconGenerator.generateIconForUrl(mItem.getUrl()); @@ -970,8 +967,8 @@ public View createMostVisitedItemView(LayoutInflater inflater, final String url, String displayTitle, MostVisitedItem item, final boolean isInitialLoad) { - final IconMostVisitedItemView view = (IconMostVisitedItemView) inflater.inflate( - R.layout.icon_most_visited_item, mMostVisitedLayout, false); + final MostVisitedItemView view = (MostVisitedItemView) inflater.inflate( + R.layout.most_visited_item, mMostVisitedLayout, false); view.setTitle(displayTitle); view.setOfflineAvailable(mManager.isOfflineAvailable(url) && !OfflinePageUtils.isConnected(getContext()));
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java index da0067ff..71cc2cb 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/prerender/ExternalPrerenderHandler.java
@@ -23,6 +23,10 @@ /** * Add a prerender for the given url and given content view dimensions. + * <p> + * The generated {@link WebContents} does not actually contain the prerendered contents but + * must be used as the container that you load the prerendered URL into. + * * @param profile The profile to use for the prerender. * @param url The url to prerender. * @param referrer The referrer for the prerender request. @@ -34,8 +38,7 @@ public WebContents addPrerender(Profile profile, String url, String referrer, int width, int height) { WebContents webContents = WebContentsFactory.createWebContents(false, false); - if (nativeAddPrerender(mNativeExternalPrerenderHandler, profile, webContents, - url, referrer, width, height)) { + if (addPrerender(profile, webContents, url, referrer, width, height)) { return webContents; } if (webContents != null) webContents.destroy(); @@ -43,6 +46,24 @@ } /** + * Adds a prerender for the given URL to an existing {@link WebContents} with the given + * dimensions. + * + * @param profile The profile to use for the prerender. + * @param webContents The WebContents to add the prerender to. + * @param url The url to prerender. + * @param referrer The referrer for the prerender request. + * @param width The width for the content view (render widget host view) for the prerender. + * @param height The height for the content view (render widget host view) for the prerender. + * @return Whether the prerender was successful. + */ + public boolean addPrerender(Profile profile, WebContents webContents, String url, + String referrer, int width, int height) { + return nativeAddPrerender(mNativeExternalPrerenderHandler, profile, webContents, + url, referrer, width, height); + } + + /** * Cancel the current prerender action on this {@link ExternalPrerenderHandler}. */ public void cancelCurrentPrerender() {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/DataUseSnackbarController.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/DataUseSnackbarController.java index 898835c..3da6729 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/DataUseSnackbarController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/DataUseSnackbarController.java
@@ -42,7 +42,8 @@ mSnackbarManager.showSnackbar(Snackbar.make( mContext.getString(R.string.data_use_tracking_started_snackbar_message), this) .setAction(mContext.getString(R.string.data_use_tracking_snackbar_action), - STARTED_SNACKBAR)); + STARTED_SNACKBAR) + .setForceDisplay()); DataUseTabUIManager.recordDataUseUIAction(DataUseUIActions.STARTED_SNACKBAR_SHOWN); } @@ -50,7 +51,8 @@ mSnackbarManager.showSnackbar(Snackbar.make( mContext.getString(R.string.data_use_tracking_ended_snackbar_message), this) .setAction(mContext.getString(R.string.data_use_tracking_snackbar_action), - ENDED_SNACKBAR)); + ENDED_SNACKBAR) + .setForceDisplay()); DataUseTabUIManager.recordDataUseUIAction(DataUseUIActions.ENDED_SNACKBAR_SHOWN); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java index 77a828b..2bf2863 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/LoFiBarPopupController.java
@@ -97,7 +97,8 @@ : R.string.data_reduction_lo_fi_snackbar_action); mSnackbarManager.showSnackbar(Snackbar.make(message, this) .setAction(buttonText, tab.getId()) - .setDuration(DEFAULT_LO_FI_SNACKBAR_SHOW_DURATION_MS)); + .setDuration(DEFAULT_LO_FI_SNACKBAR_SHOW_DURATION_MS) + .setForceDisplay()); DataReductionProxySettings.getInstance().incrementLoFiSnackbarShown(); DataReductionProxyUma.dataReductionProxyLoFiUIAction( DataReductionProxyUma.ACTION_LOAD_IMAGES_SNACKBAR_SHOWN);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java index 21908ae5..cde96c1 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/Snackbar.java
@@ -29,6 +29,7 @@ private boolean mSingleLine = true; private int mDurationMs; private Bitmap mProfileImage; + private boolean mForceDisplay = false; // Prevent instantiation. private Snackbar() {} @@ -102,6 +103,27 @@ return this; } + /** + * Forces this snackbar to be shown when {@link #dismissAllSnackbars(SnackbarManager)} is called + * from a timeout. If {@link #showSnackbar(SnackbarManager)} is called while this snackbar is + * showing, the new snackbar will be added to the stack and this snackbar will not be + * overwritten. + */ + public Snackbar setForceDisplay() { + mForceDisplay = true; + return this; + } + + /** + * Returns true if this snackbar should still be shown when @link + * #dismissAllSnackbars(SnackbarManager)} is called from a timeout. If + * {@link #showSnackbar(SnackbarManager)} is called while this snackbar is showing, the new + * snackbar will be added to the stack and this snackbar will not be overwritten. + */ + public boolean getForceDisplay() { + return mForceDisplay; + } + SnackbarController getController() { return mController; }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java index 6e0c69cc..e2da38d6 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/snackbar/SnackbarManager.java
@@ -133,11 +133,17 @@ /** * Shows a snackbar at the bottom of the screen, or above the keyboard if the keyboard is - * visible. + * visible. If the currently displayed snackbar is forcing display, the new snackbar is added as + * the next to be displayed on the stack. */ public void showSnackbar(Snackbar snackbar) { if (!mActivityInForeground) return; + if (mPopup != null && !mStack.empty() && mStack.peek().getForceDisplay()) { + mStack.add(mStack.size() - 1, snackbar); + return; + } + int durationMs = snackbar.getDuration(); if (durationMs == 0) { durationMs = DeviceClassManager.isAccessibilityModeEnabled(mDecor.getContext()) @@ -189,6 +195,11 @@ controllers.add(snackbar.getController()); } snackbar.getController().onDismissNoAction(snackbar.getActionData()); + + if (isTimeout && !mStack.isEmpty() && mStack.peek().getForceDisplay()) { + showSnackbar(mStack.pop()); + return; + } } mDecor.getViewTreeObserver().removeOnGlobalLayoutListener(this); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/PrerenderTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/PrerenderTest.java index fe223a6..f624bd8 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/PrerenderTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/PrerenderTest.java
@@ -6,15 +6,17 @@ import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE; +import android.test.FlakyTest; +import android.test.MoreAsserts; import android.test.suitebuilder.annotation.LargeTest; import android.view.KeyEvent; import org.chromium.base.ThreadUtils; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.base.test.util.Restriction; import org.chromium.chrome.R; import org.chromium.chrome.browser.omnibox.UrlBar; +import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeTabbedActivityTestBase; import org.chromium.chrome.test.util.ChromeTabUtils; @@ -32,20 +34,6 @@ * Tests are disabled on low-end devices. These only support one renderer for performance reasons. */ public class PrerenderTest extends ChromeTabbedActivityTestBase { - - // junit.framework.Assert has - // assertEquals(Object,Object) - // assertEquals(String,String) and - // assertNotSame(Object,Object), but no - // assertNotSame(String,String). - // Since String equality needs equals() and object equality uses - // ==, the lack of a proper API means it's easy to use object - // equality by accident since Object is a base class of String. - // But that's not what you want! - void assertNotEquals(String expected, String actual) { - assertFalse(expected.equals(actual)); - } - /** * We are using Autocomplete Action Predictor to decide whether or not to prerender. /* Without any training data the default action should be no-prerender. @@ -72,16 +60,16 @@ } /* + crbug.com/339668 @LargeTest @Restriction({RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @Feature({"TabContents"}) - crbug.com/339668 */ - @DisabledTest + @FlakyTest public void testPrerenderNotDead() throws InterruptedException, TimeoutException { String testUrl = TestHttpServerClient.getUrl( "chrome/test/data/android/prerender/google.html"); - PrerenderTestHelper.trainAutocompleteActionPredictorAndTestPrerender(testUrl, this); + PrerenderTestHelper.prerenderUrlAndFocusOmnibox(testUrl, this); final Tab tab = getActivity().getActivityTab(); // Navigate should use the prerendered version. assertEquals(TabLoadStatus.FULL_PRERENDERED_PAGE_LOAD, @@ -90,10 +78,10 @@ // Prerender again with new text; make sure we get something different. String newTitle = "Welcome to the YouTube"; testUrl = TestHttpServerClient.getUrl("chrome/test/data/android/prerender/youtube.html"); - PrerenderTestHelper.trainAutocompleteActionPredictorAndTestPrerender(testUrl, this); + PrerenderTestHelper.prerenderUrlAndFocusOmnibox(testUrl, this); // Make sure the current tab title is NOT from the prerendered page. - assertNotEquals(newTitle, tab.getTitle()); + MoreAsserts.assertNotEqual(newTitle, tab.getTitle()); TabTitleObserver observer = new TabTitleObserver(tab, newTitle); @@ -110,16 +98,12 @@ * Tests that we do get the page load finished notification even when a page has been fully * prerendered. */ - /* @LargeTest @Restriction({RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @Feature({"TabContents"}) - crbug.com/339668 - */ - @DisabledTest public void testPageLoadFinishNotification() throws InterruptedException { String url = TestHttpServerClient.getUrl("chrome/test/data/android/prerender/google.html"); - PrerenderTestHelper.trainAutocompleteActionPredictorAndTestPrerender(url, this); + PrerenderTestHelper.prerenderUrlAndFocusOmnibox(url, this); // Now let's press enter to validate the suggestion. The prerendered page should be // committed and we should get a page load finished notification (which would trigger the // page load). @@ -134,22 +118,20 @@ } /** - * Tests that we don't crash when dismissing a prerendered page with infobars and unlonad + * Tests that we don't crash when dismissing a prerendered page with infobars and unload * handler (See bug 5757331). * Note that this bug happened with the instant code. Now that we use Wicked Fast, we don't * deal with infobars ourselves. */ - /* @LargeTest @Restriction({RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @Feature({"TabContents"}) - crbug.com/339668 - */ - @DisabledTest public void testInfoBarDismissed() throws InterruptedException { final String url = TestHttpServerClient.getUrl( "chrome/test/data/geolocation/geolocation_on_load.html"); - PrerenderTestHelper.trainAutocompleteActionPredictorAndTestPrerender(url, this); + final ExternalPrerenderHandler handler = PrerenderTestHelper.prerenderUrlAndFocusOmnibox( + url, this); + // Let's clear the URL bar, this will discard the prerendered WebContents and close the // infobars. final UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); @@ -159,6 +141,7 @@ public void run() { urlBar.requestFocus(); urlBar.setText(""); + handler.cancelCurrentPrerender(); } }); }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java index f65db51d..440624e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/TabsOpenedFromExternalAppTest.java
@@ -369,7 +369,7 @@ /** * Tests that a tab is not reused when launched from the same app as an already opened tab and - * when the user typed in the location bar. + * when the user has navigated elsewhere manually in the same tab. * @throws InterruptedException */ /** @@ -378,17 +378,18 @@ * Bug 6467101 */ @FlakyTest - public void testNewTabWhenLocationBarEdited() throws InterruptedException { + public void testNewTabAfterNavigation() throws InterruptedException { startMainActivityFromLauncher(); String url1 = TestHttpServerClient.getUrl("chrome/test/data/android/google.html"); String url2 = TestHttpServerClient.getUrl("chrome/test/data/android/about.html"); + String url3 = TestHttpServerClient.getUrl("chrome/test/data/android/test.html"); // Launch a first URL from an app. launchUrlFromExternalApp(url1, EXTERNAL_APP_1_ID, false); - // Now simulate the user typing something in the location bar. - typeInOmnibox("hi", true); + // Now simulate the user manually navigating to another URL. + loadUrl(url3); // Launch a second URL from the same app, it should open in a new tab. int originalTabCount = ChromeTabUtils.getNumOpenTabs(getActivity()); @@ -419,9 +420,9 @@ // Launch a first URL from an app. launchUrlFromExternalApp(url1, EXTERNAL_APP_1_ID, false); - // Click the text-field and type something. + // Focus the text-field and type something. Tab tab = getActivity().getActivityTab(); - DOMUtils.clickNode(this, tab.getContentViewCore(), "textField"); + DOMUtils.focusNode(tab.getContentViewCore().getWebContents(), "textField"); // Some processing needs to happen before the test-field has the focus. CriteriaHelper.pollForCriteria(new ElementFocusedCriteria(
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java index 1648061a..3b884df 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchFakeServer.java
@@ -44,6 +44,7 @@ private final Map<String, FakeTapSearch> mFakeTapSearches = new HashMap<>(); private final Map<String, FakeLongPressSearch> mFakeLongPressSearches = new HashMap<>(); + private final Map<String, FakeSlowResolveSearch> mFakeSlowResolveSearches = new HashMap<>(); private FakeTapSearch mActiveFakeTapSearch; @@ -135,7 +136,7 @@ public class FakeTapSearch extends FakeSearch { private final boolean mIsNetworkUnavailable; private final int mResponseCode; - private final String mSearchTerm; + protected final String mSearchTerm; private final String mDisplayText; private final String mAlternateTerm; private final boolean mDoPreventPreload; @@ -231,7 +232,7 @@ /** * Simulates a Search Term Resolution. */ - private void simulateSearchTermResolution() { + protected void simulateSearchTermResolution() { mManagerTest.runOnMainSync(getRunnable()); } @@ -257,6 +258,68 @@ } //============================================================================================ + // FakeTapSearch + //============================================================================================ + + /** + * Class that represents a fake tap triggered contextual search that is slow to resolve. + */ + public class FakeSlowResolveSearch extends FakeTapSearch { + /** + * @param nodeId + * @param isNetworkUnavailable + * @param responseCode + * @param searchTerm + * @param displayText + * @param alternateTerm + * @param doPreventPreload + * @param startAdjust + * @param endAdjust + * @param contextLanguage + */ + FakeSlowResolveSearch(String nodeId, boolean isNetworkUnavailable, int responseCode, + String searchTerm, String displayText, String alternateTerm, + boolean doPreventPreload, int startAdjust, int endAdjust, String contextLanguage) { + super(nodeId, isNetworkUnavailable, responseCode, searchTerm, displayText, + alternateTerm, doPreventPreload, startAdjust, endAdjust, contextLanguage); + } + + @Override + public void simulate() throws InterruptedException, TimeoutException { + mActiveFakeTapSearch = this; + + // When a resolution is needed, the simulation does not start until the system + // requests one, and it does not finish until the simulated resolution happens. + mDidStartResolution = false; + mDidFinishResolution = false; + + mManagerTest.clickNode(getNodeId()); + mManagerTest.waitForSelectionToBe(mSearchTerm); + + if (mPolicy.shouldPreviousTapResolve(getBasePageUrl())) { + // Now wait for the Search Term Resolution to start. + mManagerTest.waitForSearchTermResolutionToStart(this); + } else { + throw new RuntimeException("Tried to simulate a slow resolving search when " + + "not resolving!"); + } + } + + /** + * Finishes the resolving of a slow-resolving Tap search. + * @throws InterruptedException + * @throws TimeoutException + */ + void finishResolve() throws InterruptedException, TimeoutException { + // Simulate a Search Term Resolution. + simulateSearchTermResolution(); + + // Now wait for the simulated Search Term Resolution to finish. + mManagerTest.waitForSearchTermResolutionToFinish(this); + } + } + + //============================================================================================ // OverlayPanelContentWrapper //============================================================================================ @@ -482,6 +545,9 @@ "Resolution", "Resolution", "alternate-term", false, 0, 0, "")); registerFakeTapSearch(new FakeTapSearch("german", false, 200, "Deutsche", "Deutsche", "alternate-term", false, 0, 0, "de")); + + registerFakeSlowResolveSearch(new FakeSlowResolveSearch( + "search", false, 200, "Search", "Search", "alternate-term", false, 0, 0, "")); } /** @@ -501,6 +567,14 @@ } /** + * @param id The ID of the FakeSlowResolveSearch. + * @return The {@code FakeSlowResolveSearch} with the given ID. + */ + public FakeSlowResolveSearch getFakeSlowResolveSearch(String id) { + return mFakeSlowResolveSearches.get(id); + } + + /** * Register the FakeLongPressSearch. * @param fakeSearch The FakeLongPressSearch to be registered. */ @@ -515,4 +589,12 @@ private void registerFakeTapSearch(FakeTapSearch fakeSearch) { mFakeTapSearches.put(fakeSearch.getNodeId(), fakeSearch); } + + /** + * Register the FakeSlowResolveSearch. + * @param fakeSlowResolveSearch The {@code FakeSlowResolveSearch} to be registered. + */ + private void registerFakeSlowResolveSearch(FakeSlowResolveSearch fakeSlowResolveSearch) { + mFakeSlowResolveSearches.put(fakeSlowResolveSearch.getNodeId(), fakeSlowResolveSearch); + } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java index 639330d..8857d6b3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManagerTest.java
@@ -36,6 +36,7 @@ import org.chromium.chrome.browser.compositor.bottombar.OverlayContentProgressObserver; import org.chromium.chrome.browser.compositor.bottombar.OverlayPanel.PanelState; import org.chromium.chrome.browser.compositor.bottombar.contextualsearch.ContextualSearchPanel; +import org.chromium.chrome.browser.contextualsearch.ContextualSearchFakeServer.FakeSlowResolveSearch; import org.chromium.chrome.browser.externalnav.ExternalNavigationHandler; import org.chromium.chrome.browser.gsa.GSAContextDisplaySelection; import org.chromium.chrome.browser.omnibox.UrlBar; @@ -91,6 +92,9 @@ private ContextualSearchPolicy mPolicy; private ActivityMonitor mActivityMonitor; + // State for an individual test. + FakeSlowResolveSearch mLatestSlowResolveSearch; + public ContextualSearchManagerTest() { super(ChromeActivity.class); } @@ -227,7 +231,7 @@ } /** - * Simulates a tap triggered search. + * Simulates a tap-triggered search. * * @param nodeId The id of the node to be tapped. * @throws InterruptedException @@ -241,6 +245,28 @@ } /** + * Simulates a tap-triggered search with slow server response. + * + * @param nodeId The id of the node to be tapped. + * @throws InterruptedException + * @throws TimeoutException + */ + private void simulateSlowResolveSearch(String nodeId) + throws InterruptedException, TimeoutException { + mLatestSlowResolveSearch = mFakeServer.getFakeSlowResolveSearch(nodeId); + mLatestSlowResolveSearch.simulate(); + waitForPanelToPeek(); + } + + /** + * Simulates a slow response for the most recent {@link FakeSlowResolveSearch} set up + * by calling simulateSlowResolveSearch. + */ + private void simulateSlowResolveFinished() { + mLatestSlowResolveSearch.simulateSearchTermResolution(); + assertLoadedSearchTermMatches(mLatestSlowResolveSearch.getSearchTerm()); + } + /** * Registers all fake searches to be used in tests. */ private void registerFakeSearches() { @@ -568,14 +594,6 @@ } /** - * Asserts that the panel was never opened. - * @throws InterruptedException - */ - private void assertPanelNeverOpened() throws InterruptedException { - waitForPanelToEnterState(PanelState.UNDEFINED); - } - - /** * Waits for the Search Panel to enter the given {@code PanelState} and assert. * @param state The {@link PanelState} to wait for. * @throws InterruptedException @@ -1363,19 +1381,16 @@ * Test that tapping on the Search Bar before having a resolved search term does not * promote to a tab, and that after the resolution it does promote to a tab. * + * Re-enable the test after fixing http://crbug.com/578334. * @SmallTest * @Feature({"ContextualSearch"}) */ - @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE}) @CommandLineFlags.Add(ChromeSwitches.DISABLE_DOCUMENT_MODE) @FlakyTest public void testTapSearchBarPromotesToTab() throws InterruptedException, TimeoutException { - // Tap on a word. - clickWordNode("intelligence"); - assertSearchTermRequested(); - - // Wait for the panel to peek. - waitForPanelToPeek(); + // Tap on a word when the server is slow to resolve. + simulateSlowResolveSearch("search"); // Swipe Panel up and wait for it to maximize. flingPanelUpToTop(); @@ -1392,29 +1407,29 @@ }; getActivity().getTabModelSelector().addObserver(observer); - // Tap the Search Bar. + // Tap the Search Bar -- should not promote since we are still waiting to Resolve. clickPanelBar(0.05f); // The Search Term Resolution response hasn't arrived yet, so the Panel should not // be promoted. Therefore, we are asserting that the Panel is still maximized. waitForPanelToMaximize(); - // Get a Search Term Resolution response. - fakeResponse(false, 200, "Intelligence", "display-text", "alternate-term", false); - assertContainsParameters("Intelligence", "alternate-term"); + // Let the Search Term Resolution finish. + simulateSlowResolveFinished(); - // Tap the Search Bar again. + // Tap the Search Bar again -- should promote to a separate tab. clickPanelBar(0.05f); // Now that the response has arrived, tapping on the Search Panel should promote it // to a Tab. Therefore, we are asserting that the Panel got closed. waitForPanelToClose(); - // Finally, make sure a tab was created. - if (!FeatureUtilities.isDocumentMode(getInstrumentation().getContext())) { - // TODO(donnd): figure out how to check for tab creation in Document mode. - tabCreatedHelper.waitForCallback(tabCreatedHelperCallCount); - } + // Should not fail -- this test was set up to disable document mode. + assertFalse(FeatureUtilities.isDocumentMode(getInstrumentation().getContext())); + + // Make sure a tab was created. + tabCreatedHelper.waitForCallback(tabCreatedHelperCallCount); + getActivity().getTabModelSelector().removeObserver(observer); } @@ -1556,52 +1571,6 @@ } /** - * Tests the tap triggered promo limit for opt-out. - * @SmallTest - * @Feature({"ContextualSearch"}) - */ - @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - @FlakyTest - public void testTapTriggeredPromoLimitForOptOut() - throws InterruptedException, TimeoutException { - mPolicy.setPromoTapTriggeredLimitForTesting(2); - mPolicy.overrideDecidedStateForTesting(false); - - clickWordNode("states"); - clickNode("states-far"); - waitForPanelToCloseAndSelectionDissolved(); - clickWordNode("states"); - clickNode("states-far"); - waitForPanelToCloseAndSelectionDissolved(); - - // 3rd click won't peek the panel. - clickNode("states"); - assertPanelClosedOrUndefined(); - // The Tap should not select any text either! - assertNull(getSelectedText()); - - // A long-press should still show the promo bar. - longPressNode("states"); - waitForPanelToPeek(); - - // Expanding the panel should deactivate the limit. - tapBarToExpandAndClosePanel(); - // Clear the long-press selection. - clickNode("states-far"); - - // Three taps should work now. - clickWordNode("states"); - clickNode("states-far"); - waitForPanelToCloseAndSelectionDissolved(); - clickWordNode("states"); - clickNode("states-far"); - waitForPanelToCloseAndSelectionDissolved(); - clickWordNode("states"); - clickNode("states-far"); - waitForPanelToCloseAndSelectionDissolved(); - } - - /** * Tests expanding the panel before the search term has resolved, verifies that nothing * loads until the resolve completes and that it's now a normal priority URL. */ @@ -1773,17 +1742,12 @@ * * This test is very similar to an existing test for this same feature, so I'm proactively * marking this as a FlakyTest too (since we're landing right before upstreaming). - * - * @SmallTest - * @Feature({"ContextualSearch"}) */ + @SmallTest + @Feature({"ContextualSearch"}) @Restriction({RESTRICTION_TYPE_PHONE, RESTRICTION_TYPE_NON_LOW_END_DEVICE}) - @FlakyTest public void testPromoTapCount() throws InterruptedException, TimeoutException { mPolicy.setPromoTapTriggeredLimitForTesting(2); - // Note that this tests the basic underlying counter used by - // testTapTriggeredPromoLimitForOptOut. - // TODO(donnd): consider removing either this test or testTapTriggeredPromoLimitForOptOut. mPolicy.overrideDecidedStateForTesting(false); assertTapPromoCounterEnabledAt(0); @@ -1803,7 +1767,8 @@ // An open should disable the counter, but we need to use long-press (tap is now disabled). longPressNode("states-far"); tapPeekingBarToExpandAndAssert(); - tapBasePageToClosePanel(); + pressBackButton(); + waitForPanelToClose(); assertTapPromoCounterDisabledAt(2); // Even though we closed the panel, the long-press selection is still there. @@ -2481,13 +2446,17 @@ assertTrue(mFakeServer.hasRemovedUrl(url3)); } + //============================================================================================ + // Translate Tests + //============================================================================================ + /** * Tests that a simple Tap with language determination triggers translation. */ @SmallTest @Feature({"ContextualSearch"}) @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - @CommandLineFlags.Add(ContextualSearchFieldTrial.ENABLE_TRANSLATION_FOR_TESTING + "=true") + @CommandLineFlags.Add(ContextualSearchFieldTrial.ENABLE_TRANSLATION + "=true") public void testTapWithLanguage() throws InterruptedException, TimeoutException { // Tapping a German word should trigger translation. simulateTapSearch("german"); @@ -2504,7 +2473,7 @@ @SmallTest @Feature({"ContextualSearch"}) @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - @CommandLineFlags.Add(ContextualSearchFieldTrial.ENABLE_TRANSLATION_FOR_TESTING + "=true") + @CommandLineFlags.Add(ContextualSearchFieldTrial.ENABLE_TRANSLATION + "=true") public void testTapWithoutLanguage() throws InterruptedException, TimeoutException { // Tapping an English word should NOT trigger translation. simulateTapSearch("search"); @@ -2514,12 +2483,29 @@ } /** + * Tests that the server-controlled-onebox flag can override behavior on a simple Tap + * without language determination. + */ + @SmallTest + @Feature({"ContextualSearch"}) + @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) + @CommandLineFlags.Add({ContextualSearchFieldTrial.ENABLE_TRANSLATION + "=true", + ContextualSearchFieldTrial.ENABLE_SERVER_CONTROLLED_ONEBOX + "=true"}) + public void testTapWithoutLanguageCanBeForced() throws InterruptedException, TimeoutException { + // Tapping an English word should trigger translation. + simulateTapSearch("search"); + + // Make sure we did try to trigger translate. + assertTrue(mManager.getRequest().isTranslationForced()); + } + + /** * Tests that a long-press does trigger translation. */ @SmallTest @Feature({"ContextualSearch"}) @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - @CommandLineFlags.Add(ContextualSearchFieldTrial.ENABLE_TRANSLATION_FOR_TESTING + "=true") + @CommandLineFlags.Add(ContextualSearchFieldTrial.ENABLE_TRANSLATION + "=true") public void testLongpressTranslates() throws InterruptedException, TimeoutException { // LongPress on any word should trigger translation. simulateLongPressSearch("search"); @@ -2534,7 +2520,7 @@ @SmallTest @Feature({"ContextualSearch"}) @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - @CommandLineFlags.Add({ContextualSearchFieldTrial.ENABLE_TRANSLATION_FOR_TESTING + "=true", + @CommandLineFlags.Add({ContextualSearchFieldTrial.ENABLE_TRANSLATION + "=true", ContextualSearchFieldTrial.DISABLE_AUTO_DETECT_TRANSLATION_ONEBOX + "=true"}) public void testLongpressAutoDetectDisabledDoesNotTranslate() throws InterruptedException, TimeoutException { @@ -2551,7 +2537,7 @@ @SmallTest @Feature({"ContextualSearch"}) @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - @CommandLineFlags.Add({ContextualSearchFieldTrial.ENABLE_TRANSLATION_FOR_TESTING + "=true", + @CommandLineFlags.Add({ContextualSearchFieldTrial.ENABLE_TRANSLATION + "=true", ContextualSearchFieldTrial.DISABLE_FORCE_TRANSLATION_ONEBOX + "=true"}) public void testLongpressTranslateDisabledDoesNotTranslate() throws InterruptedException, TimeoutException {
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java index 04510b8..147955e 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/customtabs/CustomTabActivityTest.java
@@ -498,7 +498,7 @@ Bundle bundle = makeBottomBarBundle(i, expectedIcon, Integer.toString(i)); bundles.add(bundle); } - intent.putExtra(CustomTabsIntent.EXTRA_ACTION_BUTTON_BUNDLE, bundles); + intent.putExtra(CustomTabsIntent.EXTRA_ACTION_BAR_ITEMS, bundles); startCustomTabActivityWithIntent(intent); ViewGroup bottomBar = (ViewGroup) getActivity().findViewById(R.id.bottombar);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java index 51a599c..cfca678fe 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/fullscreen/FullscreenManagerTest.java
@@ -4,11 +4,12 @@ package org.chromium.chrome.browser.fullscreen; +import static org.chromium.base.test.util.Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE; + import android.graphics.Rect; import android.graphics.Region; import android.os.Build; import android.os.SystemClock; -import android.test.FlakyTest; import android.test.suitebuilder.annotation.LargeTest; import android.test.suitebuilder.annotation.MediumTest; import android.view.View; @@ -18,8 +19,10 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.Feature; +import org.chromium.base.test.util.Restriction; import org.chromium.base.test.util.UrlUtils; import org.chromium.chrome.R; +import org.chromium.chrome.browser.fullscreen.ChromeFullscreenManager.FullscreenListener; import org.chromium.chrome.browser.omnibox.UrlBar; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.browser.tab.TabWebContentsDelegateAndroid; @@ -28,13 +31,14 @@ import org.chromium.chrome.test.util.PrerenderTestHelper; import org.chromium.chrome.test.util.TestHttpServerClient; import org.chromium.content.browser.ContentViewCore; +import org.chromium.content.browser.test.util.CallbackHelper; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; import org.chromium.content.browser.test.util.TestTouchUtils; import org.chromium.content.browser.test.util.UiUtils; -import java.util.concurrent.Callable; -import java.util.concurrent.ExecutionException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; /** @@ -132,8 +136,7 @@ @LargeTest @Feature({"Fullscreen"}) - public void testExitPersistentFullscreenAllowsManualFullscreen() - throws InterruptedException, ExecutionException { + public void testExitPersistentFullscreenAllowsManualFullscreen() throws InterruptedException { startMainActivityWithURL(LONG_FULLSCREEN_API_HTML_TEST_PAGE); ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); @@ -147,36 +150,30 @@ singleClickView(view); waitForPersistentFullscreen(delegate, true); - assertEquals((float) -topControlsHeight, waitForTopControlsPosition(-topControlsHeight)); + waitForTopControlsPosition(-topControlsHeight); TestTouchUtils.sleepForDoubleTapTimeout(getInstrumentation()); singleClickView(view); waitForPersistentFullscreen(delegate, false); waitForNoBrowserTopControlsOffset(); - assertEquals((float) 0, waitForTopControlsPosition(0)); + waitForTopControlsPosition(0); scrollTopControls(false); scrollTopControls(true); } - /** - * Marked flaky on 2015-05-15: http://crbug.com/488393 - * @LargeTest - * @Feature({"Fullscreen"}) - */ - @FlakyTest - public void testManualHidingShowingTopControls() - throws InterruptedException, ExecutionException { + @LargeTest + @Feature({"Fullscreen"}) + public void testManualHidingShowingTopControls() throws InterruptedException { startMainActivityWithURL(LONG_HTML_TEST_PAGE); - ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); - fullscreenManager.disableBrowserOverrideForTest(); + final ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); + disableBrowserOverrides(); assertEquals(fullscreenManager.getControlOffset(), 0f); - scrollTopControls(false); - // Reverse the scroll and ensure the controls come back into view. - scrollTopControls(true); + waitForTopControlsToBeMoveable(getActivity().getActivityTab()); + // Check that the URL bar has not grabbed focus (http://crbug/236365) UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); assertFalse("Url bar grabbed focus", urlBar.hasFocus()); @@ -184,12 +181,11 @@ @LargeTest @Feature({"Fullscreen"}) - public void testHidingTopControlsRemovesSurfaceFlingerOverlay() - throws InterruptedException, ExecutionException { + public void testHidingTopControlsRemovesSurfaceFlingerOverlay() throws InterruptedException { startMainActivityWithURL(LONG_HTML_TEST_PAGE); - ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); - fullscreenManager.disableBrowserOverrideForTest(); + final ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); + disableBrowserOverrides(); assertEquals(fullscreenManager.getControlOffset(), 0f); @@ -214,7 +210,7 @@ } }); - getInstrumentation().runOnMainSync(new Runnable() { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { // Check that when the top controls are gone, the entire decorView is contained @@ -235,14 +231,13 @@ @LargeTest @Feature({"Fullscreen"}) - public void testManualFullscreenDisabledForChromePages() - throws InterruptedException, ExecutionException { + public void testManualFullscreenDisabledForChromePages() throws InterruptedException { // The credits page was chosen as it is a chrome:// page that is long and would support // manual fullscreen if it were supported. startMainActivityWithURL("chrome://credits"); - ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); - fullscreenManager.disableBrowserOverrideForTest(); + final ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); + disableBrowserOverrides(); int topControlsHeight = fullscreenManager.getTopControlsHeight(); assertEquals(fullscreenManager.getControlOffset(), 0f); @@ -254,15 +249,14 @@ long downTime = SystemClock.uptimeMillis(); dragStart(dragX, dragStartY, downTime); dragTo(dragX, dragX, dragStartY, dragFullY, 100, downTime); - assertEquals(0f, waitForTopControlsPosition(0f)); + waitForTopControlsPosition(0f); dragEnd(dragX, dragFullY, downTime); - assertEquals(0f, waitForTopControlsPosition(0f)); + waitForTopControlsPosition(0f); } @LargeTest @Feature({"Fullscreen"}) - public void testControlsShownOnUnresponsiveRenderer() - throws InterruptedException, ExecutionException { + public void testControlsShownOnUnresponsiveRenderer() throws InterruptedException { startMainActivityWithURL(LONG_HTML_TEST_PAGE); ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); @@ -281,7 +275,7 @@ delegate.rendererUnresponsive(); } }); - assertEquals(0f, waitForTopControlsPosition(0f)); + waitForTopControlsPosition(0f); ThreadUtils.runOnUiThread(new Runnable() { @Override @@ -292,29 +286,24 @@ waitForNoBrowserTopControlsOffset(); } - /* @LargeTest @Feature({"Fullscreen"}) @Restriction(RESTRICTION_TYPE_NON_LOW_END_DEVICE) - crbug.com/339668 - */ - @FlakyTest - public void testPrerenderedPageSupportsManualHiding() - throws InterruptedException, ExecutionException { + public void testPrerenderedPageSupportsManualHiding() throws InterruptedException { startMainActivityOnBlankPage(); - - ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); - fullscreenManager.disableBrowserOverrideForTest(); + disableBrowserOverrides(); final Tab tab = getActivity().getActivityTab(); final String testUrl = TestHttpServerClient.getUrl( "chrome/test/data/android/very_long_google.html"); - PrerenderTestHelper.trainAutocompleteActionPredictorAndTestPrerender(testUrl, this); + PrerenderTestHelper.prerenderUrlAndFocusOmnibox(testUrl, this); assertTrue("loadUrl did not use pre-rendered page.", PrerenderTestHelper.isLoadUrlResultPrerendered(loadUrl(testUrl))); UrlBar urlBar = (UrlBar) getActivity().findViewById(R.id.url_bar); OmniboxTestUtils.toggleUrlBarFocus(urlBar, false); + OmniboxTestUtils.waitForFocusAndKeyboardActive(urlBar, false); + ThreadUtils.runOnUiThreadBlocking(new Runnable() { @Override public void run() { @@ -322,17 +311,12 @@ } }); - scrollTopControls(false); + waitForTopControlsToBeMoveable(tab); } - /* - Marked flaky on 2015-07-20: http://crbug.com/512299 @LargeTest @Feature({"Fullscreen"}) - */ - @FlakyTest - public void testTopControlsShownWhenInputIsFocused() - throws InterruptedException, ExecutionException { + public void testTopControlsShownWhenInputIsFocused() throws InterruptedException { startMainActivityWithURL(LONG_HTML_WITH_AUTO_FOCUS_INPUT_TEST_PAGE); ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); @@ -354,11 +338,11 @@ Tab tab = getActivity().getActivityTab(); singleClickView(tab.getView()); waitForEditableNodeToLoseFocus(tab); - scrollTopControls(false); - scrollTopControls(true); + + waitForTopControlsToBeMoveable(getActivity().getActivityTab()); } - private void scrollTopControls(boolean show) throws InterruptedException, ExecutionException { + private void scrollTopControls(boolean show) throws InterruptedException { ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); int topControlsHeight = fullscreenManager.getTopControlsHeight(); @@ -379,9 +363,8 @@ long downTime = SystemClock.uptimeMillis(); dragStart(dragX, dragStartY, downTime); dragTo(dragX, dragX, dragStartY, dragEndY, 100, downTime); - assertEquals(expectedPosition, waitForTopControlsPosition(expectedPosition)); dragEnd(dragX, dragEndY, downTime); - assertEquals(expectedPosition, waitForTopControlsPosition(expectedPosition)); + waitForTopControlsPosition(expectedPosition); } private void togglePersistentFullscreen(final TabWebContentsDelegateAndroid delegate, @@ -435,21 +418,17 @@ }); } - private float waitForTopControlsPosition(final float position) - throws InterruptedException, ExecutionException { + private void waitForTopControlsPosition(final float position) + throws InterruptedException { final ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); CriteriaHelper.pollForUIThreadCriteria(new Criteria() { @Override public boolean isSatisfied() { + updateFailureReason("Top controls did not reach expected position. Expected: " + + position + ", Actual: " + fullscreenManager.getControlOffset()); return position == fullscreenManager.getControlOffset(); } }); - return ThreadUtils.runOnUiThreadBlocking(new Callable<Float>() { - @Override - public Float call() throws Exception { - return fullscreenManager.getControlOffset(); - } - }); } private void waitForNoBrowserTopControlsOffset() throws InterruptedException { @@ -473,6 +452,64 @@ }); } + /** + * Waits for the top controls to be moveable by user gesture. + * <p> + * This function requires the top controls to start fully visible. It till then ensure that at + * some point the controls can be moved by user gesture. It will then fully cycle the top + * controls to entirely hidden and back to fully shown. + */ + private void waitForTopControlsToBeMoveable(final Tab tab) throws InterruptedException { + waitForTopControlsPosition(0f); + + final CallbackHelper contentMovedCallback = new CallbackHelper(); + final ChromeFullscreenManager fullscreenManager = getActivity().getFullscreenManager(); + final float initialVisibleContentOffset = fullscreenManager.getVisibleContentOffset(); + + fullscreenManager.addListener(new FullscreenListener() { + @Override + public void onVisibleContentOffsetChanged(float offset) { + if (offset != initialVisibleContentOffset) { + contentMovedCallback.notifyCalled(); + fullscreenManager.removeListener(this); + } + } + + @Override + public void onToggleOverlayVideoMode(boolean enabled) { + } + + @Override + public void onContentOffsetChanged(float offset) { + } + }); + + float dragX = 50f; + float dragStartY = tab.getView().getHeight() - 50f; + + for (int i = 0; i < 10; i++) { + float dragEndY = dragStartY - fullscreenManager.getTopControlsHeight(); + + long downTime = SystemClock.uptimeMillis(); + dragStart(dragX, dragStartY, downTime); + dragTo(dragX, dragX, dragStartY, dragEndY, 100, downTime); + dragEnd(dragX, dragEndY, downTime); + + try { + contentMovedCallback.waitForCallback(0, 1, 500, TimeUnit.MILLISECONDS); + + scrollTopControls(false); + scrollTopControls(true); + + return; + } catch (TimeoutException e) { + // Ignore and retry + } + } + + fail("Visible content never moved as expected."); + } + private void waitForEditableNodeToLoseFocus(final Tab tab) throws InterruptedException { CriteriaHelper.pollForUIThreadCriteria(new Criteria() { @Override @@ -483,6 +520,15 @@ }); } + private void disableBrowserOverrides() { + ThreadUtils.runOnUiThreadBlocking(new Runnable() { + @Override + public void run() { + getActivity().getFullscreenManager().disableBrowserOverrideForTest(); + } + }); + } + @Override protected void startMainActivityWithURL(String url) throws InterruptedException { super.startMainActivityWithURL(url);
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastReconnectTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastReconnectTest.java deleted file mode 100644 index 2d95f03..0000000 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/media/remote/CastReconnectTest.java +++ /dev/null
@@ -1,183 +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.chrome.browser.media.remote; - -import android.app.Activity; -import android.app.Instrumentation; -import android.app.Instrumentation.ActivityMonitor; -import android.graphics.Rect; -import android.view.View; - -import org.chromium.base.test.util.HostDrivenTest; -import org.chromium.chrome.R; -import org.chromium.chrome.browser.tab.Tab; -import org.chromium.chrome.test.util.ActivityUtils; -import org.chromium.chrome.test.util.TestHttpServerClient; -import org.chromium.content.browser.test.util.DOMUtils; -import org.chromium.content_public.browser.WebContents; - -import java.util.concurrent.TimeoutException; - -/** - * Test casting when Chrome shuts down and restarts. - * - * These tests are run from the python wrapper test/host_driven_tests/ReconnectCastTest.py. They - * will not run correctly in isolation, and hence are marked as disabled to prevent the test runner - * from running them automatically outside the wrapper. - */ -public class CastReconnectTest extends CastTestBase { - private long mVideoDurationMs; - - /** - * Cast and pause a video. This doesn't test anything itself, but just sets up the state for - * when we restart Chrome - * - * @throws InterruptedException - * @throws TimeoutException - */ - @HostDrivenTest - public void testReconnectSetup() throws InterruptedException, TimeoutException { - castAndPauseDefaultVideoFromPage(DEFAULT_VIDEO_PAGE); - } - - /** - * Test the state after reconnection, and confirm that pressing play starts the video. - * - * @throws InterruptedException - * @throws TimeoutException - */ - @HostDrivenTest - public void testVideoContinuing() throws InterruptedException, TimeoutException { - // TODO(aberent) Check that the notification is still present. Will fail at - // the moment, and is difficult to do with the way the notification service - // currently works. - - // Put the video into fullscreen and check that it casts automatically - final Tab tab = getActivity().getActivityTab(); - - WebContents webContents = tab.getWebContents(); - waitUntilVideoReady(VIDEO_ELEMENT, webContents); - - final Rect videoRect = DOMUtils.getNodeBounds(webContents, VIDEO_ELEMENT); - ExpandedControllerActivity fullscreenControls = ActivityUtils.waitForActivityWithTimeout( - getInstrumentation(), ExpandedControllerActivity.class, new Runnable() { - @Override - public void run() { - tapVideoFullscreenButton(tab, videoRect); - } - }, MAX_VIEW_TIME_MS); - assertNotNull("Fullscreen controls not recreated", fullscreenControls); - View pauseButton = fullscreenControls.findViewById(R.id.pause); - assertNotNull("No pause/play button", pauseButton); - clickButton(pauseButton); - - // Give it time to start - Thread.sleep(STABILIZE_TIME_MS); - - checkVideoStarted(DEFAULT_VIDEO); - } - - /** - * Test going into fullscreen on a new video after reconnection. - * - * @throws InterruptedException - * @throws TimeoutException - */ - @HostDrivenTest - public void testNewVideo() throws InterruptedException, TimeoutException { - - // Load a new video on the page - loadUrl(TestHttpServerClient.getUrl(TEST_VIDEO_PAGE_2)); - - // Put the video into fullscreen - final Tab tab = getActivity().getActivityTab(); - - WebContents webContents = tab.getWebContents(); - waitUntilVideoReady(VIDEO_ELEMENT, webContents); - - final Rect videoRect = DOMUtils.getNodeBounds(webContents, VIDEO_ELEMENT); - - // Video should cast automatically - ExpandedControllerActivity fullscreenControls = ActivityUtils.waitForActivityWithTimeout( - getInstrumentation(), ExpandedControllerActivity.class, new Runnable() { - @Override - public void run() { - tapVideoFullscreenButton(tab, videoRect); - } - }, MAX_VIEW_TIME_MS); - assertNotNull("Fullscreen controls not recreated", fullscreenControls); - - // Wait for it to start (may take some time, hence use a busy wait) - for (int time = 0; time < MAX_VIEW_TIME_MS; time += VIEW_RETRY_MS) { - if (isPlayingRemotely()) break; - sleepNoThrow(VIEW_RETRY_MS); - } - - checkVideoStarted(TEST_VIDEO_2); - } - - /** - * Cast a video but don't pause it. Use for testing reconnection after video finished - * - * @throws InterruptedException - * @throws TimeoutException - */ - @HostDrivenTest - public void testVideoFinishedSetup() throws InterruptedException, TimeoutException { - castDefaultVideoFromPage(DEFAULT_VIDEO_PAGE); - - // Get the duration of the video - mVideoDurationMs = getRemoteDurationMs(); - } - - /** - * Test that once the video has finished we don't automatically reconnect. - * - * @throws InterruptedException - * @throws TimeoutException - */ - @HostDrivenTest - public void testVideoFinished() throws InterruptedException, TimeoutException { - // Give the video time to finish (actually will probably have already finished, - // but this makes sure) - sleepNoThrow(mVideoDurationMs); - - // TODO(aberent) Check that the notification has gone away. Difficult to do until - // the notification handling is refactored. - - // Put the video into fullscreen and check that the fullscreen controls are not recreated - Tab tab = getActivity().getActivityTab(); - - WebContents webContents = tab.getWebContents(); - waitUntilVideoReady(VIDEO_ELEMENT, webContents); - - Rect videoRect = DOMUtils.getNodeBounds(webContents, VIDEO_ELEMENT); - Instrumentation instrumentation = getInstrumentation(); - ActivityMonitor monitor = instrumentation.addMonitor( - ExpandedControllerActivity.class.getCanonicalName(), null, false); - - tapVideoFullscreenButton(tab, videoRect); - - instrumentation.waitForIdleSync(); - Activity fullScreenControls = monitor.getLastActivity(); - if (fullScreenControls == null) { - fullScreenControls = monitor.waitForActivityWithTimeout(MAX_VIEW_TIME_MS); - } - assertNull(fullScreenControls); - } - - - @Override - protected void setUp() throws Exception { - mSkipClearAppData = true; - super.setUp(); - } - - @Override - public void startMainActivity() throws InterruptedException { - startMainActivityFromLauncher(); - } - -}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java index 0092485..e199808 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/util/FeatureUtilitiesTest.java
@@ -17,7 +17,6 @@ import org.chromium.base.ThreadUtils; import org.chromium.base.test.util.AdvancedMockContext; -import org.chromium.base.test.util.DisabledTest; import org.chromium.base.test.util.Feature; import org.chromium.sync.signin.AccountManagerHelper; import org.chromium.sync.test.util.MockAccountManager; @@ -203,7 +202,11 @@ assertFalse(RecognizesSpeechUncached); } - @DisabledTest // Flaked on the try bot: http://crbug.com/543160 + // This test previously flaked on the try bot: http://crbug.com/543160. + // Re-enabling this test since there has been related cleanup/refactoring + // during the time the test was disabled. If the test starts flaking again, + // re-open the bug. + // TODO(nyquist): Remove this if the test is not flaky anymore. @SmallTest @Feature({"FeatureUtilities", "GoogleAccounts"}) public void testHasGoogleAccountCorrectlyDetected() { @@ -223,7 +226,11 @@ assertTrue(hasAuthenticator); } - @DisabledTest // Flaked on the try bot: http://crbug.com/543160 + // This test previously flaked on the try bot: http://crbug.com/543160. + // Re-enabling this test since there has been related cleanup/refactoring + // during the time the test was disabled. If the test starts flaking again, + // re-open the bug. + // TODO(nyquist): Remove this if the test is not flaky anymore. @SmallTest @Feature({"FeatureUtilities", "GoogleAccounts"}) public void testHasNoGoogleAccountCorrectlyDetected() {
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index eb2a637..352225f 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd
@@ -9521,8 +9521,8 @@ <message name="IDS_AUTOFILL_ADD_CREDITCARD_CAPTION" desc="The caption on the edit Autofill credit card dialog the new entry."> Add a credit card </message> - <message name="IDS_AUTOFILL_USE_WALLET_DATA" desc="The text for the checkbox that controls the Autofill/Wallet integration feature."> - Sync credit cards and addresses using Google Payments + <message name="IDS_AUTOFILL_USE_PAYMENTS_DATA" desc="The text for the checkbox that controls the Autofill/Payments integration feature."> + Credit cards and addresses using Google Payments </message> <message name="IDS_AUTOFILL_FIELD_LABEL_EMAIL" desc="The label of the Email entry."> @@ -14526,40 +14526,40 @@ </message> <!-- Update Menu Item Flags --> - <message name="IDS_FLAGS_UPDATE_MENU_ITEM_NAME" desc="Name of the flag to force show the update menu item."> + <message name="IDS_FLAGS_UPDATE_MENU_ITEM_NAME" desc="Name of the flag to force show the update menu item." translateable="false"> Force show update menu item </message> - <message name="IDS_FLAGS_UPDATE_MENU_ITEM_DESCRIPTION" desc="Description of the flag to force show the update menu item."> + <message name="IDS_FLAGS_UPDATE_MENU_ITEM_DESCRIPTION" desc="Description of the flag to force show the update menu item." translateable="false"> When enabled, an "Update Chrome" item will be shown in the app menu. </message> - <message name="IDS_FLAGS_UPDATE_MENU_ITEM_SUMMARY_NAME" desc="Name of the flag to show a summary below the update menu item."> + <message name="IDS_FLAGS_UPDATE_MENU_ITEM_SUMMARY_NAME" desc="Name of the flag to show a summary below the update menu item." translateable="false"> Update menu item summary </message> - <message name="IDS_FLAGS_UPDATE_MENU_ITEM_SUMMARY_DESCRIPTION" desc="Description of the flag to show a summary below the update menu item."> + <message name="IDS_FLAGS_UPDATE_MENU_ITEM_SUMMARY_DESCRIPTION" desc="Description of the flag to show a summary below the update menu item." translateable="false"> When this flag and the force show update menu item flag are enabled, a summary will be displayed below the update menu item. </message> - <message name="IDS_FLAGS_UPDATE_MENU_ITEM_NO_SUMMARY" desc="Option to not show a summary for the update menu item."> + <message name="IDS_FLAGS_UPDATE_MENU_ITEM_NO_SUMMARY" desc="Option to not show a summary for the update menu item." translateable="false"> No summary </message> - <message name="IDS_FLAGS_UPDATE_MENU_ITEM_DEFAULT_SUMMARY" desc="Option to show the default summary for the update menu item."> + <message name="IDS_FLAGS_UPDATE_MENU_ITEM_DEFAULT_SUMMARY" desc="Option to show the default summary for the update menu item." translateable="false"> Default summary </message> - <message name="IDS_FLAGS_UPDATE_MENU_ITEM_NEW_FEATURES_SUMMARY" desc="Option to show a summary for the update menu item prompting users to 'get the latest features'."> + <message name="IDS_FLAGS_UPDATE_MENU_ITEM_NEW_FEATURES_SUMMARY" desc="Option to show a summary for the update menu item prompting users to 'get the latest features'." translateable="false"> New features summary </message> - <message name="IDS_FLAGS_UPDATE_MENU_ITEM_CUSTOM_SUMMARY" desc="Option to show a custom summary for the update menu item."> + <message name="IDS_FLAGS_UPDATE_MENU_ITEM_CUSTOM_SUMMARY" desc="Option to show a custom summary for the update menu item." translateable="false"> Custom summary </message> - <message name="IDS_FLAGS_UPDATE_MENU_BADGE_NAME" desc="Name of the flag to force show the update menu badge."> + <message name="IDS_FLAGS_UPDATE_MENU_BADGE_NAME" desc="Name of the flag to force show the update menu badge." translateable="false"> Force show update menu badge </message> - <message name="IDS_FLAGS_UPDATE_MENU_BADGE_DESCRIPTION" desc="Description of the flag to force show the update menu badge."> + <message name="IDS_FLAGS_UPDATE_MENU_BADGE_DESCRIPTION" desc="Description of the flag to force show the update menu badge." translateable="false"> When enabled, an update badge will be shown on the app menu button. </message> - <message name="IDS_FLAGS_SET_MARKET_URL_FOR_TESTING_NAME" desc="Name of the flag to set a market URL for testing the update menu item."> + <message name="IDS_FLAGS_SET_MARKET_URL_FOR_TESTING_NAME" desc="Name of the flag to set a market URL for testing the update menu item." translateable="false"> Set market URL for testing </message> - <message name="IDS_FLAGS_SET_MARKET_URL_FOR_TESTING_DESCRIPTION" desc="Description of the flag to set a market URL for testing the update menu item."> + <message name="IDS_FLAGS_SET_MARKET_URL_FOR_TESTING_DESCRIPTION" desc="Description of the flag to set a market URL for testing the update menu item." translateable="false"> When enabled, sets the market URL for use in testing the update menu item. </message> </if>
diff --git a/chrome/browser/android/data_usage/data_use_matcher.cc b/chrome/browser/android/data_usage/data_use_matcher.cc index 8959c64..21e435ca 100644 --- a/chrome/browser/android/data_usage/data_use_matcher.cc +++ b/chrome/browser/android/data_usage/data_use_matcher.cc
@@ -10,9 +10,11 @@ #include <utility> #include "base/memory/weak_ptr.h" +#include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "base/time/default_tick_clock.h" #include "base/time/tick_clock.h" +#include "base/time/time.h" #include "chrome/browser/android/data_usage/external_data_use_observer.h" #include "third_party/re2/src/re2/re2.h" #include "url/gurl.h" @@ -46,6 +48,7 @@ DCHECK_EQ(app_package_names.size(), labels.size()); base::hash_set<std::string> removed_matching_rule_labels; + uint32_t invalid_rules = 0; for (const auto& matching_rule : matching_rules_) removed_matching_rule_labels.insert(matching_rule->label()); @@ -61,11 +64,15 @@ const base::TimeTicks now_ticks = tick_clock_->NowTicks(); ParsePackageField(app_package_names.at(i), &app_package_name, &expiration); - if (url_regex.empty() && app_package_name.empty()) + if (url_regex.empty() && app_package_name.empty()) { + invalid_rules++; continue; + } scoped_ptr<re2::RE2> pattern(new re2::RE2(url_regex, options)); - if (!pattern->ok()) + if (!pattern->ok()) { + invalid_rules++; continue; + } if (expiration <= now_ticks) continue; // skip expired matching rules. @@ -80,6 +87,11 @@ if (data_use_tab_model_) data_use_tab_model_->OnTrackingLabelRemoved(label); } + UMA_HISTOGRAM_COUNTS_100("DataUsage.MatchingRulesCount.Valid", + matching_rules_.size()); + UMA_HISTOGRAM_COUNTS_100("DataUsage.MatchingRulesCount.Invalid", + invalid_rules); + DCHECK(io_task_runner_); // Notify |external_data_use_observer_| if it should register as a data use @@ -101,7 +113,11 @@ for (const auto& matching_rule : matching_rules_) { if (matching_rule->expiration() <= now_ticks) continue; // skip expired matching rules. - if (re2::RE2::FullMatch(url.spec(), *(matching_rule->pattern()))) { + base::TimeTicks begin = base::TimeTicks::Now(); + bool match = re2::RE2::FullMatch(url.spec(), *(matching_rule->pattern())); + UMA_HISTOGRAM_TIMES("DataUsage.Perf.URLRegexMatchDuration", + base::TimeTicks::Now() - begin); + if (match) { *label = matching_rule->label(); return true; }
diff --git a/chrome/browser/android/data_usage/data_use_matcher_unittest.cc b/chrome/browser/android/data_usage/data_use_matcher_unittest.cc index 759a23c..318e519 100644 --- a/chrome/browser/android/data_usage/data_use_matcher_unittest.cc +++ b/chrome/browser/android/data_usage/data_use_matcher_unittest.cc
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" +#include "base/test/histogram_tester.h" #include "base/time/tick_clock.h" #include "base/time/time.h" #include "chrome/browser/android/data_usage/external_data_use_observer.h" @@ -23,6 +24,13 @@ namespace { +const char kUMAMatchingRulesCountValidHistogram[] = + "DataUsage.MatchingRulesCount.Valid"; +const char kUMAMatchingRulesCountInvalidHistogram[] = + "DataUsage.MatchingRulesCount.Invalid"; +const char kUMAURLRegexMatchDurationHistogram[] = + "DataUsage.Perf.URLRegexMatchDuration"; + const char kRegexFoo[] = "http://foo.com/"; const char kLabelFoo[] = "label_foo"; const char kAppFoo[] = "com.example.foo"; @@ -94,39 +102,52 @@ std::string url; std::string regex; bool expect_match; + int expect_count_valid_rules; + int expect_count_url_match_duration_samples; } tests[] = { - {"http://www.google.com", "http://www.google.com/", true}, - {"http://www.Google.com", "http://www.google.com/", true}, - {"http://www.googleacom", "http://www.google.com/", true}, - {"http://www.googleaacom", "http://www.google.com/", false}, - {"http://www.google.com", "https://www.google.com/", false}, + {"http://www.google.com", "http://www.google.com/", true, 1, 1}, + {"http://www.Google.com", "http://www.google.com/", true, 1, 1}, + {"http://www.googleacom", "http://www.google.com/", true, 1, 1}, + {"http://www.googleaacom", "http://www.google.com/", false, 1, 1}, + {"http://www.google.com", "https://www.google.com/", false, 1, 1}, {"http://www.google.com", "{http|https}://www[.]google[.]com/search.*", - false}, + false, 1, 1}, {"https://www.google.com/search=test", - "https://www[.]google[.]com/search.*", true}, + "https://www[.]google[.]com/search.*", true, 1, 1}, {"https://www.googleacom/search=test", - "https://www[.]google[.]com/search.*", false}, + "https://www[.]google[.]com/search.*", false, 1, 1}, {"https://www.google.com/Search=test", - "https://www[.]google[.]com/search.*", true}, - {"www.google.com", "http://www.google.com", false}, - {"www.google.com:80", "http://www.google.com", false}, - {"http://www.google.com:80", "http://www.google.com", false}, - {"http://www.google.com:80/", "http://www.google.com/", true}, - {"", "http://www.google.com", false}, - {"", "", false}, - {"https://www.google.com", "http://www.google.com", false}, + "https://www[.]google[.]com/search.*", true, 1, 1}, + {"www.google.com", "http://www.google.com", false, 1, 0}, + {"www.google.com:80", "http://www.google.com", false, 1, 1}, + {"http://www.google.com:80", "http://www.google.com", false, 1, 1}, + {"http://www.google.com:80/", "http://www.google.com/", true, 1, 1}, + {"", "http://www.google.com", false, 1, 0}, + {"", "", false, 0, 0}, + {"https://www.google.com", "http://www.google.com", false, 1, 1}, + {"https://www.google.com", "[", false, 0}, + {"https://www.google.com", "]", false, 1, 1}, }; for (size_t i = 0; i < arraysize(tests); ++i) { + base::HistogramTester histogram_tester; std::string label(""); RegisterURLRegexes( // App package name not specified in the matching rule. std::vector<std::string>(1, std::string()), std::vector<std::string>(1, tests[i].regex), std::vector<std::string>(1, "label")); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountValidHistogram, + tests[i].expect_count_valid_rules, 1); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountInvalidHistogram, + 1 - tests[i].expect_count_valid_rules, + 1); EXPECT_EQ(tests[i].expect_match, data_use_matcher()->MatchesURL(GURL(tests[i].url), &label)) << i; + histogram_tester.ExpectTotalCount( + kUMAURLRegexMatchDurationHistogram, + tests[i].expect_count_url_match_duration_samples); // Verify label matches the expected label. std::string expected_label = ""; @@ -151,37 +172,40 @@ std::string regex1; std::string regex2; bool expect_match; + int expect_count_valid_rules; + int expect_count_url_match_duration_samples; } tests[] = { {"http://www.google.com", "http://www.google.com/", - "https://www.google.com/", true}, + "https://www.google.com/", true, 1, 1}, {"http://www.googleacom", "http://www.google.com/", - "http://www.google.com/", true}, + "http://www.google.com/", true, 1, 1}, {"https://www.google.com", "http://www.google.com/", - "https://www.google.com/", true}, + "https://www.google.com/", true, 1, 1}, {"https://www.googleacom", "http://www.google.com/", - "https://www.google.com/", true}, + "https://www.google.com/", true, 1, 1}, {"http://www.google.com", "{http|https}://www[.]google[.]com/search.*", - "", false}, + "", false, 1, 1}, {"http://www.google.com/search=test", "http://www[.]google[.]com/search.*", - "https://www[.]google[.]com/search.*", true}, + "https://www[.]google[.]com/search.*", true, 1, 1}, {"https://www.google.com/search=test", "http://www[.]google[.]com/search.*", - "https://www[.]google[.]com/search.*", true}, + "https://www[.]google[.]com/search.*", true, 1, 1}, {"http://google.com/search=test", "http://www[.]google[.]com/search.*", - "https://www[.]google[.]com/search.*", false}, + "https://www[.]google[.]com/search.*", false, 1, 1}, {"https://www.googleacom/search=test", "", - "https://www[.]google[.]com/search.*", false}, + "https://www[.]google[.]com/search.*", false, 1, 1}, {"https://www.google.com/Search=test", "", - "https://www[.]google[.]com/search.*", true}, - {"www.google.com", "http://www.google.com", "", false}, - {"www.google.com:80", "http://www.google.com", "", false}, - {"http://www.google.com:80", "http://www.google.com", "", false}, - {"", "http://www.google.com", "", false}, - {"https://www.google.com", "http://www.google.com", "", false}, + "https://www[.]google[.]com/search.*", true, 1, 1}, + {"www.google.com", "http://www.google.com", "", false, 1, 0}, + {"www.google.com:80", "http://www.google.com", "", false, 1, 1}, + {"http://www.google.com:80", "http://www.google.com", "", false, 1, 1}, + {"", "http://www.google.com", "", false, 1, 0}, + {"https://www.google.com", "http://www.google.com", "", false, 1, 1}, }; for (size_t i = 0; i < arraysize(tests); ++i) { + base::HistogramTester histogram_tester; std::string got_label(""); std::vector<std::string> url_regexes; url_regexes.push_back(tests[i].regex1 + "|" + tests[i].regex2); @@ -189,9 +213,20 @@ RegisterURLRegexes( std::vector<std::string>(url_regexes.size(), "com.example.helloworld"), url_regexes, std::vector<std::string>(url_regexes.size(), label)); + histogram_tester.ExpectTotalCount(kUMAMatchingRulesCountValidHistogram, 1); + histogram_tester.ExpectTotalCount(kUMAMatchingRulesCountInvalidHistogram, + 1); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountValidHistogram, + tests[i].expect_count_valid_rules, 1); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountInvalidHistogram, + 1 - tests[i].expect_count_valid_rules, + 1); EXPECT_EQ(tests[i].expect_match, data_use_matcher()->MatchesURL(GURL(tests[i].url), &got_label)) << i; + histogram_tester.ExpectTotalCount( + kUMAURLRegexMatchDurationHistogram, + tests[i].expect_count_url_match_duration_samples); const std::string expected_label = tests[i].expect_match ? label : std::string(); EXPECT_EQ(expected_label, got_label); @@ -204,6 +239,7 @@ } TEST_F(DataUseMatcherTest, MultipleRegex) { + base::HistogramTester histogram_tester; std::vector<std::string> url_regexes; url_regexes.push_back( "https?://www[.]google[.]com/#q=.*|https?://www[.]google[.]com[.]ph/" @@ -211,6 +247,10 @@ RegisterURLRegexes( std::vector<std::string>(url_regexes.size(), std::string()), url_regexes, std::vector<std::string>(url_regexes.size(), "label")); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountValidHistogram, 1, + 1); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountInvalidHistogram, 0, + 1); const struct { std::string url; @@ -285,6 +325,7 @@ } TEST_F(DataUseMatcherTest, MultipleAppPackageName) { + base::HistogramTester histogram_tester; std::vector<std::string> url_regexes; url_regexes.push_back( "http://www[.]foo[.]com/#q=.*|https://www[.]foo[.]com/#q=.*"); @@ -307,6 +348,10 @@ app_package_names.push_back(kAppBaz); RegisterURLRegexes(app_package_names, url_regexes, labels); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountValidHistogram, 3, + 1); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountInvalidHistogram, 0, + 1); // Test if labels are matched properly for app package names. std::string got_label; @@ -387,6 +432,7 @@ // Tests if the expiration time encoded as milliseconds since epoch is parsed // correctly. TEST_F(DataUseMatcherTest, EncodeExpirationTimeInPackageName) { + base::HistogramTester histogram_tester; NowTestTickClock* tick_clock = new NowTestTickClock(); // |tick_clock| will be owned by |data_use_matcher_|. @@ -396,12 +442,16 @@ url_regexes.push_back(kRegexFoo); labels.push_back(kLabelFoo); - // Set current time to to Epoch. + // Set current time to Epoch. tick_clock->set_now_ticks(base::TimeTicks::UnixEpoch()); app_package_names.push_back(base::StringPrintf("%s|%d", kAppFoo, 10000)); RegisterURLRegexes(app_package_names, url_regexes, labels); EXPECT_FALSE(IsExpired(0)); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountValidHistogram, 1, + 1); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountInvalidHistogram, 0, + 1); // Fast forward 10 seconds, and matching rule expires. tick_clock->set_now_ticks(base::TimeTicks::UnixEpoch() + base::TimeDelta::FromMilliseconds(10000 + 1)); @@ -420,6 +470,7 @@ // Tests if the expiration time encoded in Java format is parsed correctly. TEST_F(DataUseMatcherTest, EncodeJavaExpirationTimeInPackageName) { + base::HistogramTester histogram_tester; std::vector<std::string> url_regexes, labels, app_package_names; url_regexes.push_back(kRegexFoo); labels.push_back(kLabelFoo); @@ -433,6 +484,10 @@ static_cast<long long int>(expiration_time.ToJavaTime()))); RegisterURLRegexes(app_package_names, url_regexes, labels); EXPECT_FALSE(IsExpired(0)); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountValidHistogram, 1, + 1); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountInvalidHistogram, 0, + 1); // Check if expiration duration is close to 10 seconds. EXPECT_GE(base::TimeDelta::FromMilliseconds(10001), @@ -445,6 +500,7 @@ // Tests that expired matching rules are ignored by MatchesURL and // MatchesAppPackageName. TEST_F(DataUseMatcherTest, MatchesIgnoresExpiredRules) { + base::HistogramTester histogram_tester; std::vector<std::string> url_regexes, labels, app_package_names; std::string got_label; NowTestTickClock* tick_clock = new NowTestTickClock(); @@ -457,6 +513,10 @@ labels.push_back(kLabelFoo); app_package_names.push_back(base::StringPrintf("%s|%d", kAppFoo, 10000)); RegisterURLRegexes(app_package_names, url_regexes, labels); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountValidHistogram, 1, + 1); + histogram_tester.ExpectUniqueSample(kUMAMatchingRulesCountInvalidHistogram, 0, + 1); tick_clock->set_now_ticks(base::TimeTicks::UnixEpoch() + base::TimeDelta::FromMilliseconds(1));
diff --git a/chrome/browser/android/data_usage/external_data_use_observer.cc b/chrome/browser/android/data_usage/external_data_use_observer.cc index 94e9e06..a1dba79 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer.cc +++ b/chrome/browser/android/data_usage/external_data_use_observer.cc
@@ -205,6 +205,9 @@ RecordDataUsageReportSubmission(DATAUSAGE_REPORT_SUBMISSION_FAILED, pending_report_bytes_); } + UMA_HISTOGRAM_TIMES( + "DataUsage.Perf.ReportSubmissionDuration", + base::TimeTicks::Now() - last_data_report_submitted_ticks_); last_data_report_submitted_ticks_ = base::TimeTicks(); pending_report_bytes_ = 0;
diff --git a/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc b/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc index 71ad96c..57cffd38 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc +++ b/chrome/browser/android/data_usage/external_data_use_observer_bridge.cc
@@ -10,6 +10,7 @@ #include "base/android/jni_string.h" #include "base/memory/scoped_ptr.h" #include "base/metrics/field_trial.h" +#include "base/metrics/histogram_macros.h" #include "base/single_thread_task_runner.h" #include "base/time/time.h" #include "chrome/browser/android/data_usage/data_use_tab_model.h" @@ -36,7 +37,9 @@ namespace android { -ExternalDataUseObserverBridge::ExternalDataUseObserverBridge() { +ExternalDataUseObserverBridge::ExternalDataUseObserverBridge() + : construct_time_(base::TimeTicks::Now()), + is_first_matching_rule_fetch_(true) { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); // Detach from IO thread since rest of ExternalDataUseObserverBridge lives on @@ -96,6 +99,7 @@ const base::android::JavaParamRef<jobjectArray>& domain_path_regex, const base::android::JavaParamRef<jobjectArray>& label) { DCHECK(thread_checker_.CalledOnValidThread()); + DCHECK(!construct_time_.is_null()); // Convert to native objects. std::vector<std::string> app_package_name_native; @@ -117,6 +121,12 @@ if (!data_use_tab_model_) return; + if (is_first_matching_rule_fetch_) { + is_first_matching_rule_fetch_ = false; + UMA_HISTOGRAM_TIMES("DataUsage.Perf.MatchingRuleFirstFetchDuration", + base::TimeTicks::Now() - construct_time_); + } + data_use_tab_model_->RegisterURLRegexes( app_package_name_native, domain_path_regex_native, label_native); }
diff --git a/chrome/browser/android/data_usage/external_data_use_observer_bridge.h b/chrome/browser/android/data_usage/external_data_use_observer_bridge.h index 2727c407..4925870 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer_bridge.h +++ b/chrome/browser/android/data_usage/external_data_use_observer_bridge.h
@@ -21,6 +21,7 @@ namespace base { class SingleThreadTaskRunner; class Time; +class TimeTicks; } namespace chrome { @@ -101,6 +102,12 @@ // |data_use_tab_model_| is notified of the matching rules on UI thread. base::WeakPtr<DataUseTabModel> data_use_tab_model_; + // The construction time of |this|. + const base::TimeTicks construct_time_; + + // True if matching rules are fetched for the first time. + bool is_first_matching_rule_fetch_; + // |io_task_runner_| accesses ExternalDataUseObserver members on IO thread. scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
diff --git a/chrome/browser/android/data_usage/external_data_use_observer_unittest.cc b/chrome/browser/android/data_usage/external_data_use_observer_unittest.cc index f13fb58f..8b9205ef 100644 --- a/chrome/browser/android/data_usage/external_data_use_observer_unittest.cc +++ b/chrome/browser/android/data_usage/external_data_use_observer_unittest.cc
@@ -33,6 +33,11 @@ namespace { +const char kUMAMatchingRuleFirstFetchDurationHistogram[] = + "DataUsage.Perf.MatchingRuleFirstFetchDuration"; +const char kUMAReportSubmissionDurationHistogram[] = + "DataUsage.Perf.ReportSubmissionDuration"; + const char kDefaultLabel[] = "label"; const SessionID::id_type kDefaultTabId = 0; const char kDefaultURL[] = "http://www.google.com/#q=abc"; @@ -467,6 +472,7 @@ histogram_tester.ExpectUniqueSample( "DataUsage.ReportSubmission.Bytes.Successful", external_data_use_observer()->data_use_report_min_bytes_, 1); + histogram_tester.ExpectTotalCount(kUMAReportSubmissionDurationHistogram, 1); // Verify that metrics were updated correctly for the report that was not // successfully submitted. @@ -479,6 +485,7 @@ histogram_tester.ExpectUniqueSample( "DataUsage.ReportSubmission.Bytes.Failed", external_data_use_observer()->data_use_report_min_bytes_, 1); + histogram_tester.ExpectTotalCount(kUMAReportSubmissionDurationHistogram, 2); } #if defined(OS_ANDROID) @@ -486,6 +493,7 @@ // Report should be submitted even if the number of bytes is less than the // threshold. Report should not be submitted if there is a pending report. TEST_F(ExternalDataUseObserverTest, DataUseReportingOnApplicationStatusChange) { + base::HistogramTester histogram_tester; AddDefaultMatchingRule(); TriggerTabTrackingOnDefaultTab(); @@ -507,6 +515,7 @@ EXPECT_EQ(0, external_data_use_observer()->total_bytes_buffered_); EXPECT_EQ(2, external_data_use_observer()->pending_report_bytes_); external_data_use_observer()->OnReportDataUseDone(true); + histogram_tester.ExpectTotalCount(kUMAReportSubmissionDurationHistogram, 1); // Create pending report. OnDataUse(default_data_use()); @@ -527,6 +536,7 @@ EXPECT_EQ(2, external_data_use_observer()->total_bytes_buffered_); EXPECT_EQ(default_upload_bytes() + default_download_bytes(), external_data_use_observer()->pending_report_bytes_); + histogram_tester.ExpectTotalCount(kUMAReportSubmissionDurationHistogram, 1); // Once pending report submission done callback was received, report should be // submitted on next application state change. @@ -535,6 +545,7 @@ base::android::APPLICATION_STATE_HAS_PAUSED_ACTIVITIES); EXPECT_EQ(0, external_data_use_observer()->total_bytes_buffered_); EXPECT_EQ(2, external_data_use_observer()->pending_report_bytes_); + histogram_tester.ExpectTotalCount(kUMAReportSubmissionDurationHistogram, 2); } #endif // OS_ANDROID @@ -565,15 +576,18 @@ // Tests if the metrics are recorded correctly. TEST_F(ExternalDataUseObserverTest, DataUseReportTimedOut) { + base::HistogramTester histogram_tester; std::map<std::string, std::string> variation_params; variation_params["data_report_submit_timeout_msec"] = "0"; variation_params["data_use_report_min_bytes"] = "0"; // Create another ExternalDataUseObserver object. ReplaceExternalDataUseObserver(variation_params); + histogram_tester.ExpectTotalCount(kUMAMatchingRuleFirstFetchDurationHistogram, + 1); + AddDefaultMatchingRule(); - base::HistogramTester histogram_tester; TriggerTabTrackingOnDefaultTab(); OnDataUse(default_data_use()); OnDataUse(default_data_use()); @@ -584,6 +598,7 @@ histogram_tester.ExpectUniqueSample( "DataUsage.ReportSubmission.Bytes.TimedOut", default_upload_bytes() + default_download_bytes(), 1); + histogram_tester.ExpectTotalCount(kUMAReportSubmissionDurationHistogram, 0); } } // namespace android
diff --git a/chrome/browser/chromeos/extensions/wallpaper_api.cc b/chrome/browser/chromeos/extensions/wallpaper_api.cc index 64be4aa..399b846 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_api.cc +++ b/chrome/browser/chromeos/extensions/wallpaper_api.cc
@@ -153,42 +153,31 @@ user_manager::User::CUSTOMIZED, image, update_wallpaper); unsafe_wallpaper_decoder_ = NULL; - if (params_->details.thumbnail) { - image.EnsureRepsForSupportedScales(); - scoped_ptr<gfx::ImageSkia> deep_copy(image.DeepCopy()); - // Generates thumbnail before call api function callback. We can then - // request thumbnail in the javascript callback. - task_runner->PostTask( - FROM_HERE, - base::Bind(&WallpaperSetWallpaperFunction::GenerateThumbnail, this, - thumbnail_path, base::Passed(std::move(deep_copy)))); + // Save current extenion name. It will be displayed in the component + // wallpaper picker app. If current extension is the component wallpaper + // picker, set an empty string. + Profile* profile = Profile::FromBrowserContext(browser_context()); + if (extension()->id() == extension_misc::kWallpaperManagerId) { + profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName, + std::string()); } else { - // Save current extenion name. It will be displayed in the component - // wallpaper picker app. If current extension is the component wallpaper - // picker, set an empty string. - Profile* profile = Profile::FromBrowserContext(browser_context()); - if (extension()->id() == extension_misc::kWallpaperManagerId) { - profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName, - std::string()); - } else { - profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName, - extension()->name()); - } - SendResponse(true); + profile->GetPrefs()->SetString(prefs::kCurrentWallpaperAppName, + extension()->name()); } - // Inform the native Wallpaper Picker Application that the current wallpaper - // has been modified by a third party application. - Profile* profile = Profile::FromBrowserContext(browser_context()); - extensions::EventRouter* event_router = extensions::EventRouter::Get(profile); - scoped_ptr<base::ListValue> event_args(new base::ListValue()); - scoped_ptr<extensions::Event> event(new extensions::Event( - extensions::events::WALLPAPER_PRIVATE_ON_WALLPAPER_CHANGED_BY_3RD_PARTY, - extensions::api::wallpaper_private::OnWallpaperChangedBy3rdParty:: - kEventName, - std::move(event_args))); - event_router->DispatchEventToExtension(extension_misc::kWallpaperManagerId, - std::move(event)); + if (!params_->details.thumbnail) + SendResponse(true); + + // We need to generate thumbnail image anyway to make the current third party + // wallpaper syncable through different devices. + image.EnsureRepsForSupportedScales(); + scoped_ptr<gfx::ImageSkia> deep_copy(image.DeepCopy()); + // Generates thumbnail before call api function callback. We can then + // request thumbnail in the javascript callback. + task_runner->PostTask( + FROM_HERE, + base::Bind(&WallpaperSetWallpaperFunction::GenerateThumbnail, this, + thumbnail_path, base::Passed(std::move(deep_copy)))); } void WallpaperSetWallpaperFunction::GenerateThumbnail( @@ -198,24 +187,52 @@ if (!base::PathExists(thumbnail_path.DirName())) base::CreateDirectory(thumbnail_path.DirName()); - scoped_refptr<base::RefCountedBytes> data; + scoped_refptr<base::RefCountedBytes> original_data; + scoped_refptr<base::RefCountedBytes> thumbnail_data; + chromeos::WallpaperManager::Get()->ResizeImage( + *image, wallpaper::WALLPAPER_LAYOUT_STRETCH, image->width(), + image->height(), &original_data, NULL); chromeos::WallpaperManager::Get()->ResizeImage( *image, wallpaper::WALLPAPER_LAYOUT_STRETCH, wallpaper::kWallpaperThumbnailWidth, wallpaper::kWallpaperThumbnailHeight, - &data, NULL); + &thumbnail_data, NULL); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind( - &WallpaperSetWallpaperFunction::ThumbnailGenerated, - this, data)); + base::Bind(&WallpaperSetWallpaperFunction::ThumbnailGenerated, this, + original_data, thumbnail_data)); } void WallpaperSetWallpaperFunction::ThumbnailGenerated( - base::RefCountedBytes* data) { - BinaryValue* result = BinaryValue::CreateWithCopiedBuffer( - reinterpret_cast<const char*>(data->front()), data->size()); - SetResult(result); - SendResponse(true); + base::RefCountedBytes* original_data, + base::RefCountedBytes* thumbnail_data) { + BinaryValue* original_result = BinaryValue::CreateWithCopiedBuffer( + reinterpret_cast<const char*>(original_data->front()), + original_data->size()); + BinaryValue* thumbnail_result = BinaryValue::CreateWithCopiedBuffer( + reinterpret_cast<const char*>(thumbnail_data->front()), + thumbnail_data->size()); + + if (params_->details.thumbnail) { + SetResult(thumbnail_result); + SendResponse(true); + } + + // Inform the native Wallpaper Picker Application that the current wallpaper + // has been modified by a third party application. + Profile* profile = Profile::FromBrowserContext(browser_context()); + extensions::EventRouter* event_router = extensions::EventRouter::Get(profile); + scoped_ptr<base::ListValue> event_args(new base::ListValue()); + event_args->Append(original_result); + event_args->Append(thumbnail_result); + event_args->Append(new base::StringValue( + extensions::api::wallpaper::ToString(params_->details.layout))); + scoped_ptr<extensions::Event> event(new extensions::Event( + extensions::events::WALLPAPER_PRIVATE_ON_WALLPAPER_CHANGED_BY_3RD_PARTY, + extensions::api::wallpaper_private::OnWallpaperChangedBy3rdParty:: + kEventName, + std::move(event_args))); + event_router->DispatchEventToExtension(extension_misc::kWallpaperManagerId, + std::move(event)); } void WallpaperSetWallpaperFunction::OnWallpaperFetched(
diff --git a/chrome/browser/chromeos/extensions/wallpaper_api.h b/chrome/browser/chromeos/extensions/wallpaper_api.h index e1d2517..cd2420c 100644 --- a/chrome/browser/chromeos/extensions/wallpaper_api.h +++ b/chrome/browser/chromeos/extensions/wallpaper_api.h
@@ -41,7 +41,8 @@ scoped_ptr<gfx::ImageSkia> image); // Thumbnail is ready. Calls api function javascript callback. - void ThumbnailGenerated(base::RefCountedBytes* data); + void ThumbnailGenerated(base::RefCountedBytes* original_data, + base::RefCountedBytes* thumbnail_data); // Called by OnURLFetchComplete(). void OnWallpaperFetched(bool success, const std::string& response);
diff --git a/chrome/browser/component_updater/widevine_cdm_component_installer.cc b/chrome/browser/component_updater/widevine_cdm_component_installer.cc index bd5172f..a6df16c 100644 --- a/chrome/browser/component_updater/widevine_cdm_component_installer.cc +++ b/chrome/browser/component_updater/widevine_cdm_component_installer.cc
@@ -8,6 +8,7 @@ #include <stdint.h> #include <string.h> #include <string> +#include <utility> #include <vector> #include "base/base_paths.h" @@ -373,7 +374,7 @@ new WidevineCdmComponentInstallerTraits); // |cus| will take ownership of |installer| during installer->Register(cus). DefaultComponentInstaller* installer = - new DefaultComponentInstaller(traits.Pass()); + new DefaultComponentInstaller(std::move(traits)); installer->Register(cus, base::Closure()); #endif // defined(WIDEVINE_CDM_AVAILABLE) && defined(WIDEVINE_CDM_IS_COMPONENT) }
diff --git a/chrome/browser/extensions/api/messaging/extension_message_port.cc b/chrome/browser/extensions/api/messaging/extension_message_port.cc index 72acfee..aba3048 100644 --- a/chrome/browser/extensions/api/messaging/extension_message_port.cc +++ b/chrome/browser/extensions/api/messaging/extension_message_port.cc
@@ -45,6 +45,12 @@ port_->UnregisterFrame(render_frame_host); } + // TODO(robwu): This should be superfluous with RenderFrameDeleted above, but + // we are not entirely sure. + void FrameDeleted(content::RenderFrameHost* render_frame_host) override { + port_->UnregisterFrame(render_frame_host); + } + void DidNavigateAnyFrame(content::RenderFrameHost* render_frame_host, const content::LoadCommittedDetails& details, const content::FrameNavigateParams&) override { @@ -102,7 +108,7 @@ background_host_ptr_(nullptr), frame_tracker_(new FrameTracker(this)) { content::WebContents* tab = content::WebContents::FromRenderFrameHost(rfh); - DCHECK(tab); + CHECK(tab); frame_tracker_->TrackTabFrames(tab); if (include_child_frames) { tab->ForEachFrame(base::Bind(&ExtensionMessagePort::RegisterFrame,
diff --git a/chrome/browser/extensions/extension_service.cc b/chrome/browser/extensions/extension_service.cc index 89d5dec..4a4b216b 100644 --- a/chrome/browser/extensions/extension_service.cc +++ b/chrome/browser/extensions/extension_service.cc
@@ -379,8 +379,6 @@ extensions::ExtensionManagementFactory::GetInstance() ->GetForBrowserContext(profile()) ->RemoveObserver(this); - system_->management_policy()->UnregisterProvider( - shared_module_policy_provider_.get()); } const Extension* ExtensionService::GetExtensionById(
diff --git a/chrome/browser/extensions/extension_service.h b/chrome/browser/extensions/extension_service.h index 740c755..01fea8ec 100644 --- a/chrome/browser/extensions/extension_service.h +++ b/chrome/browser/extensions/extension_service.h
@@ -25,7 +25,6 @@ #include "extensions/browser/crx_file_info.h" #include "extensions/browser/external_provider_interface.h" #include "extensions/browser/install_flag.h" -#include "extensions/browser/management_policy.h" #include "extensions/browser/process_manager.h" #include "extensions/browser/uninstall_reason.h" #include "extensions/common/extension.h" @@ -726,8 +725,6 @@ scoped_ptr<extensions::ExtensionActionStorageManager> extension_action_storage_manager_; - scoped_ptr<extensions::ManagementPolicy::Provider> - shared_module_policy_provider_; // The SharedModuleService used to check for import dependencies. scoped_ptr<extensions::SharedModuleService> shared_module_service_;
diff --git a/chrome/browser/net/async_dns_field_trial.cc b/chrome/browser/net/async_dns_field_trial.cc index b8ce85fd..3013ef9 100644 --- a/chrome/browser/net/async_dns_field_trial.cc +++ b/chrome/browser/net/async_dns_field_trial.cc
@@ -61,7 +61,7 @@ } // namespace bool ConfigureAsyncDnsFieldTrial() { -#if defined(OS_ANDROID) || defined(OS_IOS) +#if defined(OS_IOS) // There is no DnsConfigService on those platforms so disable the field trial. HistogramPrefDefaultSource(PLATFORM, false); return false;
diff --git a/chrome/browser/permissions/permission_uma_util.cc b/chrome/browser/permissions/permission_uma_util.cc index f155a19..439ca44 100644 --- a/chrome/browser/permissions/permission_uma_util.cc +++ b/chrome/browser/permissions/permission_uma_util.cc
@@ -69,6 +69,9 @@ case IGNORED: action_str = "Ignored"; break; + case REVOKED: + action_str = "Revoked"; + break; default: NOTREACHED(); break; @@ -299,3 +302,15 @@ const GURL& requesting_origin) { RecordPermissionAction(permission, IGNORED, requesting_origin); } + +void PermissionUmaUtil::PermissionRevoked(PermissionType permission, + const GURL& revoked_origin) { + // TODO(tsergeant): Expand metrics definitions for revocation to include all + // permissions. + if (permission == PermissionType::NOTIFICATIONS || + permission == PermissionType::GEOLOCATION || + permission == PermissionType::AUDIO_CAPTURE || + permission == PermissionType::VIDEO_CAPTURE) { + RecordPermissionAction(permission, REVOKED, revoked_origin); + } +}
diff --git a/chrome/browser/permissions/permission_uma_util.h b/chrome/browser/permissions/permission_uma_util.h index 254f3c1..deee1d7 100644 --- a/chrome/browser/permissions/permission_uma_util.h +++ b/chrome/browser/permissions/permission_uma_util.h
@@ -30,6 +30,8 @@ const GURL& requesting_origin); static void PermissionIgnored(content::PermissionType permission, const GURL& requesting_origin); + static void PermissionRevoked(content::PermissionType permission, + const GURL& revoked_origin); private: DISALLOW_IMPLICIT_CONSTRUCTORS(PermissionUmaUtil);
diff --git a/chrome/browser/permissions/permission_util.cc b/chrome/browser/permissions/permission_util.cc index 4daa4ba5..12fb7bb 100644 --- a/chrome/browser/permissions/permission_util.cc +++ b/chrome/browser/permissions/permission_util.cc
@@ -39,3 +39,29 @@ NOTREACHED(); return std::string(); } + +bool PermissionUtil::GetPermissionType(ContentSettingsType type, + PermissionType* out) { + if (type == CONTENT_SETTINGS_TYPE_GEOLOCATION) { + *out = PermissionType::GEOLOCATION; + } else if (type == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { + *out = PermissionType::NOTIFICATIONS; + } else if (type == CONTENT_SETTINGS_TYPE_MIDI_SYSEX) { + *out = PermissionType::MIDI_SYSEX; + } else if (type == CONTENT_SETTINGS_TYPE_PUSH_MESSAGING) { + *out = PermissionType::PUSH_MESSAGING; + } else if (type == CONTENT_SETTINGS_TYPE_DURABLE_STORAGE) { + *out = PermissionType::DURABLE_STORAGE; + } else if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) { + *out = PermissionType::VIDEO_CAPTURE; + } else if (type == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) { + *out = PermissionType::AUDIO_CAPTURE; +#if defined(OS_ANDROID) || defined(OS_CHROMEOS) + } else if (type == CONTENT_SETTINGS_TYPE_PROTECTED_MEDIA_IDENTIFIER) { + *out = PermissionType::PROTECTED_MEDIA_IDENTIFIER; +#endif + } else { + return false; + } + return true; +}
diff --git a/chrome/browser/permissions/permission_util.h b/chrome/browser/permissions/permission_util.h index be19b5a5..eb0e066 100644 --- a/chrome/browser/permissions/permission_util.h +++ b/chrome/browser/permissions/permission_util.h
@@ -8,6 +8,7 @@ #include <string> #include "base/macros.h" +#include "components/content_settings/core/common/content_settings_types.h" namespace content { enum class PermissionType; @@ -19,6 +20,15 @@ // Returns the permission string for the given PermissionType. static std::string GetPermissionString(content::PermissionType permission); + // Limited conversion of ContentSettingsType to PermissionType. Intended for + // recording Permission UMA metrics from areas of the codebase which have not + // yet been converted to PermissionType. Returns true if the conversion was + // performed. + // TODO(tsergeant): Remove this function once callsites operate on + // PermissionType directly. + static bool GetPermissionType(ContentSettingsType type, + content::PermissionType* out); + private: DISALLOW_IMPLICIT_CONSTRUCTORS(PermissionUtil); };
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox.gyp b/chrome/browser/resources/chromeos/chromevox/chromevox.gyp index 9cdc4f5f..5406faf0 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox.gyp +++ b/chrome/browser/resources/chromeos/chromevox/chromevox.gyp
@@ -44,10 +44,11 @@ }], ['chromevox_compress_js==1', { 'dependencies': [ + 'chromevox_background_script', 'chromevox_content_script', 'chromevox_kbexplorer_script', + 'chromevox_min_content_script', 'chromevox_options_script', - 'chromevox_background_script', 'chromevox_panel_script', ], }, { # chromevox_compress_js==0 @@ -212,6 +213,15 @@ 'sources': [ '<(chromevox_panel_script_loader_file)' ], 'includes': [ 'compress_js.gypi', ], }, + { + 'target_name': 'chromevox_min_content_script', + 'type': 'none', + 'variables': { + 'output_file': '<(chromevox_dest_dir)/chromeVox2ChromePageScript.js', + }, + 'sources': [ '<(chromevox_min_content_script_loader_file)' ], + 'includes': [ 'compress_js.gypi', ], + }, ], }, { # chromevox_compress_js==0 'targets': [
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json b/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json index 3f885ccd..8d0628c 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json +++ b/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json
@@ -197,7 +197,7 @@ "sequence": { "cvoxModifier": true, "keys": { - "keyCode": [67] + "keyCode": [76] } } },
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/init_document.js b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/init_document.js index 45e8716..e22cfc8 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox/injected/init_document.js +++ b/chrome/browser/resources/chromeos/chromevox/chromevox/injected/init_document.js
@@ -45,13 +45,11 @@ /** * Flag indicating if ChromeVox Classic is enabled based on the Next - * background page. Initializes to true for non-top level - * (i.e. iframes) windows. For top level windows, left undefined and - * set when background page replies. + * background page which sends the state at page load. * @type {boolean|undefined} * @private */ -cvox.ChromeVox.isClassicEnabled_ = window.top == window ? undefined : true; +cvox.ChromeVox.isClassicEnabled_ = undefined; /**
diff --git a/chrome/browser/resources/chromeos/chromevox/chromevox_vars.gypi b/chrome/browser/resources/chromeos/chromevox/chromevox_vars.gypi index 59dfde51..c38d599f 100644 --- a/chrome/browser/resources/chromeos/chromevox/chromevox_vars.gypi +++ b/chrome/browser/resources/chromeos/chromevox/chromevox_vars.gypi
@@ -6,11 +6,12 @@ { 'variables': { - 'chromevox_content_script_loader_file': 'chromevox/injected/loader.js', - 'chromevox_kbexplorer_loader_file': 'chromevox/background/kbexplorer_loader.js', - 'chromevox_options_script_loader_file': 'chromevox/background/options_loader.js', 'chromevox_background_script_loader_file': 'cvox2/background/loader.js', - 'chromevox_panel_script_loader_file': 'cvox2/background/panel_loader.js', + 'chromevox_content_script_loader_file': 'chromevox/injected/loader.js', 'chromevox_extension_key': 'MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDltVl1k15pjRzuZfMc3B69inxwm2bZeZ2O8/zFO+NluHnBm3GJ3fzdOoFGJd+M16I8p7zxxQyHeDMfWYASyCeB8XnUEDKjqNLQfCnncsANzHsYoEbYj2nEUML2P13b9q+AAvpCBpAJ4cZp81e9n1y/vbSXHE4385cgkKueItzikQIDAQAB', - } + 'chromevox_kbexplorer_loader_file': 'chromevox/background/kbexplorer_loader.js', + 'chromevox_min_content_script_loader_file': 'cvox2/injected/loader.js', + 'chromevox_options_script_loader_file': 'chromevox/background/options_loader.js', + 'chromevox_panel_script_loader_file': 'cvox2/background/panel_loader.js', + } }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js index 11f093d..281f5b9 100644 --- a/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/background/background.js
@@ -657,6 +657,10 @@ target: 'next', isClassicEnabled: isClassicEnabled }); + } else if (action == 'onCommand') { + this.onGotCommand(msg['command']); + } else if (action == 'flushNextUtterance') { + Output.flushNextSpeechUtterance(); } break; }
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/injected/keyboard_handler.js b/chrome/browser/resources/chromeos/chromevox/cvox2/injected/keyboard_handler.js new file mode 100644 index 0000000..5b64017 --- /dev/null +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/injected/keyboard_handler.js
@@ -0,0 +1,47 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview A minimal keyboard handler. + */ + +goog.provide('KeyboardHandler'); + +// Implicit dependency on cvox.ChromeVoxKbHandler; cannot include here because +// ChromeVoxKbHandler redefines members. + +/** + * @constructor + */ +KeyboardHandler = function() { + cvox.ChromeVoxKbHandler.commandHandler = this.handleCommand_.bind(this); + cvox.ChromeVoxKbHandler.handlerKeyMap = cvox.KeyMap.fromNext(); + document.addEventListener('keydown', this.handleKeyDown_.bind(this), false); +}; + +KeyboardHandler.prototype = { + /** + * @param {Event} evt + * @private + */ + handleKeyDown_: function(evt) { + cvox.ExtensionBridge.send({ + 'target': 'next', + 'action': 'flushNextUtterance' + }); + cvox.ChromeVoxKbHandler.basicKeyDownActionsListener(evt); + }, + + /** + * @param {string} command + * @private + */ + handleCommand_: function(command) { + cvox.ExtensionBridge.send({ + 'target': 'next', + 'action': 'onCommand', + 'command': command + }); + } +};
diff --git a/chrome/browser/resources/chromeos/chromevox/cvox2/injected/loader.js b/chrome/browser/resources/chromeos/chromevox/cvox2/injected/loader.js new file mode 100644 index 0000000..0797cb80 --- /dev/null +++ b/chrome/browser/resources/chromeos/chromevox/cvox2/injected/loader.js
@@ -0,0 +1,27 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +goog.require('KeyboardHandler'); + +/** + * Initializes minimal content script. + */ +function initMin() { + if (cvox.ChromeVox.isChromeOS) + return; + + if (cvox.ChromeVox.isClassicEnabled_ === undefined) { + window.setTimeout(function() { + initMin(); + }, 500); + return; + } + + if (cvox.ChromeVox.isClassicEnabled_) + return; + + new KeyboardHandler(); +} + +initMin();
diff --git a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 index 6cf146e8..ffb8734 100644 --- a/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2 +++ b/chrome/browser/resources/chromeos/chromevox/manifest.json.jinja2
@@ -40,7 +40,8 @@ "all_frames": true, "js": [ {% if is_js_compressed == '1' %} - "chromeVoxChromePageScript.js" + "chromeVoxChromePageScript.js", + "chromeVox2ChromePageScript.js" {% else %} "closure/closure_preinit.js", "closure/base.js", @@ -51,6 +52,7 @@ } ], "web_accessible_resources": [ + "chromevox/background/keymaps/next_keymap.json", "chromevox/injected/api.js", "chromevox/injected/api_util.js", "chromevox/injected/mathjax.js",
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js index 8001c16..3e1f728 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/constants.js
@@ -91,5 +91,10 @@ WallpaperDirNameEnum: { ORIGINAL: 'original', THUMBNAIL: 'thumbnail' - } + }, + + /** + * The filename prefix for a third party wallpaper. + */ + ThirdPartyWallpaperPrefix: 'third_party_' };
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js index eba94a34..4a5a310 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/event_page.js
@@ -320,6 +320,16 @@ } } + if (changes[Constants.AccessLocalWallpaperInfoKey]) { + // If the old wallpaper is a third party wallpaper we should remove it + // from the local & sync file system to free space. + var oldInfo = changes[Constants.AccessLocalWallpaperInfoKey].oldValue; + if (oldInfo.url.indexOf(Constants.ThirdPartyWallpaperPrefix) != -1) { + WallpaperUtil.deleteWallpaperFromLocalFS(oldInfo.url); + WallpaperUtil.deleteWallpaperFromSyncFS(oldInfo.url); + } + } + if (changes[Constants.AccessSyncWallpaperInfoKey]) { var syncInfo = changes[Constants.AccessSyncWallpaperInfoKey].newValue; @@ -368,6 +378,15 @@ Constants.WallpaperSourceEnum.Default) { chrome.wallpaperPrivate.resetWallpaper(); } + + // If the old wallpaper is a third party wallpaper we should + // remove it from the local & sync file system to free space. + if (localInfo && localInfo.url.indexOf( + Constants.ThirdPartyWallpaperPrefix) != -1) { + WallpaperUtil.deleteWallpaperFromLocalFS(localInfo.url); + WallpaperUtil.deleteWallpaperFromSyncFS(localInfo.url); + } + WallpaperUtil.saveToLocalStorage( Constants.AccessLocalWallpaperInfoKey, syncInfo); } @@ -394,11 +413,21 @@ SurpriseWallpaper.getInstance().next(); }); -chrome.wallpaperPrivate.onWallpaperChangedBy3rdParty.addListener(function() { +chrome.wallpaperPrivate.onWallpaperChangedBy3rdParty.addListener(function( + wallpaper, thumbnail, layout) { WallpaperUtil.saveToLocalStorage( Constants.AccessLocalSurpriseMeEnabledKey, false, function() { WallpaperUtil.saveToSyncStorage(Constants.AccessSyncSurpriseMeEnabledKey, false); }); SurpriseWallpaper.getInstance().disable(); + + // Make third party wallpaper syncable through different devices. + // TODO(xdai): also sync the third party app name. + var filename = Constants.ThirdPartyWallpaperPrefix + new Date().getTime(); + var thumbnailFilename = filename + Constants.CustomWallpaperThumbnailSuffix; + WallpaperUtil.storeWallpaperToSyncFS(filename, wallpaper); + WallpaperUtil.storeWallpaperToSyncFS(thumbnailFilename, thumbnail); + WallpaperUtil.saveWallpaperInfo(filename, layout, + Constants.WallpaperSourceEnum.Custom); });
diff --git a/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js b/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js index 90191d6b..b1e402d 100644 --- a/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js +++ b/chrome/browser/resources/chromeos/wallpaper_manager/js/util.js
@@ -77,13 +77,28 @@ function(fe) { fe.remove(function() {}, null); }, - WallpaperUtil.onFileSystemError); + function(e) { + // NotFoundError is expected under the following scenario: + // The user uses a same account on device A and device B. + // The current wallpaper is a third party wallpaper. Then + // the user changes it to a ONLINE wallpaper on device A. + // Sync file system change and local file system change + // will then both be fired on device B, which makes the + // third party wallpaper be deleted twice from the sync + // file system. We should ignore this error. + if (e.name != 'NotFoundError') + WallpaperUtil.onFileSystemError(e); + }); fs.root.getFile(thumbnailFilename, {create: false}, function(fe) { fe.remove(function() {}, null); }, - WallpaperUtil.onFileSystemError); + function(e) { + // Same as above. + if (e.name != 'NotFoundError') + WallpaperUtil.onFileSystemError(e); + }); }; WallpaperUtil.requestSyncFS(success); };
diff --git a/chrome/browser/resources/media_router/compiled_resources.gyp b/chrome/browser/resources/media_router/compiled_resources.gyp new file mode 100644 index 0000000..5b7abe5 --- /dev/null +++ b/chrome/browser/resources/media_router/compiled_resources.gyp
@@ -0,0 +1,55 @@ +# Copyright 2015 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. +{ + 'targets': [ + { + 'target_name': 'media_router', + 'variables': { + 'depends': [ + '../../../../third_party/polymer/v1_0/components-chromium/iron-a11y-keys-behavior/iron-a11y-keys-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-button-state-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-behaviors/iron-control-state-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-form-element-behavior/iron-form-element-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-icon/iron-icon-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-menu-behavior/iron-menu-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-meta/iron-meta-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-selector/iron-multi-selectable-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-selector/iron-selectable-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-selector/iron-selection-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/iron-validatable-behavior/iron-validatable-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-button-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-ripple-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-behaviors/paper-inky-focus-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-dropdown-menu/paper-dropdown-menu-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-button/paper-button-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-icon-button/paper-icon-button-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-input/paper-input-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-item/paper-item-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-menu/paper-menu-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-ripple/paper-ripple-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-behavior-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-spinner/paper-spinner-extracted.js', + '../../../../third_party/polymer/v1_0/components-chromium/paper-toolbar/paper-toolbar-extracted.js', + '../../../../ui/webui/resources/js/cr.js', + '../../../../ui/webui/resources/js/compiled_resources.gyp:load_time_data', + '../../../../ui/webui/resources/js/util.js', + 'media_router.js', + 'media_router_data.js', + 'media_router_ui_interface.js', + 'elements/issue_banner/issue_banner.js', + 'elements/route_details/route_details.js', + 'elements/media_router_header/media_router_header.js', + 'elements/media_router_container/media_router_container.js', + ], + 'externs': [ + '<(EXTERNS_DIR)/chrome_send.js', + 'externs.js', + ], + }, + 'includes': ['../../../../third_party/closure_compiler/compile_js.gypi'], + } + ], +} +
diff --git a/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.js b/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.js index 7d5c710..02956851 100644 --- a/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.js +++ b/chrome/browser/resources/media_router/elements/issue_banner/issue_banner.js
@@ -113,7 +113,8 @@ * @private */ onClickOptAction_: function(event) { - this.fireIssueActionClick_(this.issue.secondaryActionType); + this.fireIssueActionClick_( + /** @type {number} */(this.issue.secondaryActionType)); }, /**
diff --git a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js index 85073e5f..79b8d77 100644 --- a/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js +++ b/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.js
@@ -52,7 +52,7 @@ */ currentView_: { type: String, - value: '', + value: null, }, /** @@ -62,7 +62,9 @@ deviceMissingText_: { type: String, readOnly: true, - value: loadTimeData.getString('deviceMissing'), + value: function() { + return loadTimeData.getString('deviceMissing'); + }, }, /** @@ -99,7 +101,9 @@ firstRunFlowButtonText_: { type: String, readOnly: true, - value: loadTimeData.getString('firstRunFlowButton'), + value: function() { + return loadTimeData.getString('firstRunFlowButton'); + }, }, /** @@ -109,7 +113,9 @@ firstRunFlowText_: { type: String, readOnly: true, - value: loadTimeData.getString('firstRunFlowText'), + value: function() { + return loadTimeData.getString('firstRunFlowText'); + }, }, /** @@ -119,7 +125,9 @@ firstRunFlowTitle_: { type: String, readOnly: true, - value: loadTimeData.getString('firstRunFlowTitle'), + value: function() { + return loadTimeData.getString('firstRunFlowTitle'); + }, }, /** @@ -134,11 +142,11 @@ /** * The header text tooltip. This would be descriptive of the * source origin, whether a host name, tab URL, etc. - * @type {string} + * @type {?string} */ headerTextTooltip: { type: String, - value: '', + value: null, }, /** @@ -158,7 +166,9 @@ issueHeaderText_: { type: String, readOnly: true, - value: loadTimeData.getString('issueHeader'), + value: function() { + return loadTimeData.getString('issueHeader'); + }, }, /** @@ -216,7 +226,9 @@ selectCastModeHeaderText_: { type: String, readOnly: true, - value: loadTimeData.getString('selectCastModeHeader'), + value: function() { + return loadTimeData.getString('selectCastModeHeader'); + }, }, /** @@ -226,7 +238,9 @@ shareYourScreenSubheadingText_: { type: String, readOnly: true, - value: loadTimeData.getString('shareYourScreenSubheading'), + value: function() { + return loadTimeData.getString('shareYourScreenSubheading'); + }, }, /** @@ -317,6 +331,7 @@ ready: function() { this.elementReadyTimeMs_ = performance.now(); this.showSinkList_(); + this.updateMaxSinkListHeight(this.dialogHeight_); }, attached: function() { @@ -345,6 +360,7 @@ * Fires a 'report-initial-action' event when the user takes their first * action after the dialog opens. Also fires a 'report-initial-action-close' * event if that initial action is to close the dialog. + * @param {!media_router.MediaRouterUserAction} initialAction */ maybeReportUserFirstAction: function(initialAction) { if (this.userHasTakenInitialAction_) @@ -408,7 +424,7 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. + * @param {?media_router.MediaRouterView} view The current view. * @return {boolean} Whether or not to hide the cast mode list. * @private */ @@ -451,7 +467,7 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. + * @param {?media_router.MediaRouterView} view The current view. * @param {?media_router.Issue} issue The current issue. * @return {boolean} Whether or not to hide the header. * @private @@ -463,7 +479,7 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. + * @param {?media_router.MediaRouterView} view The current view. * @param {string} headerText The header text for the sink list. * @return {string} The text for the header. * @private @@ -485,7 +501,7 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. + * @param {?media_router.MediaRouterView} view The current view. * @param {string} headerTooltip The tooltip for the header for the sink * list. * @return {string} The tooltip for the header. @@ -496,8 +512,8 @@ }, /** - * @param {string} The ID of the sink that is currently launching, or empty - * string if none exists. + * @param {string} currentLaunchingSinkId ID of the sink that is currently + * launching, or empty string if none exists. * @private */ computeIsLaunching_: function(currentLaunchingSinkId) { @@ -514,7 +530,7 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. + * @param {?media_router.MediaRouterView} view The current view. * @param {?media_router.Issue} issue The current issue. * @return {boolean} Whether or not to show the issue banner. * @private @@ -538,7 +554,7 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. + * @param {?media_router.MediaRouterView} view The current view. * @param {?media_router.Issue} issue The current issue. * @return {boolean} Whether or not to hide the route details. * @private @@ -561,7 +577,7 @@ /** * @param {boolean} showFirstRunFlow Whether or not to show the first run * flow. - * @param {!media_router.MediaRouterView} currentView The current view. + * @param {?media_router.MediaRouterView} currentView The current view. * @private */ computeShowFirstRunFlow_: function(showFirstRunFlow, currentView) { @@ -606,9 +622,10 @@ }, /** - * @param {!string} currentLauchingSinkid The ID of the sink that is + * @param {!string} currentLaunchingSinkId The ID of the sink that is * currently launching. * @param {!string} sinkId A sink ID. + * @return {boolean} |true| if given sink is currently launching. * @private */ computeSinkIsLaunching_: function(currentLaunchingSinkId, sinkId) { @@ -616,7 +633,7 @@ }, /** - * @param {!Array<!media_router.Sink>} The list of sinks. + * @param {!Array<!media_router.Sink>} sinksToShow The list of sinks. * @return {boolean} Whether or not to hide the sink list. * @private */ @@ -625,7 +642,7 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. + * @param {?media_router.MediaRouterView} view The current view. * @param {?media_router.Issue} issue The current issue. * @return {boolean} Whether or not to hide entire the sink list view. * @private @@ -653,7 +670,7 @@ * |sinkToRouteMap|. * @param {!media_router.Sink} sink * @param {!Object<!string, ?media_router.Route>} sinkToRouteMap - * @return {string} The subtext to be shown. + * @return {?string} The subtext to be shown. * @private */ computeSinkSubtext_: function(sink, sinkToRouteMap) { @@ -813,16 +830,17 @@ * to close the dialog if there is no click within three seconds. * * @param {!Event} event The event object. - * @param {{detail: {route: media_router.Route}}} data - * Parameters in |data|.detail: + * Parameters in |event|.detail: * route - route to close. * @private */ - onCloseRouteClick_: function(event, data) { + onCloseRouteClick_: function(event) { + /** @type {{route: media_router.Route}} */ + var detail = event.detail; this.showSinkList_(); this.startTapTimer_(); - if (data.route.isLocal) { + if (detail.route.isLocal) { this.maybeReportUserFirstAction( media_router.MediaRouterUserAction.STOP_LOCAL); } @@ -890,7 +908,7 @@ */ onSinkClick_: function(event) { this.showOrCreateRoute_(this.$.sinkList.itemForElement(event.target)); - this.fire('sink-click', {index: event.model.index}); + this.fire('sink-click', {index: event['model'].index}); }, /** @@ -985,7 +1003,7 @@ * @param {!media_router.CastMode} castMode */ setShownCastMode_: function(castMode) { - if (this.shownCastMode_ == castMode.type) + if (this.shownCastModeValue_ == castMode.type) return; this.shownCastModeValue_ = castMode.type;
diff --git a/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js b/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js index f0025f7..3e9ea19 100644 --- a/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js +++ b/chrome/browser/resources/media_router/elements/media_router_header/media_router_header.js
@@ -37,11 +37,11 @@ /** * The current view that this header should reflect. - * @type {media_router.MediaRouterView} + * @type {?media_router.MediaRouterView} */ view: { type: String, - value: '', + value: null, }, /** @@ -61,7 +61,7 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. + * @param {?media_router.MediaRouterView} view The current view. * @return {string} The current arrow-drop-* icon to use. * @private */ @@ -71,8 +71,8 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. - * @return {string} Whether or not the arrow drop icon should be hidden. + * @param {?media_router.MediaRouterView} view The current view. + * @return {boolean} Whether or not the arrow drop icon should be hidden. * @private */ computeArrowDropIconHidden_: function(view) { @@ -81,8 +81,8 @@ }, /** - * @param {media_router.MediaRouterView} view The current view. - * @return {string} Whether or not the back button should be hidden. + * @param {?media_router.MediaRouterView} view The current view. + * @return {boolean} Whether or not the back button should be hidden. * @private */ computeBackButtonHidden_: function(view) {
diff --git a/chrome/browser/resources/media_router/elements/route_details/route_details.js b/chrome/browser/resources/media_router/elements/route_details/route_details.js index 0f3daa71..39a4e86 100644 --- a/chrome/browser/resources/media_router/elements/route_details/route_details.js +++ b/chrome/browser/resources/media_router/elements/route_details/route_details.js
@@ -44,7 +44,9 @@ stopCastingButtonText_: { type: String, readOnly: true, - value: loadTimeData.getString('stopCastingButton'), + value: function() { + return loadTimeData.getString('stopCastingButton'); + }, }, /**
diff --git a/chrome/browser/resources/media_router/externs.js b/chrome/browser/resources/media_router/externs.js new file mode 100644 index 0000000..5821b32c --- /dev/null +++ b/chrome/browser/resources/media_router/externs.js
@@ -0,0 +1,15 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview Externs to be declared to properly compile JS code. + * @externs + */ + +var performance = {}; + +/** + * @return {number} + */ +performance.now = function() {};
diff --git a/chrome/browser/resources/media_router/media_router.css b/chrome/browser/resources/media_router/media_router.css index 00e539a2..c2aca5e 100644 --- a/chrome/browser/resources/media_router/media_router.css +++ b/chrome/browser/resources/media_router/media_router.css
@@ -9,6 +9,12 @@ } #media-router-container { + -webkit-margin-start: 1px; + box-shadow: 0 3px 4px 0 rgba(0, 0, 0, 0.14), + 0 1px 8px 0 rgba(0, 0, 0, 0.12), + 0 3px 3px -2px rgba(0, 0, 0, 0.4); display: flex; flex-direction: column; + margin-bottom: 1px; + width: calc(100% - 2px); }
diff --git a/chrome/browser/resources/media_router/media_router.js b/chrome/browser/resources/media_router/media_router.js index ad9f6cf5..f358ce78 100644 --- a/chrome/browser/resources/media_router/media_router.js +++ b/chrome/browser/resources/media_router/media_router.js
@@ -13,7 +13,10 @@ // @const {number} var KEYCODE_ESC = 27; - // The media-router-container element. Initialized after polymer is ready. + /** + * The media-router-container element. Initialized after polymer is ready. + * @type {?MediaRouterContainerElement} + */ var container = null; /** @@ -23,7 +26,8 @@ function initialize() { media_router.browserApi.requestInitialData(); - container = $('media-router-container'); + container = /** @type {!MediaRouterContainerElement} */ + ($('media-router-container')); media_router.ui.setContainer(container); container.addEventListener('acknowledge-first-run-flow', @@ -62,12 +66,14 @@ * Reports the selected cast mode. * Called when the user selects a cast mode from the picker. * - * @param {{detail: {castModeType: number}}} data - * Parameters in |data|.detail: + * @param {!Event} event + * Parameters in |event|.detail: * castModeType - type of cast mode selected by the user. */ - function onCastModeSelected(data) { - media_router.browserApi.reportSelectedCastMode(data.detail.castModeType); + function onCastModeSelected(event) { + /** @type {{castModeType: number}} */ + var detail = event.detail; + media_router.browserApi.reportSelectedCastMode(detail.castModeType); } /** @@ -94,12 +100,14 @@ * Called when the user explicitly interacts with the dialog to perform an * action. * - * @param {{detail: {action: number}}} data - * Parameters in |data|.detail: + * @param {!Event} event + * Parameters in |event|.detail: * action - the first action taken by the user. */ - function onInitialAction(data) { - media_router.browserApi.reportInitialAction(data.detail.action); + function onInitialAction(event) { + /** @type {{action: number}} */ + var detail = event.detail; + media_router.browserApi.reportInitialAction(detail.action); } /** @@ -107,29 +115,32 @@ * first action the user took after opening the dialog. * Called when the user closes the dialog without taking any other action. * - * @param {{detail: {timeMs: number}}} data - * Parameters in |data|.detail: + * @param {!Event} event + * Parameters in |event|.detail: * timeMs - time in ms for the user to close the dialog. */ - function onInitialActionClose(data) { - media_router.browserApi.reportTimeToInitialActionClose(data.detail.timeMs); + function onInitialActionClose(event) { + /** @type {{timeMs: number}} */ + var detail = event.detail; + media_router.browserApi.reportTimeToInitialActionClose(detail.timeMs); } /** * Acts on an issue and dismisses it from the UI. * Called when the user performs an action on an issue. * - * @param {{detail: {id: string, actionType: number, helpPageId: number}}} - * data - * Parameters in |data|.detail: + * @param {!Event} event + * Parameters in |event|.detail: * id - issue ID. * actionType - type of action performed by the user. * helpPageId - the numeric help center ID. */ - function onIssueActionClick(data) { - media_router.browserApi.actOnIssue(data.detail.id, - data.detail.actionType, - data.detail.helpPageId); + function onIssueActionClick(event) { + /** @type {{id: string, actionType: number, helpPageId: number}} */ + var detail = event.detail; + media_router.browserApi.actOnIssue(detail.id, + detail.actionType, + detail.helpPageId); container.issue = null; } @@ -137,50 +148,44 @@ * Creates a media route. * Called when the user requests to create a media route. * - * @param {{detail: {sinkId: string, selectedCastModeValue: number}}} data - * Parameters in |data|.detail: + * @param {!Event} event + * Parameters in |event|.detail: * sinkId - sink ID selected by the user. * selectedCastModeValue - cast mode selected by the user. */ - function onCreateRoute(data) { - media_router.browserApi.requestRoute(data.detail.sinkId, - data.detail.selectedCastModeValue); + function onCreateRoute(event) { + /** @type {{sinkId: string, selectedCastModeValue, number}} */ + var detail = event.detail; + media_router.browserApi.requestRoute(detail.sinkId, + detail.selectedCastModeValue); } /** * Stops a route. * Called when the user requests to stop a media route. * - * @param {{detail: {route: media_router.Route}}} data - * Parameters in |data|.detail: - * route - route to close. + * @param {!Event} event + * Parameters in |event|.detail: + * route - The route to close. */ - function onCloseRouteClick(data) { - media_router.browserApi.closeRoute(data.detail.route); + function onCloseRouteClick(event) { + /** @type {{route: !media_router.Route}} */ + var detail = event.detail; + media_router.browserApi.closeRoute(detail.route); } /** * Joins a route. * Called when the user requests to join a media route. * - * @param {{detail: {route: media_router.Route}}} data - * Parameters in |data|.detail: + * @param {!Event} event + * Parameters in |event|.detail: * route - route to join. */ - function onJoinRouteClick(data) { - media_router.browserApi.joinRoute(data.detail.route); - } - - /** - * Reports the index of the sink that was clicked. - * Called when the user selects a sink on the sink list. - * - * @param {{detail: {index: number}}} data - * Paramters in |data|.detail: - * index - the index of the clicked sink. - */ - function onSinkClick(data) { - media_router.browserApi.reportClickedSinkIndex(data.detail.index); + function onJoinRouteClick(event) { + /** @type {{route: !media_router.Route}} */ + var detail = event.detail; + media_router.browserApi.joinRoute(detail.route); } /** @@ -213,52 +218,60 @@ media_router.MediaRouterView.SINK_LIST); } - /* + /** * Reports the initial state of the dialog after it is opened. * Called after initial data is populated. * - * @param {{detail: {currentView: string}}} data - * Parameters in |data|.detail: + * @param {!Event} event + * Parameters in |event|.detail: * currentView - the current dialog's current view. */ - function onShowInitialState(data) { - media_router.browserApi.reportInitialState(data.detail.currentView); + function onShowInitialState(event) { + /** @type {{currentView: string}} */ + var detail = event.detail; + media_router.browserApi.reportInitialState(detail.currentView); } /** * Reports the index of the sink that was clicked. * Called when the user selects a sink on the sink list. * - * @param {{detail: {index: number}}} data - * Paramters in |data|.detail: + * @param {!Event} event + * Paramters in |event|.detail: * index - the index of the clicked sink. */ - function onSinkClick(data) { - media_router.browserApi.reportClickedSinkIndex(data.detail.index); + function onSinkClick(event) { + /** @type {{index: number}} */ + var detail = event.detail; + media_router.browserApi.reportClickedSinkIndex(detail.index); } /** * Reports the time it took for the user to select a sink to create a route * after the list was popuated and shown. * - * @param {{detail: {timeMs: number}}} data - * Paramters in |data|.detail: + * @param {!Event} event + * Paramters in |event|.detail: * timeMs - the time it took for the user to select a sink. */ - function onSinkClickTimeReported(data) { - media_router.browserApi.reportTimeToClickSink(data.detail.timeMs); + function onSinkClickTimeReported(event) { + /** @type {{timeMs: number}} */ + var detail = event.detail; + media_router.browserApi.reportTimeToClickSink(detail.timeMs); } /** * Reports the current sink count. * Called 3 seconds after the dialog is initially opened. * - * @param {{detail: {sinkCount: number}}} data - * Parameters in |data|.detail: + * @param {!Event} event + * Parameters in |event|.detail: * sinkCount - the number of sinks. */ - function onSinkCountReported(data) { - media_router.browserApi.reportSinkCount(data.detail.sinkCount); + function onSinkCountReported(event) { + /** @type {{sinkCount: number}} */ + var detail = event.detail; + media_router.browserApi.reportSinkCount(detail.sinkCount); } return {
diff --git a/chrome/browser/resources/media_router/media_router_data.js b/chrome/browser/resources/media_router/media_router_data.js index ea21e63..f28ccd5 100644 --- a/chrome/browser/resources/media_router/media_router_data.js +++ b/chrome/browser/resources/media_router/media_router_data.js
@@ -4,74 +4,76 @@ // Any strings used here will already be localized. Values such as // CastMode.type or IDs will be defined elsewhere and determined later. + +cr.exportPath('media_router'); + +/** + * This corresponds to the C++ MediaCastMode, with the exception of AUTO. + * See below for details. Note to support fast bitset operations, the values + * here are (1 << [corresponding value in MR]). + * @enum {number} + */ +media_router.CastModeType = { + // Note: AUTO mode is only used to configure the sink list container to show + // all sinks. Individual sinks are configured with a specific cast mode + // (DEFAULT, TAB_MIRROR, DESKTOP_MIRROR). + AUTO: -1, + DEFAULT: 0x1, + TAB_MIRROR: 0x2, + DESKTOP_MIRROR: 0x4, +}; + +/** + * This corresponds to the C++ MediaRouterMetrics MediaRouterUserAction. + * @enum {number} + */ +media_router.MediaRouterUserAction = { + CHANGE_MODE: 0, + START_LOCAL: 1, + STOP_LOCAL: 2, + CLOSE: 3, + STATUS_REMOTE: 4, +}; + +/** + * The possible states of the Media Router dialog. Used to determine which + * components to show. + * @enum {string} + */ +media_router.MediaRouterView = { + CAST_MODE_LIST: 'cast-mode-list', + FILTER: 'filter', + ISSUE: 'issue', + ROUTE_DETAILS: 'route-details', + SINK_LIST: 'sink-list', +}; + +/** + * This corresponds to the C++ MediaSink IconType. + * @enum {number} + */ +media_router.SinkIconType = { + CAST: 0, + CAST_AUDIO: 1, + CAST_AUDIO_GROUP: 2, + GENERIC: 3, + HANGOUT: 4, +}; + +/** + * @enum {string} + */ +media_router.SinkStatus = { + IDLE: 'idle', + ACTIVE: 'active', + REQUEST_PENDING: 'request_pending' +}; + cr.define('media_router', function() { 'use strict'; /** - * This corresponds to the C++ MediaCastMode, with the exception of AUTO. - * See below for details. Note to support fast bitset operations, the values - * here are (1 << [corresponding value in MR]). - * @enum {number} - */ - var CastModeType = { - // Note: AUTO mode is only used to configure the sink list container to show - // all sinks. Individual sinks are configured with a specific cast mode - // (DEFAULT, TAB_MIRROR, DESKTOP_MIRROR). - AUTO: -1, - DEFAULT: 0x1, - TAB_MIRROR: 0x2, - DESKTOP_MIRROR: 0x4, - }; - - /** - * This corresponds to the C++ MediaRouterMetrics MediaRouterUserAction. - * @enum {number} - */ - var MediaRouterUserAction = { - CHANGE_MODE: 0, - START_LOCAL: 1, - STOP_LOCAL: 2, - CLOSE: 3, - STATUS_REMOTE: 4, - }; - - /** - * The possible states of the Media Router dialog. Used to determine which - * components to show. - * @enum {string} - */ - var MediaRouterView = { - CAST_MODE_LIST: 'cast-mode-list', - FILTER: 'filter', - ISSUE: 'issue', - ROUTE_DETAILS: 'route-details', - SINK_LIST: 'sink-list', - }; - - /** - * This corresponds to the C++ MediaSink IconType. - * @enum {number} - */ - var SinkIconType = { - CAST: 0, - CAST_AUDIO: 1, - CAST_AUDIO_GROUP: 2, - GENERIC: 3, - HANGOUT: 4, - }; - - /** - * @enum {string} - */ - var SinkStatus = { - IDLE: 'idle', - ACTIVE: 'active', - REQUEST_PENDING: 'request_pending' - }; - - - /** - * @param {media_router.CastModeType} type The type of cast mode. + * @param {number} type The type of cast mode. * @param {string} description The description of the cast mode. * @param {?string} host The hostname of the site to cast. * @constructor @@ -92,10 +94,9 @@ * Placeholder object for AUTO cast mode. See comment in CastModeType. * @const {!media_router.CastMode} */ - var AUTO_CAST_MODE = new CastMode(CastModeType.AUTO, + var AUTO_CAST_MODE = new CastMode(media_router.CastModeType.AUTO, loadTimeData.getString('autoCastMode'), null); - /** * @param {string} id The ID of this issue. * @param {string} title The issue title. @@ -201,10 +202,10 @@ /** @type {?string} */ this.domain = domain; - /** @type {SinkIconType} */ + /** @type {!media_router.SinkIconType} */ this.iconType = iconType; - /** @type {media_router.SinkStatus} */ + /** @type {!media_router.SinkStatus} */ this.status = status; /** @type {number} */ @@ -228,11 +229,6 @@ return { AUTO_CAST_MODE: AUTO_CAST_MODE, - CastModeType: CastModeType, - MediaRouterUserAction: MediaRouterUserAction, - MediaRouterView: MediaRouterView, - SinkIconType: SinkIconType, - SinkStatus: SinkStatus, CastMode: CastMode, Issue: Issue, Route: Route,
diff --git a/chrome/browser/resources/media_router/media_router_ui_interface.js b/chrome/browser/resources/media_router/media_router_ui_interface.js index 49044f8..fb53eff 100644 --- a/chrome/browser/resources/media_router/media_router_ui_interface.js +++ b/chrome/browser/resources/media_router/media_router_ui_interface.js
@@ -50,16 +50,18 @@ /** * Populates the WebUI with data obtained from Media Router. * - * @param {deviceMissingUrl: string, - * sinks: !Array<!media_router.Sink>, - * routes: !Array<!media_router.Route>, - * castModes: !Array<!media_router.CastMode>, - * wasFirstRunFlowAcknowledged: boolean} data + * @param {{deviceMissingUrl: string, + * sinks: !Array<!media_router.Sink>, + * routes: !Array<!media_router.Route>, + * castModes: !Array<!media_router.CastMode>, + * wasFirstRunFlowAcknowledged: boolean}} data * Parameters in data: * deviceMissingUrl - url to be opened on "Device missing?" clicked. * sinks - list of sinks to be displayed. * routes - list of routes that are associated with the sinks. * castModes - list of available cast modes. + * wasFirstRunFlowAcknowledged - true if first run flow was previously + * acknowledged by user. */ function setInitialData(data) { container.deviceMissingUrl = data['deviceMissingUrl']; @@ -185,7 +187,7 @@ chrome.send('reportClickedSinkIndex', [sinkIndex]); } - /* + /** * Reports the initial dialog view. * * @param {string} view
diff --git a/chrome/browser/resources/options/autofill_options.html b/chrome/browser/resources/options/autofill_options.html index e018c505e..cf33636 100644 --- a/chrome/browser/resources/options/autofill_options.html +++ b/chrome/browser/resources/options/autofill_options.html
@@ -2,14 +2,6 @@ <div class="close-button"></div> <h1 i18n-content="autofillOptionsPage"></h1> <div class="content-area"> - <!-- TODO(estade): This checkbox shouldn't show if you're not signed into - sync. Or perhaps it should show with a link to go sign in with sync? - --> - <div id="autofill-wallet-setting-area" class="checkbox"> - <label> - <input pref="autofill.wallet_import_enabled" type="checkbox"> - <span i18n-content="autofillWalletOption"></span> - </div> <h3 i18n-content="autofillAddresses"></h3> <div class="settings-list"> <list id="address-list"></list>
diff --git a/chrome/browser/resources/options/autofill_options.js b/chrome/browser/resources/options/autofill_options.js index bea6a1a..7f30000 100644 --- a/chrome/browser/resources/options/autofill_options.js +++ b/chrome/browser/resources/options/autofill_options.js
@@ -76,9 +76,6 @@ return true; // Always follow the href }; - this.walletIntegrationAvailableStateChanged_( - loadTimeData.getBoolean('autofillWalletIntegrationAvailable')); - // TODO(jhawkins): What happens when Autofill is disabled whilst on the // Autofill options page? }, @@ -187,16 +184,6 @@ AutofillEditCreditCardOverlay.loadCreditCard(creditCard); PageManager.showPageByName('autofillEditCreditCard'); }, - - /** - * Toggles the visibility of the Wallet integration checkbox. - * @param {boolean} available Whether the user has the option of using - * Wallet data. - * @private - */ - walletIntegrationAvailableStateChanged_: function(available) { - $('autofill-wallet-setting-area').hidden = !available; - }, }; AutofillOptions.setAddressList = function(entries) { @@ -215,11 +202,6 @@ AutofillOptions.getInstance().showEditAddressOverlay_(address); }; - AutofillOptions.walletIntegrationAvailableStateChanged = function(available) { - AutofillOptions.getInstance(). - walletIntegrationAvailableStateChanged_(available); - }; - /** * @param {CreditCardData} creditCard */
diff --git a/chrome/browser/resources/options/browser_options.css b/chrome/browser/resources/options/browser_options.css index bc6f017..ef72ef0 100644 --- a/chrome/browser/resources/options/browser_options.css +++ b/chrome/browser/resources/options/browser_options.css
@@ -149,17 +149,6 @@ vertical-align: middle; } -/* CSS tweak to fix crbug.com/151788. Inconsistencies in the CSS rules across - * platforms and elements. Too risky to attempt a general fix for M23 at this - * time. This fix addresses the immediate problem in the bug report by forcing - * the button to align consistently with its neighboring select element. - * TODO(kevers): Revisit padding rules for select and buttons to ensure - * consistency in the size and baseline across all platforms. */ -#manage-default-search-engines { - padding-bottom: 0; - padding-top: 0; -} - .extension-controlled-warning-box { background-color: #fbfbfb; border: 1px solid #cecece; @@ -175,14 +164,6 @@ padding-top: 3px; } -/* Override a platform specific rule in Widgets that may no longer be relevant. - * Too late in the development cycle to update Widgets.css due to the number - * of pages that depend on it. - * TODO(kevers): Rivisit padding rules. */ -#default-search-engine { - padding-bottom: 0; -} - .setting-extra-description { -webkit-margin-start: 1.8em; color: #999;
diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html index 51a79e6..69f0434 100644 --- a/chrome/browser/resources/options/browser_options.html +++ b/chrome/browser/resources/options/browser_options.html
@@ -7,7 +7,7 @@ <link rel="import" href="chrome://resources/cr_elements/network/cr_network_icon.html"> <link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html"> <include src="secondary_user_banner.html"> - <section> + <section id="network-section-cros"> <div id="network-section-header" class="section-header"> <h3 i18n-content="sectionTitleInternet"></h3> <span class="controlled-setting-indicator" plural></span> @@ -102,7 +102,7 @@ </if> </section> <if expr="chromeos"> - <section> + <section id="device-section"> <h3 i18n-content="sectionTitleDevice"></h3> <div> <span i18n-content="deviceGroupDescription"></span> @@ -137,7 +137,7 @@ </div> </section> </if> - <section> + <section id="search-section"> <h3 i18n-content="sectionTitleSearch"></h3> <div id="search-section-content"> <span id="default-search-engine-label" @@ -283,7 +283,7 @@ <div id="advanced-settings" hidden> <div id="advanced-settings-container"> <if expr="chromeos"> - <section> + <section id="date-time-section"> <h3 i18n-content="datetimeTitle"></h3> <div class="option-control-table"> <div guest-visibility="disabled"> @@ -727,7 +727,7 @@ </div> </div> </section> - <section> + <section id="certificates-section"> <h3 i18n-content="advancedSectionTitleCertificates"></h3> <div> <if expr="use_nss_certs or is_win or is_macosx"> @@ -772,7 +772,7 @@ <include src="startup_section.html"> </if> -<section> +<section id="a11y-section"> <h3 i18n-content="accessibilityTitle"></h3> <div>
diff --git a/chrome/browser/resources/options/search_page.js b/chrome/browser/resources/options/search_page.js index 6cd5ff8..90703103 100644 --- a/chrome/browser/resources/options/search_page.js +++ b/chrome/browser/resources/options/search_page.js
@@ -2,6 +2,55 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/** + * Section IDs use for metrics. The integer values should match up with the + * |SettingsSections| in histograms.xml. + * @type {Object<string, number>} + */ +var SettingsSections = { + 'None': 0, + 'Unknown': 1, + 'network-section-cros': 2, + 'proxy-section': 3, + 'appearance-section': 4, + 'device-section': 5, + 'search-section': 6, + 'sync-users-section': 7, + 'set-default-browser-section': 8, + 'date-time-section': 9, + 'device-control-section': 10, + 'privacy-section': 11, + 'bluetooth-devices': 12, + 'passwords-and-autofill-section': 13, + 'easy-unlock-section': 14, + 'web-content-section': 15, + 'network-section': 16, + 'languages-section': 17, + 'downloads-section': 18, + 'certificates-section': 19, + 'cloudprint-options-mdns': 20, + 'a11y-section': 21, + 'factory-reset-section': 22, + 'system-section': 23, + 'reset-profile-settings-section': 24, + 'sync-section': 25, + 'startup-section': 26, + 'mouselock-section': 27, + 'page-zoom-levels': 28, + 'status-section': 29, + 'main-section': 30, + 'pointer-section-touchpad': 31, + 'pointer-section-mouse': 32, + 'prefs-blocked-languages': 33, + 'prefs-language-blacklist': 34, + 'prefs-site-blacklist': 35, + 'prefs-whitelists': 36, + 'prefs-supported-languages': 37, + 'prefs-cld-version': 38, + 'prefs-cld-data-source': 39, + 'prefs-dump': 40, +}; + cr.define('options', function() { /** @const */ var Page = cr.ui.pageManager.Page; /** @const */ var PageManager = cr.ui.pageManager.PageManager; @@ -353,6 +402,7 @@ var bubbleControls = []; var pageMatchesForMetrics = 0; var subpageMatchesForMetrics = 0; + var sectionMatchesForMetrics = {}; // Generate search text by applying lowercase and escaping any characters // that would be problematic for regular expressions. @@ -373,6 +423,9 @@ if (!node.hidden) { foundMatches = true; pageMatchesForMetrics += 1; + var section = SettingsSections[node.id] || + SettingsSections['Unknown']; + sectionMatchesForMetrics[section] = section; } } } @@ -410,7 +463,17 @@ if (!foundMatches) { chrome.metricsPrivate.recordSmallCount( 'Settings.SearchLengthNoMatch', text.length); + chrome.metricsPrivate.recordSmallCount( + 'Settings.SearchSections', SettingsSections['None']); + } else { + for (var section in sectionMatchesForMetrics) { + var sectionId = sectionMatchesForMetrics[section]; + assert(sectionId !== undefined); + chrome.metricsPrivate.recordSmallCount( + 'Settings.SearchSections', sectionId); + } } + chrome.metricsPrivate.recordUserAction('Settings.Searching'); chrome.metricsPrivate.recordSmallCount( 'Settings.SearchLength', text.length);
diff --git a/chrome/browser/resources/options/sync_setup_overlay.css b/chrome/browser/resources/options/sync_setup_overlay.css index c04dc00..0b79504 100644 --- a/chrome/browser/resources/options/sync_setup_overlay.css +++ b/chrome/browser/resources/options/sync_setup_overlay.css
@@ -42,10 +42,6 @@ padding: 10px; } -#sync-select-container { - margin-bottom: 10px; -} - #sync-instructions-container { line-height: 1.8em; margin-bottom: 30px; @@ -53,7 +49,7 @@ #choose-data-types-body { -webkit-column-count: 3; - margin: 10px 0; + margin: 10px 0 0 0; } #choose-data-types-body > .checkbox:first-child {
diff --git a/chrome/browser/resources/options/sync_setup_overlay.html b/chrome/browser/resources/options/sync_setup_overlay.html index eee31994..8924552 100644 --- a/chrome/browser/resources/options/sync_setup_overlay.html +++ b/chrome/browser/resources/options/sync_setup_overlay.html
@@ -106,6 +106,14 @@ </div> </div> </div> + <div id="payments-integration-setting-area" class="checkbox"> + <label> + <input id="payments-integration-checkbox" type="checkbox"> + <span i18n-content="enablePaymentsIntegration"></span> + </label> + <a i18n-values="href:autofillHelpURL" target="_blank" + i18n-content="learnMore"></a> + </div> <div id="customize-sync-encryption-new"> <hr> <h4 i18n-content="encryptionSectionTitle"></h4>
diff --git a/chrome/browser/resources/options/sync_setup_overlay.js b/chrome/browser/resources/options/sync_setup_overlay.js index d05b778..50a297a 100644 --- a/chrome/browser/resources/options/sync_setup_overlay.js +++ b/chrome/browser/resources/options/sync_setup_overlay.js
@@ -25,6 +25,7 @@ * passwordsEnforced: boolean, * passwordsRegistered: boolean, * passwordsSynced: boolean, + * paymentsIntegrationEnabled: boolean, * preferencesEnforced: boolean, * preferencesRegistered: boolean, * preferencesSynced: boolean, @@ -159,6 +160,11 @@ $('use-default-link').onclick = function() { self.showSyncEverythingPage_(); }; + $('autofill-checkbox').onclick = function() { + var autofillSyncEnabled = $('autofill-checkbox').checked; + $('payments-integration-checkbox').checked = autofillSyncEnabled; + $('payments-integration-checkbox').disabled = !autofillSyncEnabled; + }; }, /** @private */ @@ -210,6 +216,7 @@ for (var i = 0; i < checkboxes.length; i++) { checkboxes[i].checked = value; } + $('payments-integration-checkbox').checked = value; }, /** @@ -330,6 +337,7 @@ options.DataTypeSelection.SYNC_EVERYTHING; var syncNothing = $('sync-select-datatypes').selectedIndex == options.DataTypeSelection.SYNC_NOTHING; + var autofillSynced = syncAll || $('autofill-checkbox').checked; var result = JSON.stringify({ 'syncAllDataTypes': syncAll, 'syncNothing': syncNothing, @@ -337,13 +345,15 @@ 'preferencesSynced': syncAll || $('preferences-checkbox').checked, 'themesSynced': syncAll || $('themes-checkbox').checked, 'passwordsSynced': syncAll || $('passwords-checkbox').checked, - 'autofillSynced': syncAll || $('autofill-checkbox').checked, + 'autofillSynced': autofillSynced, 'extensionsSynced': syncAll || $('extensions-checkbox').checked, 'typedUrlsSynced': syncAll || $('typed-urls-checkbox').checked, 'appsSynced': syncAll || $('apps-checkbox').checked, 'tabsSynced': syncAll || $('tabs-checkbox').checked, - 'wifiCredentialsSynced': syncAll || - $('wifi-credentials-checkbox').checked, + 'wifiCredentialsSynced': + syncAll || $('wifi-credentials-checkbox').checked, + 'paymentsIntegrationEnabled': syncAll || + (autofillSynced && $('payments-integration-checkbox').checked), 'encryptAllData': encryptAllData, 'usePassphrase': usePassphrase, 'isGooglePassphrase': googlePassphrase, @@ -367,6 +377,7 @@ for (var i = 0; i < configureElements.length; i++) configureElements[i].disabled = disabled; $('sync-select-datatypes').disabled = disabled; + $('payments-integration-checkbox').disabled = disabled; $('customize-link').hidden = disabled; $('customize-link').disabled = disabled; @@ -420,9 +431,15 @@ this.dataTypeBoxesChecked_['autofill-checkbox'] = args.autofillSynced; this.dataTypeBoxesDisabled_['autofill-checkbox'] = args.autofillEnforced; + this.dataTypeBoxesChecked_['payments-integration-checkbox'] = + args.autofillSynced && args.paymentsIntegrationEnabled; + this.dataTypeBoxesDisabled_['payments-integration-checkbox'] = + !args.autofillSynced; $('autofill-item').hidden = false; + $('payments-integration-setting-area').hidden = false; } else { $('autofill-item').hidden = true; + $('payments-integration-setting-area').hidden = true; } if (args.extensionsRegistered) { $('extensions-checkbox').checked = args.extensionsSynced;
diff --git a/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chrome/browser/resources/settings/privacy_page/privacy_page.html index 254e197..2e6650a 100644 --- a/chrome/browser/resources/settings/privacy_page/privacy_page.html +++ b/chrome/browser/resources/settings/privacy_page/privacy_page.html
@@ -71,18 +71,22 @@ </if> </div> <div class="settings-box" on-tap="onManageCertificatesTap_"> - <paper-item> - <paper-item-body> - <div i18n-content="manageCertificates"></div> - </paper-item-body> - </paper-item> + <div class="start"> + <div i18n-content="manageCertificates"></div> + <div class="secondary"> + <!-- TODO(dschuyler) replace this placeholder text --> + Contrary to popular belief, Lorem Ipsum is not simply random text. + </div> + </div> </div> <div class="settings-box" on-tap="onSiteSettingsTap_"> - <paper-item> - <paper-item-body> - <div i18n-content="siteSettings"></div> - </paper-item-body> - </paper-item> + <div class="start"> + <div i18n-content="siteSettings"></div> + <div class="secondary"> + <!-- TODO(dschuyler) replace this placeholder text --> + Contrary to popular belief, Lorem Ipsum is not simply random text. + </div> + </div> </div> <div class="settings-box"> <paper-button on-tap="onClearBrowsingDataTap_"
diff --git a/chrome/browser/resources/settings/settings_shared.css b/chrome/browser/resources/settings/settings_shared.css index 131a7e2..ba6bb13 100644 --- a/chrome/browser/resources/settings/settings_shared.css +++ b/chrome/browser/resources/settings/settings_shared.css
@@ -97,6 +97,10 @@ border-top: none; } +.settings-box .secondary { + color: #969696; +} + .split { display: flex; }
diff --git a/chrome/browser/resources/settings/site_settings/site_list.js b/chrome/browser/resources/settings/site_settings/site_list.js index e8f03f09..79e64e4 100644 --- a/chrome/browser/resources/settings/site_settings/site_list.js +++ b/chrome/browser/resources/settings/site_settings/site_list.js
@@ -100,35 +100,45 @@ }, observers: [ - 'onCategoryChanged_(prefs.profile.content_settings.exceptions.*, ' + - 'category, categorySubtype)', + 'initialize_(prefs.profile.content_settings.exceptions.*,' + + 'category, categorySubtype)' ], - ready: function() { - CrSettingsPrefs.initialized.then(function() { - this.initialize_(); - }.bind(this)); - }, - /** * One-time initialization routines for this class. * @private */ initialize_: function() { - this.setUpActionMenu_(); + CrSettingsPrefs.initialized.then(function() { + this.setUpActionMenu_(); + this.ensureOpened_(); + }.bind(this)); - if (this.categorySubtype == settings.PermissionValues.ALLOW) { - this.$.category.opened = true; - } + this.populateList_(); }, /** - * Handles changes to the category, either via the underlying exceptions pref - * changing or direct manipulation of the |category| variable. - * @private + * Ensures the widget is |opened| when needed when displayed initially. */ - onCategoryChanged_: function() { - this.populateList_(); + ensureOpened_: function() { + // Allowed list is always shown opened by default. + if (this.categorySubtype == settings.PermissionValues.ALLOW) { + this.$.category.opened = true; + return; + } + + // Block list should only be shown opened if there is nothing to show in + // the allowed list. + var pref = this.getPref( + this.computeCategoryExceptionsPrefName(this.category)); + var sites = pref.value; + for (var origin in sites) { + var site = /** @type {{setting: number}} */(sites[origin]); + if (site.setting == settings.PermissionValues.ALLOW) + return; + } + + this.$.category.opened = true; }, /**
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.cc b/chrome/browser/safe_browsing/client_side_detection_host.cc index 1fce269..f7cb750 100644 --- a/chrome/browser/safe_browsing/client_side_detection_host.cc +++ b/chrome/browser/safe_browsing/client_side_detection_host.cc
@@ -340,7 +340,9 @@ ui_manager_->RemoveObserver(this); } -bool ClientSideDetectionHost::OnMessageReceived(const IPC::Message& message) { +bool ClientSideDetectionHost::OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(ClientSideDetectionHost, message) IPC_MESSAGE_HANDLER(SafeBrowsingHostMsg_PhishingDetectionDone,
diff --git a/chrome/browser/safe_browsing/client_side_detection_host.h b/chrome/browser/safe_browsing/client_side_detection_host.h index 4bc7760..02b2767 100644 --- a/chrome/browser/safe_browsing/client_side_detection_host.h +++ b/chrome/browser/safe_browsing/client_side_detection_host.h
@@ -38,7 +38,8 @@ ~ClientSideDetectionHost() override; // From content::WebContentsObserver. - bool OnMessageReceived(const IPC::Message& message) override; + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override; void DidGetResourceResponseStart( const content::ResourceRequestDetails& details) override;
diff --git a/chrome/browser/sync/test/integration/dictionary_helper.cc b/chrome/browser/sync/test/integration/dictionary_helper.cc index e22457d2..b9937bcb 100644 --- a/chrome/browser/sync/test/integration/dictionary_helper.cc +++ b/chrome/browser/sync/test/integration/dictionary_helper.cc
@@ -10,6 +10,7 @@ #include "base/format_macros.h" #include "base/macros.h" #include "base/run_loop.h" +#include "base/strings/string_number_conversions.h" #include "base/strings/stringprintf.h" #include "chrome/browser/spellchecker/spellcheck_custom_dictionary.h" #include "chrome/browser/spellchecker/spellcheck_factory.h" @@ -26,16 +27,16 @@ public: // Same as SpellcheckCustomDictionary::AddWord/RemoveWord, except does not // write to disk. - static bool ApplyChange( - SpellcheckCustomDictionary* dictionary, - SpellcheckCustomDictionary::Change& change) { - int result = change.Sanitize(dictionary->GetWords()); - dictionary->Apply(change); - dictionary->Notify(change); - dictionary->Sync(change); + static bool ApplyChange(SpellcheckCustomDictionary* dictionary, + SpellcheckCustomDictionary::Change* change) { + int result = change->Sanitize(dictionary->GetWords()); + dictionary->Apply(*change); + dictionary->Notify(*change); + dictionary->Sync(*change); return !result; } + private: DISALLOW_COPY_AND_ASSIGN(DictionarySyncIntegrationTestHelper); }; @@ -183,10 +184,18 @@ SpellcheckCustomDictionary::Change dictionary_change; dictionary_change.AddWord(word); bool result = DictionarySyncIntegrationTestHelper::ApplyChange( - GetDictionary(index), dictionary_change); + GetDictionary(index), &dictionary_change); if (sync_datatype_helper::test()->use_verifier()) { result &= DictionarySyncIntegrationTestHelper::ApplyChange( - GetVerifierDictionary(), dictionary_change); + GetVerifierDictionary(), &dictionary_change); + } + return result; +} + +bool AddWords(int index, int n, const std::string& prefix) { + bool result = true; + for (int i = 0; i < n; ++i) { + result &= AddWord(index, prefix + base::IntToString(i)); } return result; } @@ -195,10 +204,10 @@ SpellcheckCustomDictionary::Change dictionary_change; dictionary_change.RemoveWord(word); bool result = DictionarySyncIntegrationTestHelper::ApplyChange( - GetDictionary(index), dictionary_change); + GetDictionary(index), &dictionary_change); if (sync_datatype_helper::test()->use_verifier()) { result &= DictionarySyncIntegrationTestHelper::ApplyChange( - GetVerifierDictionary(), dictionary_change); + GetVerifierDictionary(), &dictionary_change); } return result; }
diff --git a/chrome/browser/sync/test/integration/dictionary_helper.h b/chrome/browser/sync/test/integration/dictionary_helper.h index 659155b..cd73291 100644 --- a/chrome/browser/sync/test/integration/dictionary_helper.h +++ b/chrome/browser/sync/test/integration/dictionary_helper.h
@@ -43,6 +43,11 @@ // if |word| is valid and not a duplicate. Otherwise returns false. bool AddWord(int index, const std::string& word); +// Add |n| words with the given |prefix| to the specified client |index|. Also +// adds to the verifier if not disAbled. Return value is true iff all words are +// not duplicates and valid. +bool AddWords(int index, int n, const std::string& prefix); + // Removes |word| from the dictionary for profile with index |index|. Also // removes |word| from the verifier if DisableVerifier() hasn't been called. // Returns true if |word| was found. Otherwise returns false.
diff --git a/chrome/browser/sync/test/integration/fake_server_match_status_checker.cc b/chrome/browser/sync/test/integration/fake_server_match_status_checker.cc new file mode 100644 index 0000000..d45b01d --- /dev/null +++ b/chrome/browser/sync/test/integration/fake_server_match_status_checker.cc
@@ -0,0 +1,39 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/sync/test/integration/fake_server_match_status_checker.h" +#include "chrome/browser/sync/test/integration/sync_datatype_helper.h" +#include "chrome/browser/sync/test/integration/sync_test.h" + +namespace fake_server { + +FakeServerMatchStatusChecker::FakeServerMatchStatusChecker() + : fake_server_(sync_datatype_helper::test()->GetFakeServer()) { + DCHECK(fake_server_); +} + +void FakeServerMatchStatusChecker::Wait() { + DVLOG(1) << "Await: " << GetDebugMessage(); + + if (IsExitConditionSatisfied()) { + DVLOG(1) << "Await -> Exit before waiting: " << GetDebugMessage(); + return; + } + + fake_server_->AddObserver(this); + StartBlockingWait(); + fake_server_->RemoveObserver(this); +} + +void FakeServerMatchStatusChecker::OnCommit( + const std::string& committer_id, + syncer::ModelTypeSet committed_model_types) { + CheckExitCondition(); +} + +fake_server::FakeServer* FakeServerMatchStatusChecker::fake_server() const { + return fake_server_; +} + +} // namespace fake_server
diff --git a/chrome/browser/sync/test/integration/fake_server_match_status_checker.h b/chrome/browser/sync/test/integration/fake_server_match_status_checker.h new file mode 100644 index 0000000..02f0ae3 --- /dev/null +++ b/chrome/browser/sync/test/integration/fake_server_match_status_checker.h
@@ -0,0 +1,36 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_FAKE_SERVER_MATCH_STATUS_CHECKER_H_ +#define CHROME_BROWSER_SYNC_TEST_INTEGRATION_FAKE_SERVER_MATCH_STATUS_CHECKER_H_ + +#include <string> + +#include "chrome/browser/sync/test/integration/status_change_checker.h" +#include "sync/internal_api/public/base/model_type.h" +#include "sync/test/fake_server/fake_server.h" + +namespace fake_server { + +// A matcher that checks a generic condition against the fake server. This class +// is abstract where any subclass will be responsible for implementing some of +// StatusChangeChecker's virtual methods. +class FakeServerMatchStatusChecker : public StatusChangeChecker, + public FakeServer::Observer { + public: + FakeServerMatchStatusChecker(); + void Wait(); + void OnCommit(const std::string& committer_id, + syncer::ModelTypeSet committed_model_types) override; + + protected: + FakeServer* fake_server() const; + + private: + FakeServer* fake_server_; +}; + +} // namespace fake_server + +#endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_FAKE_SERVER_MATCH_STATUS_CHECKER_H_
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.cc b/chrome/browser/sync/test/integration/sync_integration_test_util.cc index c84e948..896d969e 100644 --- a/chrome/browser/sync/test/integration/sync_integration_test_util.cc +++ b/chrome/browser/sync/test/integration/sync_integration_test_util.cc
@@ -4,11 +4,40 @@ #include "chrome/browser/sync/test/integration/sync_integration_test_util.h" +#include <string> + +#include "base/strings/stringprintf.h" +#include "chrome/browser/sync/test/integration/fake_server_match_status_checker.h" #include "chrome/browser/sync/test/integration/single_client_status_change_checker.h" #include "chrome/browser/sync/test/integration/updated_progress_marker_checker.h" #include "components/browser_sync/browser/profile_sync_service.h" -namespace sync_integration_test_util { +namespace { + +// Helper class to block until the server has a given number of entities. +class ServerCountMatchStatusChecker + : public fake_server::FakeServerMatchStatusChecker { + public: + ServerCountMatchStatusChecker(syncer::ModelType type, size_t count) + : type_(type), count_(count) {} + ~ServerCountMatchStatusChecker() override {} + + bool IsExitConditionSatisfied() override { + return count_ == fake_server()->GetSyncEntitiesByModelType(type_).size(); + } + + std::string GetDebugMessage() const override { + return base::StringPrintf( + "Waiting for fake server entity count %zu to match expected count %zu " + "for type %d", + (size_t)fake_server()->GetSyncEntitiesByModelType(type_).size(), count_, + type_); + } + + private: + const syncer::ModelType type_; + const size_t count_; +}; class PassphraseRequiredChecker : public SingleClientStatusChangeChecker { public: @@ -35,6 +64,10 @@ std::string GetDebugMessage() const override { return "Passhrase Accepted"; } }; +} // namespace + +namespace sync_integration_test_util { + bool AwaitPassphraseRequired(ProfileSyncService* service) { PassphraseRequiredChecker checker(service); checker.Wait(); @@ -53,4 +86,10 @@ return !checker.TimedOut(); } +bool AwaitServerCount(syncer::ModelType type, size_t count) { + ServerCountMatchStatusChecker checker(type, count); + checker.Wait(); + return !checker.TimedOut(); +} + } // namespace sync_integration_test_util
diff --git a/chrome/browser/sync/test/integration/sync_integration_test_util.h b/chrome/browser/sync/test/integration/sync_integration_test_util.h index db43c96..fcbd2227 100644 --- a/chrome/browser/sync/test/integration/sync_integration_test_util.h +++ b/chrome/browser/sync/test/integration/sync_integration_test_util.h
@@ -5,8 +5,14 @@ #ifndef CHROME_BROWSER_SYNC_TEST_INTEGRATION_SYNC_INTEGRATION_TEST_UTIL_H_ #define CHROME_BROWSER_SYNC_TEST_INTEGRATION_SYNC_INTEGRATION_TEST_UTIL_H_ +#include "sync/internal_api/public/base/model_type.h" + class ProfileSyncService; +namespace fake_server { +class FakeServer; +} // namespace fake_server + namespace sync_integration_test_util { // Wait until the provided |service| is blocked waiting for a passphrase. @@ -19,6 +25,9 @@ // This can be a bit flaky. See UpdatedProgressMarkerChecker for details. bool AwaitCommitActivityCompletion(ProfileSyncService* service); +// Wait until the fake server has a specific count for the given type. +bool AwaitServerCount(syncer::ModelType type, size_t count); + } // namespace sync_integration_test_util #endif // CHROME_BROWSER_SYNC_TEST_INTEGRATION_SYNC_INTEGRATION_TEST_UTIL_H_
diff --git a/chrome/browser/sync/test/integration/two_client_dictionary_sync_test.cc b/chrome/browser/sync/test/integration/two_client_dictionary_sync_test.cc index 518dc99..85a4c8c0 100644 --- a/chrome/browser/sync/test/integration/two_client_dictionary_sync_test.cc +++ b/chrome/browser/sync/test/integration/two_client_dictionary_sync_test.cc
@@ -9,10 +9,12 @@ #include "chrome/browser/sync/test/integration/sync_integration_test_util.h" #include "chrome/browser/sync/test/integration/sync_test.h" #include "chrome/common/spellcheck_common.h" +#include "sync/internal_api/public/base/model_type.h" using chrome::spellcheck_common::MAX_SYNCABLE_DICTIONARY_WORDS; using dictionary_helper::AwaitNumDictionaryEntries; using sync_integration_test_util::AwaitCommitActivityCompletion; +using sync_integration_test_util::AwaitServerCount; class TwoClientDictionarySyncTest : public SyncTest { public: @@ -112,73 +114,46 @@ ASSERT_EQ(1UL, dictionary_helper::GetDictionarySize(0)); } -// Tests the case where the Nth client pushes the server beyond its +// Tests the case where a client has more words added than the // MAX_SYNCABLE_DICTIONARY_WORDS limit. -// Used to crash on Windows; now failing on Linux after conversion to -// 2-client test. See crbug.com/575316 -IN_PROC_BROWSER_TEST_F(TwoClientDictionarySyncTest, DISABLED_Limit) { +IN_PROC_BROWSER_TEST_F(TwoClientDictionarySyncTest, Limit) { ASSERT_TRUE(SetupSync()) << "SetupSync() failed."; dictionary_helper::LoadDictionaries(); ASSERT_TRUE(dictionary_helper::AwaitDictionariesMatch()); - const int n = num_clients(); + // Disable client #1 before client #0 starts adding anything. + GetClient(1)->DisableSyncForAllDatatypes(); - // Pick a number of initial words per client such that - // (num-clients()-1) * initial_words - // < MAX_SYNCABLE_DICTIONARY_WORDS - // < num_clients() * initial_words - size_t initial_words = - (MAX_SYNCABLE_DICTIONARY_WORDS + n) / n; + // Pick a size between 1/2 and 1/3 of MAX_SYNCABLE_DICTIONARY_WORDS. This will + // allow the test to verify that while we crossed the limit the client not + // actively making changes is still recieving sync updates but stops exactly + // on the limit. + size_t chunk_size = MAX_SYNCABLE_DICTIONARY_WORDS * 2 / 5; - // Add |initial_words| words to each of the clients before sync. - for (int i = 0; i < n; ++i) { - GetClient(i)->DisableSyncForAllDatatypes(); - for (size_t j = 0; j < initial_words; ++j) { - ASSERT_TRUE(dictionary_helper::AddWord( - i, "foo-" + base::IntToString(i) + "-" + base::Uint64ToString(j))); - } - ASSERT_EQ(initial_words, dictionary_helper::GetDictionarySize(i)); - } + ASSERT_TRUE(dictionary_helper::AddWords(0, chunk_size, "foo-0-")); + ASSERT_EQ(chunk_size, dictionary_helper::GetDictionarySize(0)); - // As long as we don't get involved in any race conditions where two clients - // are committing at once, we should be able to guarantee that the server has - // at most MAX_SYNCABLE_DICTIONARY_WORDS words. Every client will be able to - // sync these items. Clients are allowed to have more words if they're - // available locally, but they won't be able to commit any words once the - // server is full. - // - // As we enable clients one-by-one, all but the (N-1)th client should be able - // to commit all of their items. The last one will have some local data left - // over. + // We must wait for the server here. This test was originally an n-client test + // where n-1 clients waited to have the same state. We cannot do that on 2 + // clients because one needs to be disconnected during this process, because + // part of what we're testing is that when it comes online it pulls remote + // changes before pushing local changes, with the limit in mind. So we check + // the server count here to make sure client #0 is done pushing its changes + // out. In there real world there's a race condition here, if multiple clients + // are adding words simultaneously then we're go over the limit slightly, + // though we'd expect this to be relatively small. + AwaitServerCount(syncer::DICTIONARY, chunk_size); - // Open the floodgates. Allow N-1 clients to sync their items. - for (int i = 0; i < n-1; ++i) { - SCOPED_TRACE(i); + ASSERT_TRUE(dictionary_helper::AddWords(1, 2 * chunk_size, "foo-1-")); + ASSERT_EQ(2 * chunk_size, dictionary_helper::GetDictionarySize(1)); - // Client #i has |initial_words| words before sync. - ASSERT_EQ(initial_words, dictionary_helper::GetDictionarySize(i)); - ASSERT_TRUE(GetClient(i)->EnableSyncForAllDatatypes()); - } - - // Wait for clients to catch up. All should be in sync with the server - // and have exactly (initial_words * (N-1)) words in their dictionaries. - for (int i = 0; i < n-1; ++i) { - SCOPED_TRACE(i); - ASSERT_TRUE(AwaitNumDictionaryEntries(i, initial_words*(n-1))); - } - - // Add the client that has engough new words to cause an overflow. - ASSERT_EQ(initial_words, dictionary_helper::GetDictionarySize(n-1)); - ASSERT_TRUE(GetClient(n-1)->EnableSyncForAllDatatypes()); - - // The Nth client will receive the initial_words * (n-1) entries that were on - // the server. It will commit some of the entries it had locally. And it - // will have a few uncommittable items left over. - ASSERT_TRUE(AwaitNumDictionaryEntries(n-1, initial_words*n)); - - // Everyone else should be at the limit. - for (int i = 0; i < n-1; ++i) { - SCOPED_TRACE(i); - ASSERT_TRUE(AwaitNumDictionaryEntries(i, MAX_SYNCABLE_DICTIONARY_WORDS)); - } + // Client #1 should first pull remote changes, apply them, without capping at + // any sort of limit. This will cause client #1 to have 3 * chunk_size. When + // client #1 then tries to commit changes, that is when it obeys the limit + // and will cause client #0 to only see the limit worth of words. + ASSERT_TRUE(GetClient(1)->EnableSyncForAllDatatypes()); + ASSERT_TRUE(AwaitNumDictionaryEntries(1, 3 * chunk_size)); + ASSERT_TRUE( + AwaitServerCount(syncer::DICTIONARY, MAX_SYNCABLE_DICTIONARY_WORDS)); + ASSERT_TRUE(AwaitNumDictionaryEntries(0, MAX_SYNCABLE_DICTIONARY_WORDS)); }
diff --git a/chrome/browser/themes/theme_properties.cc b/chrome/browser/themes/theme_properties.cc index 9ae0149..55c751f 100644 --- a/chrome/browser/themes/theme_properties.cc +++ b/chrome/browser/themes/theme_properties.cc
@@ -90,12 +90,12 @@ // Default tints. const color_utils::HSL kDefaultTintButtons = { -1, -1, -1 }; -const color_utils::HSL kDefaultTintButtonsIncognito = { -1, -1, 0.85f }; +const color_utils::HSL kDefaultTintButtonsIncognito = { -1, -1, 0.85 }; const color_utils::HSL kDefaultTintFrame = { -1, -1, -1 }; -const color_utils::HSL kDefaultTintFrameInactive = { -1, -1, 0.75f }; -const color_utils::HSL kDefaultTintFrameIncognito = { -1, 0.2f, 0.35f }; -const color_utils::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3f, 0.6f }; -const color_utils::HSL kDefaultTintBackgroundTab = { -1, 0.5, 0.75 }; +const color_utils::HSL kDefaultTintFrameInactive = { -1, -1, 0.75 }; +const color_utils::HSL kDefaultTintFrameIncognito = { -1, 0.2, 0.35 }; +const color_utils::HSL kDefaultTintFrameIncognitoInactive = { -1, 0.3, 0.6 }; +const color_utils::HSL kDefaultTintBackgroundTab = { -1, -1, 0.75 }; // ---------------------------------------------------------------------------- // Defaults for properties which are not stored in the browser theme pack.
diff --git a/chrome/browser/themes/theme_service.cc b/chrome/browser/themes/theme_service.cc index 23117f9..5a18c2e8 100644 --- a/chrome/browser/themes/theme_service.cc +++ b/chrome/browser/themes/theme_service.cc
@@ -64,8 +64,6 @@ using extensions::UnloadedExtensionInfo; using ui::ResourceBundle; -typedef ThemeProperties Properties; - // The default theme if we haven't installed a theme yet or if we've clicked // the "Use Classic" button. const char ThemeService::kDefaultThemeID[] = ""; @@ -461,10 +459,10 @@ // of color IDs. int theme_supplier_id = id; if (otr) { - if (id == Properties::COLOR_FRAME) - theme_supplier_id = Properties::COLOR_FRAME_INCOGNITO; - else if (id == Properties::COLOR_FRAME_INACTIVE) - theme_supplier_id = Properties::COLOR_FRAME_INCOGNITO_INACTIVE; + if (id == ThemeProperties::COLOR_FRAME) + theme_supplier_id = ThemeProperties::COLOR_FRAME_INCOGNITO; + else if (id == ThemeProperties::COLOR_FRAME_INACTIVE) + theme_supplier_id = ThemeProperties::COLOR_FRAME_INCOGNITO_INACTIVE; } SkColor color; @@ -473,65 +471,66 @@ // For backward compat with older themes, some newer colors are generated from // older ones if they are missing. + const int kNtpText = ThemeProperties::COLOR_NTP_TEXT; + const int kLabelBackground = + ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND; switch (id) { - case Properties::COLOR_TOOLBAR_BUTTON_ICON: + case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON: return color_utils::HSLShift(gfx::kChromeIconGrey, - GetTint(Properties::TINT_BUTTONS, otr)); - case Properties::COLOR_TOOLBAR_BUTTON_ICON_INACTIVE: + GetTint(ThemeProperties::TINT_BUTTONS, otr)); + case ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON_INACTIVE: // The active color is overridden in Gtk2UI. - return SkColorSetA(GetColor(Properties::COLOR_TOOLBAR_BUTTON_ICON, otr), - 0x33); - case Properties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND: + return SkColorSetA( + GetColor(ThemeProperties::COLOR_TOOLBAR_BUTTON_ICON, otr), 0x33); + case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_BACKGROUND: if (UsingDefaultTheme()) break; return GetColor(ThemeProperties::COLOR_TOOLBAR, otr); - case Properties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR: + case ThemeProperties::COLOR_DETACHED_BOOKMARK_BAR_SEPARATOR: if (UsingDefaultTheme()) break; // Use 50% of bookmark text color as separator color. return SkColorSetA(GetColor(ThemeProperties::COLOR_BOOKMARK_TEXT, otr), 128); - case Properties::COLOR_NTP_SECTION_HEADER_TEXT: - return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT, otr), 0.30); - case Properties::COLOR_NTP_SECTION_HEADER_TEXT_HOVER: - return GetColor(Properties::COLOR_NTP_TEXT, otr); - case Properties::COLOR_NTP_SECTION_HEADER_RULE: - return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT, otr), 0.70); - case Properties::COLOR_NTP_SECTION_HEADER_RULE_LIGHT: - return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT, otr), 0.86); - case Properties::COLOR_NTP_TEXT_LIGHT: - return IncreaseLightness(GetColor(Properties::COLOR_NTP_TEXT, otr), 0.40); - case Properties::COLOR_TAB_THROBBER_SPINNING: - case Properties::COLOR_TAB_THROBBER_WAITING: { + case ThemeProperties::COLOR_NTP_SECTION_HEADER_TEXT: + return IncreaseLightness(GetColor(kNtpText, otr), 0.30); + case ThemeProperties::COLOR_NTP_SECTION_HEADER_TEXT_HOVER: + return GetColor(kNtpText, otr); + case ThemeProperties::COLOR_NTP_SECTION_HEADER_RULE: + return IncreaseLightness(GetColor(kNtpText, otr), 0.70); + case ThemeProperties::COLOR_NTP_SECTION_HEADER_RULE_LIGHT: + return IncreaseLightness(GetColor(kNtpText, otr), 0.86); + case ThemeProperties::COLOR_NTP_TEXT_LIGHT: + return IncreaseLightness(GetColor(kNtpText, otr), 0.40); + case ThemeProperties::COLOR_TAB_THROBBER_SPINNING: + case ThemeProperties::COLOR_TAB_THROBBER_WAITING: { SkColor base_color = - ui::GetAuraColor(id == Properties::COLOR_TAB_THROBBER_SPINNING + ui::GetAuraColor(id == ThemeProperties::COLOR_TAB_THROBBER_SPINNING ? ui::NativeTheme::kColorId_ThrobberSpinningColor : ui::NativeTheme::kColorId_ThrobberWaitingColor, nullptr); - color_utils::HSL hsl = GetTint(Properties::TINT_BUTTONS, otr); + color_utils::HSL hsl = GetTint(ThemeProperties::TINT_BUTTONS, otr); return color_utils::HSLShift(base_color, hsl); } #if defined(ENABLE_SUPERVISED_USERS) - case Properties::COLOR_SUPERVISED_USER_LABEL: - return color_utils::GetReadableColor( - SK_ColorWHITE, - GetColor(Properties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND, otr)); - case Properties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND: + case ThemeProperties::COLOR_SUPERVISED_USER_LABEL: + return color_utils::GetReadableColor(SK_ColorWHITE, + GetColor(kLabelBackground, otr)); + case ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND: return color_utils::BlendTowardOppositeLuminance( - GetColor(Properties::COLOR_FRAME, otr), 0x80); - case Properties::COLOR_SUPERVISED_USER_LABEL_BORDER: - return color_utils::AlphaBlend( - GetColor(Properties::COLOR_SUPERVISED_USER_LABEL_BACKGROUND, otr), - SK_ColorBLACK, 230); + GetColor(ThemeProperties::COLOR_FRAME, otr), 0x80); + case ThemeProperties::COLOR_SUPERVISED_USER_LABEL_BORDER: + return color_utils::AlphaBlend(GetColor(kLabelBackground, otr), + SK_ColorBLACK, 230); #endif - case Properties::COLOR_STATUS_BAR_TEXT: { + case ThemeProperties::COLOR_STATUS_BAR_TEXT: { // A long time ago, we blended the toolbar and the tab text together to // get the status bar text because, at the time, our text rendering in // views couldn't do alpha blending. Even though this is no longer the // case, this blending decision is built into the majority of themes that // exist, and we must keep doing it. - SkColor toolbar_color = GetColor(Properties::COLOR_TOOLBAR, otr); - SkColor text_color = GetColor(Properties::COLOR_TAB_TEXT, otr); + SkColor toolbar_color = GetColor(ThemeProperties::COLOR_TOOLBAR, otr); + SkColor text_color = GetColor(ThemeProperties::COLOR_TAB_TEXT, otr); return SkColorSetARGB( SkColorGetA(text_color), (SkColorGetR(text_color) + SkColorGetR(toolbar_color)) / 2, @@ -540,7 +539,7 @@ } } - return Properties::GetDefaultColor(id, otr); + return ThemeProperties::GetDefaultColor(id, otr); } int ThemeService::GetDisplayProperty(int id) const { @@ -550,19 +549,20 @@ } switch (id) { - case Properties::NTP_BACKGROUND_ALIGNMENT: - return Properties::ALIGN_CENTER; + case ThemeProperties::NTP_BACKGROUND_ALIGNMENT: + return ThemeProperties::ALIGN_CENTER; - case Properties::NTP_BACKGROUND_TILING: - return Properties::NO_REPEAT; + case ThemeProperties::NTP_BACKGROUND_TILING: + return ThemeProperties::NO_REPEAT; - case Properties::NTP_LOGO_ALTERNATE: - return UsingDefaultTheme() || UsingSystemTheme() || - (!HasCustomImage(IDR_THEME_NTP_BACKGROUND) && - IsColorGrayscale( - GetColor(Properties::COLOR_NTP_BACKGROUND, false))) - ? 0 - : 1; + case ThemeProperties::NTP_LOGO_ALTERNATE: { + if (UsingDefaultTheme() || UsingSystemTheme()) + return 0; + if (HasCustomImage(IDR_THEME_NTP_BACKGROUND)) + return 1; + return IsColorGrayscale( + GetColor(ThemeProperties::COLOR_NTP_BACKGROUND, false)) ? 0 : 1; + } default: return -1; @@ -588,7 +588,7 @@ int id, ui::ScaleFactor scale_factor) const { // Check to see whether we should substitute some images. - int ntp_alternate = GetDisplayProperty(Properties::NTP_LOGO_ALTERNATE); + int ntp_alternate = GetDisplayProperty(ThemeProperties::NTP_LOGO_ALTERNATE); if (id == IDR_PRODUCT_LOGO && ntp_alternate != 0) id = IDR_PRODUCT_LOGO_WHITE;
diff --git a/chrome/browser/ui/website_settings/website_settings.cc b/chrome/browser/ui/website_settings/website_settings.cc index 6f817da7..773a552 100644 --- a/chrome/browser/ui/website_settings/website_settings.cc +++ b/chrome/browser/ui/website_settings/website_settings.cc
@@ -31,6 +31,8 @@ #include "chrome/browser/history/history_service_factory.h" #include "chrome/browser/infobars/infobar_service.h" #include "chrome/browser/permissions/chooser_context_base.h" +#include "chrome/browser/permissions/permission_uma_util.h" +#include "chrome/browser/permissions/permission_util.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ssl/chrome_ssl_host_state_delegate.h" #include "chrome/browser/ssl/chrome_ssl_host_state_delegate_factory.h" @@ -54,6 +56,7 @@ #include "components/url_formatter/elide_url.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/cert_store.h" +#include "content/public/browser/permission_type.h" #include "content/public/browser/user_metrics.h" #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" @@ -262,26 +265,6 @@ } } -// Get corresponding Rappor Metric. TODO(raymes): This should use the same -// code that's in permission_context_uma_util.cc. Figure out how to do that. -// crbug.com/544745. -const std::string GetRapporMetric(ContentSettingsType permission) { - std::string permission_str; - - if (permission == CONTENT_SETTINGS_TYPE_GEOLOCATION) { - permission_str = "Geolocation"; - } else if (permission == CONTENT_SETTINGS_TYPE_NOTIFICATIONS) { - permission_str = "Notifications"; - } else if (permission == CONTENT_SETTINGS_TYPE_MEDIASTREAM_MIC) { - permission_str = "Mic"; - } else if (permission == CONTENT_SETTINGS_TYPE_MEDIASTREAM_CAMERA) { - permission_str = "Camera"; - } - - return base::StringPrintf("ContentSettings.PermissionActions_%s.Revoked.Url", - permission_str.c_str()); -} - void WebsiteSettings::OnSitePermissionChanged(ContentSettingsType type, ContentSetting setting) { // Count how often a permission for a specific content type is changed using @@ -300,10 +283,10 @@ "WebsiteSettings.OriginInfo.PermissionChanged.Blocked", histogram_value, num_values); // Trigger Rappor sampling if it is a permission revoke action. - const std::string& rappor_metric = GetRapporMetric(type); - if (!rappor_metric.empty()) { - rappor::SampleDomainAndRegistryFromGURL( - g_browser_process->rappor_service(), rappor_metric, this->site_url_); + content::PermissionType permission_type; + if (PermissionUtil::GetPermissionType(type, &permission_type)) { + PermissionUmaUtil::PermissionRevoked(permission_type, + this->site_url_); } }
diff --git a/chrome/browser/ui/webui/options/autofill_options_handler.cc b/chrome/browser/ui/webui/options/autofill_options_handler.cc index 28fb030..388ad27 100644 --- a/chrome/browser/ui/webui/options/autofill_options_handler.cc +++ b/chrome/browser/ui/webui/options/autofill_options_handler.cc
@@ -23,7 +23,6 @@ #include "chrome/browser/autofill/personal_data_manager_factory.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/profiles/profile.h" -#include "chrome/browser/sync/profile_sync_service_factory.h" #include "chrome/browser/ui/autofill/country_combobox_model.h" #include "chrome/common/url_constants.h" #include "chrome/grit/chromium_strings.h" @@ -210,9 +209,7 @@ namespace options { -AutofillOptionsHandler::AutofillOptionsHandler() - : personal_data_(NULL), observer_(this) { -} +AutofillOptionsHandler::AutofillOptionsHandler() : personal_data_(NULL) {} AutofillOptionsHandler::~AutofillOptionsHandler() { if (personal_data_) @@ -239,7 +236,6 @@ { "editAddressTitle", IDS_AUTOFILL_EDIT_ADDRESS_CAPTION }, { "addCreditCardTitle", IDS_AUTOFILL_ADD_CREDITCARD_CAPTION }, { "editCreditCardTitle", IDS_AUTOFILL_EDIT_CREDITCARD_CAPTION }, - { "autofillWalletOption", IDS_AUTOFILL_USE_WALLET_DATA }, }; RegisterStrings(localized_strings, resources, arraysize(resources)); @@ -260,18 +256,6 @@ localized_strings->SetString( "manageWalletPaymentMethodsUrl", autofill::wallet::GetManageInstrumentsUrl(0).spec()); - - // This is set in loadTimeData to minimize the chance of a load-time flash of - // content. - ProfileSyncService* service = - ProfileSyncServiceFactory::GetInstance()->GetForProfile( - Profile::FromWebUI(web_ui())); - if (service) - observer_.Add(service); - - localized_strings->SetBoolean("autofillWalletIntegrationAvailable", - autofill::WalletIntegrationAvailableForProfile( - Profile::FromWebUI(web_ui()))); } void AutofillOptionsHandler::InitializeHandler() { @@ -283,10 +267,6 @@ void AutofillOptionsHandler::InitializePage() { if (personal_data_) LoadAutofillData(); - - // Also update the visibility of the Wallet checkbox (which may have - // changed since the localized string dictionary was built). - OnStateChanged(); } void AutofillOptionsHandler::RegisterMessages() { @@ -323,14 +303,6 @@ // PersonalDataManagerObserver implementation: void AutofillOptionsHandler::OnPersonalDataChanged() { LoadAutofillData(); - OnStateChanged(); -} - -void AutofillOptionsHandler::OnStateChanged() { - web_ui()->CallJavascriptFunction( - "AutofillOptions.walletIntegrationAvailableStateChanged", - base::FundamentalValue(autofill::WalletIntegrationAvailableForProfile( - Profile::FromWebUI(web_ui())))); } void AutofillOptionsHandler::SetAddressOverlayStrings(
diff --git a/chrome/browser/ui/webui/options/autofill_options_handler.h b/chrome/browser/ui/webui/options/autofill_options_handler.h index 58d51e9..ef00b3e 100644 --- a/chrome/browser/ui/webui/options/autofill_options_handler.h +++ b/chrome/browser/ui/webui/options/autofill_options_handler.h
@@ -13,8 +13,6 @@ #include "base/scoped_observer.h" #include "chrome/browser/ui/webui/options/options_ui.h" #include "components/autofill/core/browser/personal_data_manager_observer.h" -#include "components/browser_sync/browser/profile_sync_service.h" -#include "components/sync_driver/sync_service_observer.h" namespace autofill { class AutofillProfile; @@ -29,8 +27,7 @@ namespace options { class AutofillOptionsHandler : public OptionsPageUIHandler, - public autofill::PersonalDataManagerObserver, - public sync_driver::SyncServiceObserver { + public autofill::PersonalDataManagerObserver { public: AutofillOptionsHandler(); ~AutofillOptionsHandler() override; @@ -44,9 +41,6 @@ // PersonalDataManagerObserver implementation. void OnPersonalDataChanged() override; - // sync_driver::SyncServiceObserver implementation. - void OnStateChanged() override; - private: FRIEND_TEST_ALL_PREFIXES(AutofillOptionsHandlerTest, AddressToDictionary); @@ -112,9 +106,6 @@ // Unowned pointer, may not be NULL. autofill::PersonalDataManager* personal_data_; - ScopedObserver<ProfileSyncService, sync_driver::SyncServiceObserver> - observer_; - DISALLOW_COPY_AND_ASSIGN(AutofillOptionsHandler); };
diff --git a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc index 0ece958..a111747 100644 --- a/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/display_options_handler.cc
@@ -9,7 +9,7 @@ #include <string> -#include "ash/display/display_configurator_animation.h" +#include "ash/display/display_animator.h" #include "ash/display/display_manager.h" #include "ash/display/resolution_notification_controller.h" #include "ash/display/window_tree_host_manager.h" @@ -350,8 +350,7 @@ int position, int offset) { SetCurrentDisplayLayout( ash::DisplayLayout::FromInts(position, offset)); - ash::Shell::GetInstance()->display_configurator_animation()-> - StartFadeInAnimation(); + ash::Shell::GetInstance()->display_animator()->StartFadeInAnimation(); } void DisplayOptionsHandler::HandleDisplayInfo( @@ -365,11 +364,9 @@ base::UserMetricsAction("Options_DisplayToggleMirroring")); bool is_mirroring = false; args->GetBoolean(0, &is_mirroring); - ash::Shell::GetInstance()->display_configurator_animation()-> - StartFadeOutAnimation(base::Bind( - &DisplayOptionsHandler::OnFadeOutForMirroringFinished, - base::Unretained(this), - is_mirroring)); + ash::Shell::GetInstance()->display_animator()->StartFadeOutAnimation( + base::Bind(&DisplayOptionsHandler::OnFadeOutForMirroringFinished, + base::Unretained(this), is_mirroring)); } void DisplayOptionsHandler::HandleSetPrimary(const base::ListValue* args) { @@ -394,12 +391,10 @@ DCHECK_LE(ash::DisplayLayout::TOP, layout); DCHECK_GE(ash::DisplayLayout::LEFT, layout); content::RecordAction(base::UserMetricsAction("Options_DisplayRearrange")); - ash::Shell::GetInstance()->display_configurator_animation()-> - StartFadeOutAnimation(base::Bind( - &DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished, - base::Unretained(this), - static_cast<int>(layout), - static_cast<int>(offset))); + ash::Shell::GetInstance()->display_animator()->StartFadeOutAnimation( + base::Bind(&DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished, + base::Unretained(this), static_cast<int>(layout), + static_cast<int>(offset))); } void DisplayOptionsHandler::HandleSetDisplayMode(const base::ListValue* args) {
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler.cc b/chrome/browser/ui/webui/options/sync_setup_handler.cc index 6c7dac3b..639f068 100644 --- a/chrome/browser/ui/webui/options/sync_setup_handler.cc +++ b/chrome/browser/ui/webui/options/sync_setup_handler.cc
@@ -39,6 +39,8 @@ #include "chrome/grit/chromium_strings.h" #include "chrome/grit/generated_resources.h" #include "chrome/grit/locale_settings.h" +#include "components/autofill/core/common/autofill_constants.h" +#include "components/autofill/core/common/autofill_pref_names.h" #include "components/browser_sync/browser/profile_sync_service.h" #include "components/google/core/browser/google_util.h" #include "components/signin/core/browser/signin_error_controller.h" @@ -76,6 +78,7 @@ bool sync_everything; bool sync_nothing; syncer::ModelTypeSet data_types; + bool payments_integration_enabled; std::string passphrase; bool passphrase_is_gaia; }; @@ -84,8 +87,8 @@ : encrypt_all(false), sync_everything(false), sync_nothing(false), - passphrase_is_gaia(false) { -} + payments_integration_enabled(false), + passphrase_is_gaia(false) {} SyncConfigInfo::~SyncConfigInfo() {} @@ -110,6 +113,13 @@ DCHECK(!(config->sync_everything && config->sync_nothing)) << "syncAllDataTypes and syncNothing cannot both be true"; + if (!result->GetBoolean("paymentsIntegrationEnabled", + &config->payments_integration_enabled)) { + DLOG(ERROR) << "GetConfiguration() not passed a paymentsIntegrationEnabled " + << "value"; + return false; + } + syncer::ModelTypeNameMap type_names = syncer::GetUserSelectableTypeNameMap(); for (syncer::ModelTypeNameMap::const_iterator it = type_names.begin(); @@ -180,6 +190,7 @@ localized_strings->SetString( "chooseDataTypesInstructions", GetStringFUTF16(IDS_SYNC_CHOOSE_DATATYPES_INSTRUCTIONS, product_name)); + localized_strings->SetString("autofillHelpURL", autofill::kHelpURL); localized_strings->SetString( "encryptionInstructions", GetStringFUTF16(IDS_SYNC_ENCRYPTION_INSTRUCTIONS, product_name)); @@ -218,56 +229,57 @@ "syncErrorHelpURL", chrome::kSyncErrorsHelpURL); static OptionsStringResource resources[] = { - { "syncSetupConfigureTitle", IDS_SYNC_SETUP_CONFIGURE_TITLE }, - { "syncSetupSpinnerTitle", IDS_SYNC_SETUP_SPINNER_TITLE }, - { "syncSetupTimeoutTitle", IDS_SYNC_SETUP_TIME_OUT_TITLE }, - { "syncSetupTimeoutContent", IDS_SYNC_SETUP_TIME_OUT_CONTENT }, - { "errorLearnMore", IDS_LEARN_MORE }, - { "cancel", IDS_CANCEL }, - { "loginSuccess", IDS_SYNC_SUCCESS }, - { "settingUp", IDS_SYNC_LOGIN_SETTING_UP }, - { "syncAllDataTypes", IDS_SYNC_EVERYTHING }, - { "chooseDataTypes", IDS_SYNC_CHOOSE_DATATYPES }, - { "syncNothing", IDS_SYNC_NOTHING }, - { "bookmarks", IDS_SYNC_DATATYPE_BOOKMARKS }, - { "preferences", IDS_SYNC_DATATYPE_PREFERENCES }, - { "autofill", IDS_SYNC_DATATYPE_AUTOFILL }, - { "themes", IDS_SYNC_DATATYPE_THEMES }, - { "passwords", IDS_SYNC_DATATYPE_PASSWORDS }, - { "extensions", IDS_SYNC_DATATYPE_EXTENSIONS }, - { "typedURLs", IDS_SYNC_DATATYPE_TYPED_URLS }, - { "apps", IDS_SYNC_DATATYPE_APPS }, - { "wifiCredentials", IDS_SYNC_DATATYPE_WIFI_CREDENTIALS }, - { "openTabs", IDS_SYNC_DATATYPE_TABS }, - { "serviceUnavailableError", IDS_SYNC_SETUP_ABORTED_BY_PENDING_CLEAR }, - { "confirmLabel", IDS_SYNC_CONFIRM_PASSPHRASE_LABEL }, - { "emptyErrorMessage", IDS_SYNC_EMPTY_PASSPHRASE_ERROR }, - { "mismatchErrorMessage", IDS_SYNC_PASSPHRASE_MISMATCH_ERROR }, - { "customizeLinkLabel", IDS_SYNC_CUSTOMIZE_LINK_LABEL }, - { "confirmSyncPreferences", IDS_SYNC_CONFIRM_SYNC_PREFERENCES }, - { "syncEverything", IDS_SYNC_SYNC_EVERYTHING }, - { "useDefaultSettings", IDS_SYNC_USE_DEFAULT_SETTINGS }, - { "enterPassphraseBody", IDS_SYNC_ENTER_PASSPHRASE_BODY }, - { "enterGooglePassphraseBody", IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY }, - { "passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL }, - { "incorrectPassphrase", IDS_SYNC_INCORRECT_PASSPHRASE }, - { "passphraseWarning", IDS_SYNC_PASSPHRASE_WARNING }, - { "yes", IDS_SYNC_PASSPHRASE_CANCEL_YES }, - { "no", IDS_SYNC_PASSPHRASE_CANCEL_NO }, - { "sectionExplicitMessagePrefix", IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_PREFIX }, - { "sectionExplicitMessagePostfix", - IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_POSTFIX }, - // TODO(rogerta): browser/resource/sync_promo/sync_promo.html and related - // file may not be needed any more. If not, then the following promo - // strings can also be removed. - { "promoPageTitle", IDS_SYNC_PROMO_TAB_TITLE }, - { "promoSkipButton", IDS_SYNC_PROMO_SKIP_BUTTON }, - { "promoAdvanced", IDS_SYNC_PROMO_ADVANCED }, - { "promoLearnMore", IDS_LEARN_MORE }, - { "promoTitleShort", IDS_SYNC_PROMO_MESSAGE_TITLE_SHORT }, - { "encryptionSectionTitle", IDS_SYNC_ENCRYPTION_SECTION_TITLE }, - { "basicEncryptionOption", IDS_SYNC_BASIC_ENCRYPTION_DATA }, - { "fullEncryptionOption", IDS_SYNC_FULL_ENCRYPTION_DATA }, + {"syncSetupConfigureTitle", IDS_SYNC_SETUP_CONFIGURE_TITLE}, + {"syncSetupSpinnerTitle", IDS_SYNC_SETUP_SPINNER_TITLE}, + {"syncSetupTimeoutTitle", IDS_SYNC_SETUP_TIME_OUT_TITLE}, + {"syncSetupTimeoutContent", IDS_SYNC_SETUP_TIME_OUT_CONTENT}, + {"errorLearnMore", IDS_LEARN_MORE}, + {"cancel", IDS_CANCEL}, + {"loginSuccess", IDS_SYNC_SUCCESS}, + {"settingUp", IDS_SYNC_LOGIN_SETTING_UP}, + {"syncAllDataTypes", IDS_SYNC_EVERYTHING}, + {"chooseDataTypes", IDS_SYNC_CHOOSE_DATATYPES}, + {"syncNothing", IDS_SYNC_NOTHING}, + {"bookmarks", IDS_SYNC_DATATYPE_BOOKMARKS}, + {"preferences", IDS_SYNC_DATATYPE_PREFERENCES}, + {"autofill", IDS_SYNC_DATATYPE_AUTOFILL}, + {"themes", IDS_SYNC_DATATYPE_THEMES}, + {"passwords", IDS_SYNC_DATATYPE_PASSWORDS}, + {"extensions", IDS_SYNC_DATATYPE_EXTENSIONS}, + {"typedURLs", IDS_SYNC_DATATYPE_TYPED_URLS}, + {"apps", IDS_SYNC_DATATYPE_APPS}, + {"wifiCredentials", IDS_SYNC_DATATYPE_WIFI_CREDENTIALS}, + {"openTabs", IDS_SYNC_DATATYPE_TABS}, + {"enablePaymentsIntegration", IDS_AUTOFILL_USE_PAYMENTS_DATA}, + {"serviceUnavailableError", IDS_SYNC_SETUP_ABORTED_BY_PENDING_CLEAR}, + {"confirmLabel", IDS_SYNC_CONFIRM_PASSPHRASE_LABEL}, + {"emptyErrorMessage", IDS_SYNC_EMPTY_PASSPHRASE_ERROR}, + {"mismatchErrorMessage", IDS_SYNC_PASSPHRASE_MISMATCH_ERROR}, + {"customizeLinkLabel", IDS_SYNC_CUSTOMIZE_LINK_LABEL}, + {"confirmSyncPreferences", IDS_SYNC_CONFIRM_SYNC_PREFERENCES}, + {"syncEverything", IDS_SYNC_SYNC_EVERYTHING}, + {"useDefaultSettings", IDS_SYNC_USE_DEFAULT_SETTINGS}, + {"enterPassphraseBody", IDS_SYNC_ENTER_PASSPHRASE_BODY}, + {"enterGooglePassphraseBody", IDS_SYNC_ENTER_GOOGLE_PASSPHRASE_BODY}, + {"passphraseLabel", IDS_SYNC_PASSPHRASE_LABEL}, + {"incorrectPassphrase", IDS_SYNC_INCORRECT_PASSPHRASE}, + {"passphraseWarning", IDS_SYNC_PASSPHRASE_WARNING}, + {"yes", IDS_SYNC_PASSPHRASE_CANCEL_YES}, + {"no", IDS_SYNC_PASSPHRASE_CANCEL_NO}, + {"sectionExplicitMessagePrefix", IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_PREFIX}, + {"sectionExplicitMessagePostfix", + IDS_SYNC_PASSPHRASE_MSG_EXPLICIT_POSTFIX}, + // TODO(rogerta): browser/resource/sync_promo/sync_promo.html and related + // file may not be needed any more. If not, then the following promo + // strings can also be removed. + {"promoPageTitle", IDS_SYNC_PROMO_TAB_TITLE}, + {"promoSkipButton", IDS_SYNC_PROMO_SKIP_BUTTON}, + {"promoAdvanced", IDS_SYNC_PROMO_ADVANCED}, + {"promoLearnMore", IDS_LEARN_MORE}, + {"promoTitleShort", IDS_SYNC_PROMO_MESSAGE_TITLE_SHORT}, + {"encryptionSectionTitle", IDS_SYNC_ENCRYPTION_SECTION_TITLE}, + {"basicEncryptionOption", IDS_SYNC_BASIC_ENCRYPTION_DATA}, + {"fullEncryptionOption", IDS_SYNC_FULL_ENCRYPTION_DATA}, }; RegisterStrings(localized_strings, resources, arraysize(resources)); @@ -568,6 +580,10 @@ service->OnUserChoseDatatypes(configuration.sync_everything, configuration.data_types); + PrefService* pref_service = GetProfile()->GetPrefs(); + pref_service->SetBoolean(autofill::prefs::kAutofillWalletImportEnabled, + configuration.payments_integration_enabled); + // Need to call IsPassphraseRequiredForDecryption() *after* calling // OnUserChoseDatatypes() because the user may have just disabled the // encrypted datatypes (in which case we just want to exit, not prompt the @@ -845,6 +861,7 @@ // syncNothing: true if the user wants to sync nothing // <data_type>Registered: true if the associated data type is supported // <data_type>Synced: true if the user wants to sync that specific data type + // paymentsIntegrationEnabled: true if the user wants Payments integration // encryptionEnabled: true if sync supports encryption // encryptAllData: true if user wants to encrypt all data (not just // passwords) @@ -868,10 +885,14 @@ // TODO(treib): How do we want to handle pref groups, i.e. when only some of // the sync types behind a checkbox are force-enabled? crbug.com/403326 } - sync_driver::SyncPrefs sync_prefs(GetProfile()->GetPrefs()); + PrefService* pref_service = GetProfile()->GetPrefs(); + sync_driver::SyncPrefs sync_prefs(pref_service); args.SetBoolean("passphraseFailed", passphrase_failed); args.SetBoolean("syncAllDataTypes", sync_prefs.HasKeepEverythingSynced()); args.SetBoolean("syncNothing", false); // Always false during initial setup. + args.SetBoolean( + "paymentsIntegrationEnabled", + pref_service->GetBoolean(autofill::prefs::kAutofillWalletImportEnabled)); args.SetBoolean("encryptAllData", service->IsEncryptEverythingEnabled()); args.SetBoolean("encryptAllDataAllowed", service->IsEncryptEverythingAllowed());
diff --git a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc index 7aeb5f1..7fcc635 100644 --- a/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc +++ b/chrome/browser/ui/webui/options/sync_setup_handler_unittest.cc
@@ -67,6 +67,11 @@ ENCRYPT_PASSWORDS }; +enum PaymentsIntegrationConfig { + PAYMENTS_INTEGRATION_ENABLED, + PAYMENTS_INTEGRATION_DISABLED +}; + // Create a json-format string with the key/value pairs appropriate for a call // to HandleConfigure(). If |extra_values| is non-null, then the values from // the passed dictionary are added to the json. @@ -74,7 +79,8 @@ SyncAllDataConfig sync_all, syncer::ModelTypeSet types, const std::string& passphrase, - EncryptAllConfig encrypt_all) { + EncryptAllConfig encrypt_all, + PaymentsIntegrationConfig payments_integration) { base::DictionaryValue result; if (extra_values) result.MergeDictionary(extra_values); @@ -96,6 +102,8 @@ result.SetBoolean("typedUrlsSynced", types.Has(syncer::TYPED_URLS)); result.SetBoolean("wifiCredentialsSynced", types.Has(syncer::WIFI_CREDENTIALS)); + result.SetBoolean("paymentsIntegrationEnabled", + payments_integration == PAYMENTS_INTEGRATION_ENABLED); std::string args; base::JSONWriter::Write(result, &args); return args; @@ -518,8 +526,9 @@ #endif // #if !defined(OS_CHROMEOS) TEST_F(SyncSetupHandlerTest, TestSyncEverything) { - std::string args = GetConfiguration( - NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS); + std::string args = + GetConfiguration(NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), + ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption()) @@ -536,8 +545,9 @@ } TEST_F(SyncSetupHandlerTest, TestSyncNothing) { - std::string args = GetConfiguration( - NULL, SYNC_NOTHING, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS); + std::string args = + GetConfiguration(NULL, SYNC_NOTHING, GetAllTypes(), std::string(), + ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, RequestStop(ProfileSyncService::CLEAR_DATA)); @@ -551,8 +561,9 @@ } TEST_F(SyncSetupHandlerTest, TurnOnEncryptAll) { - std::string args = GetConfiguration( - NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_ALL_DATA); + std::string args = + GetConfiguration(NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), + ENCRYPT_ALL_DATA, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption()) @@ -572,8 +583,9 @@ } TEST_F(SyncSetupHandlerTest, TestPassphraseStillRequired) { - std::string args = GetConfiguration( - NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_PASSWORDS); + std::string args = + GetConfiguration(NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), + ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption()) @@ -595,11 +607,9 @@ TEST_F(SyncSetupHandlerTest, SuccessfullySetPassphrase) { base::DictionaryValue dict; dict.SetBoolean("isGooglePassphrase", true); - std::string args = GetConfiguration(&dict, - SYNC_ALL_DATA, - GetAllTypes(), - "gaiaPassphrase", - ENCRYPT_PASSWORDS); + std::string args = + GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(), "gaiaPassphrase", + ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); // Act as if an encryption passphrase is required the first time, then never @@ -622,11 +632,9 @@ TEST_F(SyncSetupHandlerTest, SelectCustomEncryption) { base::DictionaryValue dict; dict.SetBoolean("isGooglePassphrase", false); - std::string args = GetConfiguration(&dict, - SYNC_ALL_DATA, - GetAllTypes(), - "custom_passphrase", - ENCRYPT_PASSWORDS); + std::string args = + GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(), "custom_passphrase", + ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption()) @@ -649,11 +657,9 @@ TEST_F(SyncSetupHandlerTest, UnsuccessfullySetPassphrase) { base::DictionaryValue dict; dict.SetBoolean("isGooglePassphrase", true); - std::string args = GetConfiguration(&dict, - SYNC_ALL_DATA, - GetAllTypes(), - "invalid_passphrase", - ENCRYPT_PASSWORDS); + std::string args = GetConfiguration(&dict, SYNC_ALL_DATA, GetAllTypes(), + "invalid_passphrase", ENCRYPT_PASSWORDS, + PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption()) @@ -689,11 +695,9 @@ for (it = user_selectable_types.First(); it.Good(); it.Inc()) { syncer::ModelTypeSet type_to_set; type_to_set.Put(it.Get()); - std::string args = GetConfiguration(NULL, - CHOOSE_WHAT_TO_SYNC, - type_to_set, - std::string(), - ENCRYPT_PASSWORDS); + std::string args = + GetConfiguration(NULL, CHOOSE_WHAT_TO_SYNC, type_to_set, std::string(), + ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption()) @@ -712,11 +716,9 @@ } TEST_F(SyncSetupHandlerTest, TestSyncAllManually) { - std::string args = GetConfiguration(NULL, - CHOOSE_WHAT_TO_SYNC, - GetAllTypes(), - std::string(), - ENCRYPT_PASSWORDS); + std::string args = + GetConfiguration(NULL, CHOOSE_WHAT_TO_SYNC, GetAllTypes(), std::string(), + ENCRYPT_PASSWORDS, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption()) @@ -810,6 +812,7 @@ CheckBool(dictionary, "tabsRegistered", true); CheckBool(dictionary, "themesRegistered", true); CheckBool(dictionary, "typedUrlsRegistered", true); + CheckBool(dictionary, "paymentsIntegrationEnabled", true); CheckBool(dictionary, "showPassphrase", false); CheckBool(dictionary, "usePassphrase", false); CheckBool(dictionary, "passphraseFailed", false); @@ -954,8 +957,9 @@ } TEST_F(SyncSetupHandlerTest, TurnOnEncryptAllDisallowed) { - std::string args = GetConfiguration( - NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), ENCRYPT_ALL_DATA); + std::string args = + GetConfiguration(NULL, SYNC_ALL_DATA, GetAllTypes(), std::string(), + ENCRYPT_ALL_DATA, PAYMENTS_INTEGRATION_ENABLED); base::ListValue list_args; list_args.Append(new base::StringValue(args)); EXPECT_CALL(*mock_pss_, IsPassphraseRequiredForDecryption())
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index bd008e7..19309d9 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi
@@ -1492,6 +1492,8 @@ 'browser/sync/test/integration/extensions_helper.h', 'browser/sync/test/integration/fake_server_invalidation_service.cc', 'browser/sync/test/integration/fake_server_invalidation_service.h', + 'browser/sync/test/integration/fake_server_match_status_checker.cc', + 'browser/sync/test/integration/fake_server_match_status_checker.h', 'browser/sync/test/integration/migration_waiter.cc', 'browser/sync/test/integration/migration_waiter.h', 'browser/sync/test/integration/migration_watcher.cc',
diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index 2a8b57cf..a476f9a 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi
@@ -2983,6 +2983,7 @@ 'test_suite_name': 'unit_tests', 'isolate_file': 'unit_tests.isolate', 'android_manifest_path': 'test/android/unit_tests_apk/AndroidManifest.xml', + 'enable_multidex': 1, 'conditions': [ ['v8_use_external_startup_data==1', { 'asset_location': '<(PRODUCT_DIR)/unit_tests_apk/assets',
diff --git a/chrome/common/extensions/api/wallpaper_private.json b/chrome/common/extensions/api/wallpaper_private.json index b2b6c933..3df4f0c 100644 --- a/chrome/common/extensions/api/wallpaper_private.json +++ b/chrome/common/extensions/api/wallpaper_private.json
@@ -260,7 +260,23 @@ { "name": "onWallpaperChangedBy3rdParty", "type": "function", - "description": "This event is sent when the current wallpaper was set by a third party application." + "description": "This event is sent when the current wallpaper was set by a third party application.", + "parameters": [ + { + "type": "binary", + "name": "wallpaper", + "description": "The third party custom wallpaper data." + }, + { + "type": "binary", + "name": "thumbnail", + "description": "The third party custom wallpaper thumbnail data." + }, + { + "name": "layout", + "$ref": "wallpaper.WallpaperLayout" + } + ] } ] }
diff --git a/chrome/renderer/content_settings_observer.cc b/chrome/renderer/content_settings_observer.cc index 2a2ba4e..f90a0ca 100644 --- a/chrome/renderer/content_settings_observer.cc +++ b/chrome/renderer/content_settings_observer.cc
@@ -43,76 +43,53 @@ namespace { +// This enum is histogrammed, so do not add, reorder, or remove values. enum { INSECURE_CONTENT_DISPLAY = 0, - INSECURE_CONTENT_DISPLAY_HOST_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_WWW_GOOGLE, + INSECURE_CONTENT_DISPLAY_HOST_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_WWW_GOOGLE, // deprecated INSECURE_CONTENT_DISPLAY_HTML, INSECURE_CONTENT_RUN, - INSECURE_CONTENT_RUN_HOST_GOOGLE, - INSECURE_CONTENT_RUN_HOST_WWW_GOOGLE, - INSECURE_CONTENT_RUN_TARGET_YOUTUBE, + INSECURE_CONTENT_RUN_HOST_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_WWW_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_TARGET_YOUTUBE, // deprecated INSECURE_CONTENT_RUN_JS, INSECURE_CONTENT_RUN_CSS, INSECURE_CONTENT_RUN_SWF, - INSECURE_CONTENT_DISPLAY_HOST_YOUTUBE, - INSECURE_CONTENT_RUN_HOST_YOUTUBE, - INSECURE_CONTENT_RUN_HOST_GOOGLEUSERCONTENT, - INSECURE_CONTENT_DISPLAY_HOST_MAIL_GOOGLE, - INSECURE_CONTENT_RUN_HOST_MAIL_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_PLUS_GOOGLE, - INSECURE_CONTENT_RUN_HOST_PLUS_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_DOCS_GOOGLE, - INSECURE_CONTENT_RUN_HOST_DOCS_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_SITES_GOOGLE, - INSECURE_CONTENT_RUN_HOST_SITES_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_PICASAWEB_GOOGLE, - INSECURE_CONTENT_RUN_HOST_PICASAWEB_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_READER, - INSECURE_CONTENT_RUN_HOST_GOOGLE_READER, - INSECURE_CONTENT_DISPLAY_HOST_CODE_GOOGLE, - INSECURE_CONTENT_RUN_HOST_CODE_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_GROUPS_GOOGLE, - INSECURE_CONTENT_RUN_HOST_GROUPS_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_MAPS_GOOGLE, - INSECURE_CONTENT_RUN_HOST_MAPS_GOOGLE, - INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_SUPPORT, - INSECURE_CONTENT_RUN_HOST_GOOGLE_SUPPORT, - INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_INTL, - INSECURE_CONTENT_RUN_HOST_GOOGLE_INTL, + INSECURE_CONTENT_DISPLAY_HOST_YOUTUBE, // deprecated + INSECURE_CONTENT_RUN_HOST_YOUTUBE, // deprecated + INSECURE_CONTENT_RUN_HOST_GOOGLEUSERCONTENT, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_MAIL_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_MAIL_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_PLUS_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_PLUS_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_DOCS_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_DOCS_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_SITES_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_SITES_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_PICASAWEB_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_PICASAWEB_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_READER, // deprecated + INSECURE_CONTENT_RUN_HOST_GOOGLE_READER, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_CODE_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_CODE_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_GROUPS_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_GROUPS_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_MAPS_GOOGLE, // deprecated + INSECURE_CONTENT_RUN_HOST_MAPS_GOOGLE, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_SUPPORT, // deprecated + INSECURE_CONTENT_RUN_HOST_GOOGLE_SUPPORT, // deprecated + INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_INTL, // deprecated + INSECURE_CONTENT_RUN_HOST_GOOGLE_INTL, // deprecated INSECURE_CONTENT_NUM_EVENTS }; // Constants for UMA statistic collection. -static const char kWWWDotGoogleDotCom[] = "www.google.com"; -static const char kMailDotGoogleDotCom[] = "mail.google.com"; -static const char kPlusDotGoogleDotCom[] = "plus.google.com"; -static const char kDocsDotGoogleDotCom[] = "docs.google.com"; -static const char kSitesDotGoogleDotCom[] = "sites.google.com"; -static const char kPicasawebDotGoogleDotCom[] = "picasaweb.google.com"; -static const char kCodeDotGoogleDotCom[] = "code.google.com"; -static const char kGroupsDotGoogleDotCom[] = "groups.google.com"; -static const char kMapsDotGoogleDotCom[] = "maps.google.com"; -static const char kWWWDotYoutubeDotCom[] = "www.youtube.com"; -static const char kDotGoogleUserContentDotCom[] = ".googleusercontent.com"; -static const char kGoogleReaderPathPrefix[] = "/reader/"; -static const char kGoogleSupportPathPrefix[] = "/support/"; -static const char kGoogleIntlPathPrefix[] = "/intl/"; static const char kDotJS[] = ".js"; static const char kDotCSS[] = ".css"; static const char kDotSWF[] = ".swf"; static const char kDotHTML[] = ".html"; -// Constants for mixed-content blocking. -static const char kGoogleDotCom[] = "google.com"; - -static bool IsHostInDomain(const std::string& host, const std::string& domain) { - return (base::EndsWith(host, domain, base::CompareCase::INSENSITIVE_ASCII) && - (host.length() == domain.length() || - (host.length() > domain.length() && - host[host.length() - domain.length() - 1] == '.'))); -} - GURL GetOriginOrURL(const WebFrame* frame) { WebString top_origin = frame->top()->securityOrigin().toString(); // The |top_origin| is unique ("null") e.g., for file:// URLs. Use the @@ -466,49 +443,9 @@ bool ContentSettingsObserver::allowDisplayingInsecureContent( bool allowed_per_settings, - const blink::WebSecurityOrigin& origin, const blink::WebURL& resource_url) { SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY); - std::string origin_host(origin.host().utf8()); - WebFrame* frame = render_frame()->GetWebFrame(); - GURL frame_gurl(frame->document().url()); - if (IsHostInDomain(origin_host, kGoogleDotCom)) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE); - if (base::StartsWith(frame_gurl.path(), kGoogleSupportPathPrefix, - base::CompareCase::INSENSITIVE_ASCII)) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_SUPPORT); - } else if (base::StartsWith(frame_gurl.path(), kGoogleIntlPathPrefix, - base::CompareCase::INSENSITIVE_ASCII)) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_INTL); - } - } - - if (origin_host == kWWWDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_WWW_GOOGLE); - if (base::StartsWith(frame_gurl.path(), kGoogleReaderPathPrefix, - base::CompareCase::INSENSITIVE_ASCII)) - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GOOGLE_READER); - } else if (origin_host == kMailDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_MAIL_GOOGLE); - } else if (origin_host == kPlusDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_PLUS_GOOGLE); - } else if (origin_host == kDocsDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_DOCS_GOOGLE); - } else if (origin_host == kSitesDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_SITES_GOOGLE); - } else if (origin_host == kPicasawebDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_PICASAWEB_GOOGLE); - } else if (origin_host == kCodeDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_CODE_GOOGLE); - } else if (origin_host == kGroupsDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_GROUPS_GOOGLE); - } else if (origin_host == kMapsDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_MAPS_GOOGLE); - } else if (origin_host == kWWWDotYoutubeDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_DISPLAY_HOST_YOUTUBE); - } - GURL resource_gurl(resource_url); if (base::EndsWith(resource_gurl.path(), kDotHTML, base::CompareCase::INSENSITIVE_ASCII)) @@ -526,55 +463,7 @@ bool allowed_per_settings, const blink::WebSecurityOrigin& origin, const blink::WebURL& resource_url) { - std::string origin_host(origin.host().utf8()); - WebFrame* frame = render_frame()->GetWebFrame(); - GURL frame_gurl(frame->document().url()); - DCHECK_EQ(frame_gurl.host(), origin_host); - - bool is_google = IsHostInDomain(origin_host, kGoogleDotCom); - if (is_google) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE); - if (base::StartsWith(frame_gurl.path(), kGoogleSupportPathPrefix, - base::CompareCase::INSENSITIVE_ASCII)) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_SUPPORT); - } else if (base::StartsWith(frame_gurl.path(), kGoogleIntlPathPrefix, - base::CompareCase::INSENSITIVE_ASCII)) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_INTL); - } - } - - if (origin_host == kWWWDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_WWW_GOOGLE); - if (base::StartsWith(frame_gurl.path(), kGoogleReaderPathPrefix, - base::CompareCase::INSENSITIVE_ASCII)) - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLE_READER); - } else if (origin_host == kMailDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_MAIL_GOOGLE); - } else if (origin_host == kPlusDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_PLUS_GOOGLE); - } else if (origin_host == kDocsDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_DOCS_GOOGLE); - } else if (origin_host == kSitesDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_SITES_GOOGLE); - } else if (origin_host == kPicasawebDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_PICASAWEB_GOOGLE); - } else if (origin_host == kCodeDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_CODE_GOOGLE); - } else if (origin_host == kGroupsDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GROUPS_GOOGLE); - } else if (origin_host == kMapsDotGoogleDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_MAPS_GOOGLE); - } else if (origin_host == kWWWDotYoutubeDotCom) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_YOUTUBE); - } else if (base::EndsWith(origin_host, kDotGoogleUserContentDotCom, - base::CompareCase::INSENSITIVE_ASCII)) { - SendInsecureContentSignal(INSECURE_CONTENT_RUN_HOST_GOOGLEUSERCONTENT); - } - GURL resource_gurl(resource_url); - if (resource_gurl.host() == kWWWDotYoutubeDotCom) - SendInsecureContentSignal(INSECURE_CONTENT_RUN_TARGET_YOUTUBE); - if (base::EndsWith(resource_gurl.path(), kDotJS, base::CompareCase::INSENSITIVE_ASCII)) SendInsecureContentSignal(INSECURE_CONTENT_RUN_JS);
diff --git a/chrome/renderer/content_settings_observer.h b/chrome/renderer/content_settings_observer.h index b876a6c6..8e16686 100644 --- a/chrome/renderer/content_settings_observer.h +++ b/chrome/renderer/content_settings_observer.h
@@ -80,7 +80,6 @@ void didNotAllowScript() override; void didUseKeygen() override; bool allowDisplayingInsecureContent(bool allowed_per_settings, - const blink::WebSecurityOrigin& context, const blink::WebURL& url) override; bool allowRunningInsecureContent(bool allowed_per_settings, const blink::WebSecurityOrigin& context,
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index b000210e..28460c7 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -15,11 +15,6 @@ import("//build/config/android/rules.gni") } -declare_args() { - # TODO(GYP) http://crbug.com/462791 - enable_nacl_browsertests = false -} - # This target exists to reference other test executables to bring these files # into the build. group("test") { @@ -930,10 +925,6 @@ defines = [ "HAS_OUT_OF_PROC_TEST_RUNNER" ] - if (!enable_nacl_browsertests) { - defines += [ "DISABLE_NACL_BROWSERTESTS" ] - } - # TODO(GYP) if (is_win) { # ['incremental_chrome_dll==1', { # 'UseLibraryDependencyInputs': "true", @@ -947,9 +938,7 @@ if (!enable_one_click_signin) { sources -= [ "../browser/ui/sync/one_click_signin_bubble_links_delegate_browsertest.cc" ] } - if (!enable_nacl_browsertests) { - sources -= [ "../browser/extensions/api/hotword_private/hotword_private_apitest.cc" ] - } else if (enable_nacl) { + if (enable_nacl) { sources += [ "../browser/extensions/extension_nacl_browsertest.cc", "../browser/nacl_host/test/gdb_debug_stub_browsertest.cc", @@ -1219,7 +1208,7 @@ "../browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc", ] } - if (!is_android && !is_ios && enable_nacl_browsertests) { + if (!is_android && !is_ios) { sources += [ "../browser/copresence/chrome_whispernet_client_browsertest.cc" ] deps += [ "//components/copresence" ] @@ -1647,6 +1636,7 @@ android_manifest = "//chrome/test/android/unit_tests_apk/AndroidManifest.xml" + enable_multidex = true isolate_file = "../unit_tests.isolate" # Some android targets still depend on --gc-sections to link.
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java index 0361ece1..57b2776 100644 --- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java +++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/PrerenderTestHelper.java
@@ -4,23 +4,17 @@ package org.chromium.chrome.test.util; -import android.util.Pair; +import junit.framework.Assert; import org.chromium.base.ThreadUtils; -import org.chromium.chrome.R; import org.chromium.chrome.browser.TabLoadStatus; -import org.chromium.chrome.browser.omnibox.LocationBarLayout; -import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter; -import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxResultItem; -import org.chromium.chrome.browser.omnibox.OmniboxResultsAdapter.OmniboxSuggestionDelegate; -import org.chromium.chrome.browser.omnibox.OmniboxSuggestion; +import org.chromium.chrome.browser.prerender.ExternalPrerenderHandler; import org.chromium.chrome.browser.tab.Tab; import org.chromium.chrome.test.ChromeTabbedActivityTestBase; import org.chromium.content.browser.test.util.Criteria; import org.chromium.content.browser.test.util.CriteriaHelper; import java.util.concurrent.Callable; -import java.util.concurrent.atomic.AtomicReference; /** * Utility class for common methods to test prerendering. @@ -29,7 +23,6 @@ private static final int UI_DELAY_MS = 100; private static final int WAIT_FOR_RESPONSE_MS = 10000; private static final int SHORT_TIMEOUT_MS = 200; - private static final int MAX_NUM_REPEATS_FOR_TRAINING = 7; private static boolean hasTabPrerenderedUrl(final Tab tab, final String url) { return ThreadUtils.runOnUiThreadBlockingNoException(new Callable<Boolean>() { @@ -62,29 +55,6 @@ return hasTabPrerenderedUrl(tab, url); } - private static Pair<OmniboxSuggestion, Integer> waitForOmniboxSuggestion( - final LocationBarLayout locationBar, final String url) throws InterruptedException { - final AtomicReference<Pair<OmniboxSuggestion, Integer>> result = - new AtomicReference<Pair<OmniboxSuggestion, Integer>>(); - CriteriaHelper.pollForCriteria(new Criteria() { - @Override - public boolean isSatisfied() { - OmniboxResultsAdapter adapter = - (OmniboxResultsAdapter) locationBar.getSuggestionList().getAdapter(); - for (int i = 0; i < adapter.getCount(); i++) { - OmniboxResultItem popupItem = (OmniboxResultItem) adapter.getItem(i); - OmniboxSuggestion matchedSuggestion = popupItem.getSuggestion(); - if (matchedSuggestion.getUrl().equals(url)) { - result.set(new Pair<OmniboxSuggestion, Integer>(matchedSuggestion, i)); - return true; - } - } - return false; - } - }, SHORT_TIMEOUT_MS, UI_DELAY_MS); - return result.get(); - } - /** * Clears the omnibox. * @@ -113,43 +83,32 @@ * @param testUrl Url to prerender * @param testBase ChromeTabbedActivityTestBase instance. */ - public static void trainAutocompleteActionPredictorAndTestPrerender(final String testUrl, - ChromeTabbedActivityTestBase testBase) - throws InterruptedException { - // TODO(yusufo): Replace with external prerender handler instead of training. - ChromeTabUtils.newTabFromMenu(testBase.getInstrumentation(), testBase.getActivity()); - for (int i = 0; i < MAX_NUM_REPEATS_FOR_TRAINING; i++) { - // Navigate to another URL otherwise pre-rendering won't happen. - // Sometimes calling clearOmnibox immediately after won't actually - // clear it. This seems to help. - clearOmnibox(testBase); - testBase.typeInOmnibox(testUrl, true); - final LocationBarLayout locationBar = - (LocationBarLayout) testBase.getActivity().findViewById(R.id.location_bar); - if (waitForPrerenderUrl(testBase.getActivity().getActivityTab(), testUrl, true)) { - break; - } + public static ExternalPrerenderHandler prerenderUrlAndFocusOmnibox( + final String testUrl, final ChromeTabbedActivityTestBase testBase) + throws InterruptedException { + final Tab currentTab = testBase.getActivity().getActivityTab(); - final Pair<OmniboxSuggestion, Integer> suggestionPair = - waitForOmniboxSuggestion(locationBar, testUrl); - ThreadUtils.runOnUiThread(new Runnable() { - @Override - public void run() { - OmniboxResultsAdapter ora = - (OmniboxResultsAdapter) locationBar.getSuggestionList().getAdapter(); - OmniboxSuggestionDelegate suggestionDelegate = - ora.getSuggestionDelegate(); - suggestionDelegate.onSelection(suggestionPair.first, suggestionPair.second); - } - }); - } - ChromeTabUtils.closeCurrentTab(testBase.getInstrumentation(), testBase.getActivity()); - clearOmnibox(testBase); + ExternalPrerenderHandler prerenderHandler = ThreadUtils.runOnUiThreadBlockingNoException( + new Callable<ExternalPrerenderHandler>() { + @Override + public ExternalPrerenderHandler call() throws Exception { + ExternalPrerenderHandler prerenderHandler = new ExternalPrerenderHandler(); + boolean didPrerender = prerenderHandler.addPrerender( + currentTab.getProfile(), currentTab.getWebContents(), testUrl, null, + currentTab.getContentViewCore().getRenderCoordinates() + .getContentWidthPixInt(), + currentTab.getContentViewCore().getRenderCoordinates() + .getContentHeightPixInt()); + Assert.assertTrue("Failed to prerender test url: " + testUrl, didPrerender); + return prerenderHandler; + } + }); - testBase.typeInOmnibox(testUrl, true); - final Tab tab = testBase.getActivity().getActivityTab(); - ChromeTabbedActivityTestBase.assertTrue("URL was not prerendered.", - PrerenderTestHelper.waitForPrerenderUrl(tab, testUrl, false)); + testBase.typeInOmnibox(testUrl, false); + Assert.assertTrue("URL was not prerendered.", + PrerenderTestHelper.waitForPrerenderUrl(currentTab, testUrl, false)); + + return prerenderHandler; } /**
diff --git a/chrome/test/data/webui/settings/site_list_tests.js b/chrome/test/data/webui/settings/site_list_tests.js index bb2b47d..50bc3ea 100644 --- a/chrome/test/data/webui/settings/site_list_tests.js +++ b/chrome/test/data/webui/settings/site_list_tests.js
@@ -41,6 +41,44 @@ }; /** + * An example pref with 1 allowed location item. + */ + var prefsOneEnabled = { + 'profile': { + 'content_settings': { + 'exceptions': { + 'geolocation': { + 'value': { + 'https:\/\/foo-allow.com:443,https:\/\/foo-allow.com:443': { + 'setting': 1, + }, + }, + }, + }, + }, + }, + }; + + /** + * An example pref with 1 blocked location item. + */ + var prefsOneDisabled = { + 'profile': { + 'content_settings': { + 'exceptions': { + 'geolocation': { + 'value': { + 'https:\/\/foo-block.com:443,https:\/\/foo-block.com:443': { + 'setting': 2, + }, + }, + }, + }, + }, + }, + }; + + /** * An example empty pref. */ var prefsEmpty = { @@ -55,11 +93,16 @@ // Import necessary html before running suite. suiteSetup(function() { + CrSettingsPrefs.setInitialized(); return PolymerTest.importHtml( 'chrome://md-settings/site_settings/site_list.html' ); }); + suiteTeardown(function() { + CrSettingsPrefs.resetForTesting(); + }); + // Initialize a site-list before each test. setup(function() { PolymerTest.clearBody(); @@ -85,87 +128,143 @@ } } - test('Empty list', function() { + /** + * Configures the test element as a location category. + * @param {settings.PermissionValues} subtype Type of list to use: ALLOW + * or BLOCK. + * @param {dictionary} prefs The prefs to use. + */ + function setupLocationCategory(subtype, prefs) { testElement.category = settings.ContentSettingsTypes.GEOLOCATION; - testElement.categorySubtype = settings.PermissionValues.ALLOW; + testElement.categorySubtype = subtype; testElement.categoryEnabled = true; - testElement.prefs = prefsEmpty; - testElement.initialize_(); - Polymer.dom.flush(); + testElement.prefs = prefs; + } - assertEquals(0, testElement.sites_.length); + test('Empty list', function() { + setupLocationCategory(settings.PermissionValues.ALLOW, prefsEmpty); + return CrSettingsPrefs.initialized.then(function() { + assertEquals(0, testElement.sites_.length); - assertTrue(testElement.isAllowList_()); - assertFalse(testElement.showSiteList_(testElement.sites_, true)); - assertFalse(testElement.showSiteList_(testElement.sites_, false)); - assertEquals('Allow - 0', testElement.computeSiteListHeader_( - testElement.sites_, true)); - assertEquals('Exceptions - 0', testElement.computeSiteListHeader_( - testElement.sites_, false)); + assertTrue(testElement.isAllowList_()); + assertFalse(testElement.showSiteList_(testElement.sites_, true)); + assertFalse(testElement.showSiteList_(testElement.sites_, false)); + assertEquals('Allow - 0', testElement.computeSiteListHeader_( + testElement.sites_, true)); + assertEquals('Exceptions - 0', testElement.computeSiteListHeader_( + testElement.sites_, false)); + }.bind(this)); }); test('initial ALLOW state is correct', function() { - testElement.category = settings.ContentSettingsTypes.GEOLOCATION; - testElement.categorySubtype = settings.PermissionValues.ALLOW; - testElement.categoryEnabled = true; - testElement.prefs = prefs; - testElement.initialize_(); - Polymer.dom.flush(); + setupLocationCategory(settings.PermissionValues.ALLOW, prefs); + return CrSettingsPrefs.initialized.then(function() { + assertEquals(2, testElement.sites_.length); + assertEquals('https://foo-allow.com:443', testElement.sites_[0].url); - assertEquals(2, testElement.sites_.length); - assertEquals('https://foo-allow.com:443', testElement.sites_[0].url); - - assertTrue(testElement.isAllowList_()); - assertMenuActionHidden(testElement, 'Allow'); - // Site list should show, no matter what category default is set to. - assertTrue(testElement.showSiteList_(testElement.sites_, true)); - assertTrue(testElement.showSiteList_(testElement.sites_, false)); - assertEquals('Exceptions - 2', testElement.computeSiteListHeader_( - testElement.sites_, false)); - assertEquals('Allow - 2', testElement.computeSiteListHeader_( - testElement.sites_, true)); + assertTrue(testElement.isAllowList_()); + assertMenuActionHidden(testElement, 'Allow'); + // Site list should show, no matter what category default is set to. + assertTrue(testElement.showSiteList_(testElement.sites_, true)); + assertTrue(testElement.showSiteList_(testElement.sites_, false)); + assertEquals('Exceptions - 2', testElement.computeSiteListHeader_( + testElement.sites_, false)); + assertEquals('Allow - 2', testElement.computeSiteListHeader_( + testElement.sites_, true)); + }.bind(this)); }); test('initial BLOCK state is correct', function() { - testElement.category = settings.ContentSettingsTypes.GEOLOCATION; - testElement.categorySubtype = settings.PermissionValues.BLOCK; - testElement.categoryEnabled = true; - testElement.prefs = prefs; - testElement.initialize_(); - Polymer.dom.flush(); + setupLocationCategory(settings.PermissionValues.BLOCK, prefs); + return CrSettingsPrefs.initialized.then(function() { + assertEquals(2, testElement.sites_.length); + assertEquals('https://foo-block.com:443', testElement.sites_[0].url); - assertEquals(2, testElement.sites_.length); - assertEquals('https://foo-block.com:443', testElement.sites_[0].url); - - assertFalse(testElement.isAllowList_()); - assertMenuActionHidden(testElement, 'Block'); - // Site list should only show when category default is enabled. - assertFalse(testElement.showSiteList_(testElement.sites_, false)); - assertTrue(testElement.showSiteList_(testElement.sites_, true)); - assertEquals('Block - 2', testElement.computeSiteListHeader_( - testElement.sites_, true)); + assertFalse(testElement.isAllowList_()); + assertMenuActionHidden(testElement, 'Block'); + // Site list should only show when category default is enabled. + assertFalse(testElement.showSiteList_(testElement.sites_, false)); + assertTrue(testElement.showSiteList_(testElement.sites_, true)); + assertEquals('Block - 2', testElement.computeSiteListHeader_( + testElement.sites_, true)); + }.bind(this)); }); test('list items shown and clickable when data is present', function() { - testElement.category = settings.ContentSettingsTypes.GEOLOCATION; - testElement.categorySubtype = settings.PermissionValues.ALLOW; - testElement.categoryEnabled = true; - testElement.prefs = prefs; - testElement.initialize_(); + setupLocationCategory(settings.PermissionValues.ALLOW, prefs); // Required for firstItem to be found below. Polymer.dom.flush(); + return CrSettingsPrefs.initialized.then(function() { + // Validate that the sites_ gets populated from pre-canned prefs. + assertEquals(2, testElement.sites_.length); + assertEquals('https://foo-allow.com:443', testElement.sites_[0].url); + assertEquals(undefined, testElement.selectedOrigin); - // Validate that the sites_ gets populated from pre-canned prefs. - assertEquals(2, testElement.sites_.length); - assertEquals('https://foo-allow.com:443', testElement.sites_[0].url); - assertEquals(undefined, testElement.selectedOrigin); + // Validate that the sites are shown in UI and can be selected. + var firstItem = testElement.$.listContainer.items[0]; + var clickable = firstItem.querySelector('.flex paper-item'); + assertNotEquals(undefined, clickable); + MockInteractions.tap(clickable); + assertEquals('https://foo-allow.com:443', testElement.selectedOrigin); + }.bind(this)); + }); - // Validate that the sites are shown in UI and can be selected. - var firstItem = testElement.$.listContainer.items[0]; - var clickable = firstItem.querySelector('.flex paper-item'); - assertNotEquals(undefined, clickable); - MockInteractions.tap(clickable); - assertEquals('https://foo-allow.com:443', testElement.selectedOrigin); + test('Block list open when Allow list is empty', function() { + // Prefs: One item in Block list, nothing in Allow list. + setupLocationCategory(settings.PermissionValues.BLOCK, + prefsOneDisabled); + return CrSettingsPrefs.initialized.then(function() { + assertFalse(testElement.$.category.hidden); + assertTrue(testElement.$.category.opened); + assertNotEquals(0, testElement.$.listContainer.offsetHeight); + }.bind(this)); + }); + + test('Block list closed when Allow list is not empty', function() { + // Prefs: Items in both Block and Allow list. + setupLocationCategory(settings.PermissionValues.BLOCK, prefs); + return CrSettingsPrefs.initialized.then(function() { + assertFalse(testElement.$.category.hidden); + assertFalse(testElement.$.category.opened); + assertEquals(0, testElement.$.listContainer.offsetHeight); + }.bind(this)); + }); + + test('Allow list is always open (Block list empty)', function() { + // Prefs: One item in Allow list, nothing in Block list. + setupLocationCategory(settings.PermissionValues.ALLOW, prefsOneEnabled); + return CrSettingsPrefs.initialized.then(function() { + assertFalse(testElement.$.category.hidden); + assertTrue(testElement.$.category.opened); + assertNotEquals(0, testElement.$.listContainer.offsetHeight); + }.bind(this)); + }); + + test('Allow list is always open (Block list non-empty)', function() { + // Prefs: Items in both Block and Allow list. + setupLocationCategory(settings.PermissionValues.ALLOW, prefs); + return CrSettingsPrefs.initialized.then(function() { + assertFalse(testElement.$.category.hidden); + assertTrue(testElement.$.category.opened); + assertNotEquals(0, testElement.$.listContainer.offsetHeight); + }.bind(this)); + }); + + test('Block list hidden when empty', function() { + // Prefs: One item in Allow list, nothing in Block list. + setupLocationCategory(settings.PermissionValues.BLOCK, prefsOneEnabled); + return CrSettingsPrefs.initialized.then(function() { + assertTrue(testElement.$.category.hidden); + }.bind(this)); + }); + + test('Allow list hidden when empty', function() { + // Prefs: One item in Block list, nothing in Allow list. + setupLocationCategory(settings.PermissionValues.ALLOW, + prefsOneDisabled); + return CrSettingsPrefs.initialized.then(function() { + assertTrue(testElement.$.category.hidden); + }.bind(this)); }); }); }
diff --git a/components/cronet/android/api/src/org/chromium/net/JavaUrlRequest.java b/components/cronet/android/api/src/org/chromium/net/JavaUrlRequest.java index 00e9e59..b4dbd875 100644 --- a/components/cronet/android/api/src/org/chromium/net/JavaUrlRequest.java +++ b/components/cronet/android/api/src/org/chromium/net/JavaUrlRequest.java
@@ -771,7 +771,7 @@ void onResponseStarted(UrlResponseInfo info) { execute(State.AWAITING_READ, new CheckedRunnable() { @Override - public void run() { + public void run() throws Exception { if (mState.compareAndSet(State.STARTED, State.AWAITING_READ)) { mCallback.onResponseStarted(JavaUrlRequest.this, mUrlResponseInfo); } @@ -782,7 +782,7 @@ void onReadCompleted(final UrlResponseInfo info, final ByteBuffer byteBuffer) { execute(State.AWAITING_READ, new CheckedRunnable() { @Override - public void run() { + public void run() throws Exception { if (mState.compareAndSet(State.READING, State.AWAITING_READ)) { mCallback.onReadCompleted(JavaUrlRequest.this, info, byteBuffer); }
diff --git a/components/cronet/android/api/src/org/chromium/net/UrlRequest.java b/components/cronet/android/api/src/org/chromium/net/UrlRequest.java index 51cbc74fc..d82488c 100644 --- a/components/cronet/android/api/src/org/chromium/net/UrlRequest.java +++ b/components/cronet/android/api/src/org/chromium/net/UrlRequest.java
@@ -279,7 +279,7 @@ * @param newLocationUrl Location where request is redirected. */ public abstract void onRedirectReceived( - UrlRequest request, UrlResponseInfo info, String newLocationUrl); + UrlRequest request, UrlResponseInfo info, String newLocationUrl) throws Exception; /** * Invoked when the final set of headers, after all redirects, is received. @@ -295,7 +295,8 @@ * @param request Request that started to get response. * @param info Response information. */ - public abstract void onResponseStarted(UrlRequest request, UrlResponseInfo info); + public abstract void onResponseStarted(UrlRequest request, UrlResponseInfo info) + throws Exception; /** * Invoked whenever part of the response body has been read. Only part of @@ -317,7 +318,7 @@ * the received data. The buffer's limit is not changed. */ public abstract void onReadCompleted( - UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer); + UrlRequest request, UrlResponseInfo info, ByteBuffer byteBuffer) throws Exception; /** * Invoked when request is completed successfully. Once invoked, no other
diff --git a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java index 4854cb5..fa9c5d09 100644 --- a/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java +++ b/components/cronet/android/test/javatests/src/org/chromium/net/QuicTest.java
@@ -43,7 +43,7 @@ JSONObject quicParams = new JSONObject() .put("connection_options", "PACE,IW10,FOO,DEADBEEF") .put("host_whitelist", "test.example.com") - .put("store_server_configs_in_properties", true) + .put("max_server_configs_stored_in_properties", 2) .put("delay_tcp_race", true) .put("max_number_of_lossy_connections", 10) .put("packet_loss_threshold", 0.5)
diff --git a/components/cronet/url_request_context_config.cc b/components/cronet/url_request_context_config.cc index cb19efc..ca88279 100644 --- a/components/cronet/url_request_context_config.cc +++ b/components/cronet/url_request_context_config.cc
@@ -15,6 +15,7 @@ #include "base/values.h" #include "net/cert/cert_verifier.h" #include "net/dns/host_resolver.h" +#include "net/http/http_server_properties.h" #include "net/quic/quic_protocol.h" #include "net/quic/quic_utils.h" #include "net/url_request/url_request_context_builder.h" @@ -28,6 +29,8 @@ const char kQuicConnectionOptions[] = "connection_options"; const char kQuicStoreServerConfigsInProperties[] = "store_server_configs_in_properties"; +const char kQuicMaxServerConfigsStoredInProperties[] = + "max_server_configs_stored_in_properties"; const char kQuicDelayTcpRace[] = "delay_tcp_race"; const char kQuicMaxNumberOfLossyConnections[] = "max_number_of_lossy_connections"; @@ -76,11 +79,20 @@ net::QuicUtils::ParseQuicConnectionOptions(quic_connection_options)); } + // TODO(rtenneti): Delete this option after apps stop using it. + // Added this for backward compatibility. bool quic_store_server_configs_in_properties = false; if (quic_args->GetBoolean(kQuicStoreServerConfigsInProperties, &quic_store_server_configs_in_properties)) { - context_builder->set_quic_store_server_configs_in_properties( - quic_store_server_configs_in_properties); + context_builder->set_quic_max_server_configs_stored_in_properties( + net::kMaxQuicServersToPersist); + } + + int quic_max_server_configs_stored_in_properties = 0; + if (quic_args->GetInteger(kQuicMaxServerConfigsStoredInProperties, + &quic_max_server_configs_stored_in_properties)) { + context_builder->set_quic_max_server_configs_stored_in_properties( + static_cast<size_t>(quic_max_server_configs_stored_in_properties)); } bool quic_delay_tcp_race = false;
diff --git a/components/cronet/url_request_context_config_unittest.cc b/components/cronet/url_request_context_config_unittest.cc index e360f55b..d14c32eb3 100644 --- a/components/cronet/url_request_context_config_unittest.cc +++ b/components/cronet/url_request_context_config_unittest.cc
@@ -35,7 +35,7 @@ // User-Agent request header field. "fake agent", // JSON encoded experimental options. - "{\"QUIC\":{\"store_server_configs_in_properties\":true," + "{\"QUIC\":{\"max_server_configs_stored_in_properties\":2," "\"delay_tcp_race\":true," "\"max_number_of_lossy_connections\":10," "\"packet_loss_threshold\":0.5," @@ -69,8 +69,8 @@ quic_connection_options.push_back(net::kREJ); EXPECT_EQ(quic_connection_options, params->quic_connection_options); - // Check store_server_configs_in_properties. - EXPECT_TRUE(params->quic_store_server_configs_in_properties); + // Check max_server_configs_stored_in_properties. + EXPECT_EQ(2u, params->quic_max_server_configs_stored_in_properties); // Check delay_tcp_race. EXPECT_TRUE(params->quic_delay_tcp_race);
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc index 452e759..d8e632d 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.cc
@@ -7,7 +7,9 @@ #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers.h" #include "net/base/load_flags.h" +#include "net/http/http_response_headers.h" #include "net/http/http_response_info.h" +#include "net/http/http_status_code.h" #include "net/proxy/proxy_config.h" #include "net/proxy/proxy_server.h" #include "net/url_request/url_request.h" @@ -27,12 +29,16 @@ return UNKNOWN_TYPE; } - // Check for a Data Reduction Proxy via header before checking if proxies are - // bypassed, to avoid misreporting cases where the Data Reduction Proxy was - // bypassed between the request being sent out and the response coming in. - if (request.response_info().headers.get() && - HasDataReductionProxyViaHeader(request.response_info().headers.get(), - NULL)) { + // Check if the request came through the Data Reduction Proxy before checking + // if proxies are bypassed, to avoid misreporting cases where the Data + // Reduction Proxy was bypassed between the request being sent out and the + // response coming in. For 304 responses, check if the request was sent to the + // Data Reduction Proxy, since 304s aren't required to have a Via header even + // if they came through the Data Reduction Proxy. + if (request.response_headers() && + (HasDataReductionProxyViaHeader(request.response_headers(), nullptr) || + (request.response_headers()->response_code() == net::HTTP_NOT_MODIFIED && + config.WasDataReductionProxyUsed(&request, nullptr)))) { return VIA_DATA_REDUCTION_PROXY; }
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc index 89f78ec..4bf279e 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics_unittest.cc
@@ -53,79 +53,97 @@ }; const TestCase test_cases[] = { { - GURL("http://foo.com"), - origin, - base::TimeDelta(), - net::LOAD_NORMAL, - "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n", - VIA_DATA_REDUCTION_PROXY, + GURL("http://foo.com"), origin, base::TimeDelta(), net::LOAD_NORMAL, + "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n", + VIA_DATA_REDUCTION_PROXY, }, { - GURL("https://foo.com"), - net::ProxyServer::Direct(), - base::TimeDelta(), - net::LOAD_NORMAL, - "HTTP/1.1 200 OK\r\n\r\n", - HTTPS, + GURL("https://foo.com"), net::ProxyServer::Direct(), + base::TimeDelta(), net::LOAD_NORMAL, "HTTP/1.1 200 OK\r\n\r\n", HTTPS, }, { - GURL("http://foo.com"), - net::ProxyServer::Direct(), - base::TimeDelta::FromSeconds(1), - net::LOAD_NORMAL, - "HTTP/1.1 200 OK\r\n\r\n", - SHORT_BYPASS, + GURL("http://foo.com"), net::ProxyServer::Direct(), + base::TimeDelta::FromSeconds(1), net::LOAD_NORMAL, + "HTTP/1.1 200 OK\r\n\r\n", SHORT_BYPASS, }, { - GURL("http://foo.com"), - net::ProxyServer::Direct(), - base::TimeDelta::FromMinutes(60), - net::LOAD_NORMAL, - "HTTP/1.1 200 OK\r\n\r\n", - LONG_BYPASS, + GURL("http://foo.com"), net::ProxyServer::Direct(), + base::TimeDelta::FromSeconds(1), net::LOAD_NORMAL, + "HTTP/1.1 304 Not Modified\r\n\r\n", SHORT_BYPASS, + }, + { + GURL("http://foo.com"), net::ProxyServer::Direct(), + base::TimeDelta::FromMinutes(60), net::LOAD_NORMAL, + "HTTP/1.1 200 OK\r\n\r\n", LONG_BYPASS, + }, + { + GURL("http://foo.com"), net::ProxyServer::Direct(), + base::TimeDelta::FromMinutes(60), net::LOAD_NORMAL, + "HTTP/1.1 304 Not Modified\r\n\r\n", LONG_BYPASS, }, // Requests with LOAD_BYPASS_PROXY (e.g. block-once) should be classified - // as - // SHORT_BYPASS. + // as SHORT_BYPASS. { - GURL("http://foo.com"), - net::ProxyServer::Direct(), - base::TimeDelta(), - net::LOAD_BYPASS_PROXY, - "HTTP/1.1 200 OK\r\n\r\n", - SHORT_BYPASS, + GURL("http://foo.com"), net::ProxyServer::Direct(), base::TimeDelta(), + net::LOAD_BYPASS_PROXY, "HTTP/1.1 200 OK\r\n\r\n", SHORT_BYPASS, }, // Another proxy overriding the Data Reduction Proxy should be classified - // as - // SHORT_BYPASS. + // as SHORT_BYPASS. { - GURL("http://foo.com"), - net::ProxyServer::FromPacString("PROXY otherproxy.net:80"), - base::TimeDelta(), - net::LOAD_NORMAL, - "HTTP/1.1 200 OK\r\n\r\n", - SHORT_BYPASS, + GURL("http://foo.com"), + net::ProxyServer::FromPacString("PROXY otherproxy.net:80"), + base::TimeDelta(), net::LOAD_NORMAL, "HTTP/1.1 200 OK\r\n\r\n", + SHORT_BYPASS, }, // Bypasses due to local bypass rules should be classified as // SHORT_BYPASS. { - GURL("http://localbypass.com"), - net::ProxyServer::Direct(), - base::TimeDelta(), - net::LOAD_NORMAL, - "HTTP/1.1 200 OK\r\n\r\n", - SHORT_BYPASS, + GURL("http://localbypass.com"), net::ProxyServer::Direct(), + base::TimeDelta(), net::LOAD_NORMAL, "HTTP/1.1 200 OK\r\n\r\n", + SHORT_BYPASS, }, // Responses that seem like they should have come through the Data - // Reduction - // Proxy, but did not, should be classified as UNKNOWN_TYPE. + // Reduction Proxy, but did not, should be classified as UNKNOWN_TYPE. { - GURL("http://foo.com"), - net::ProxyServer::Direct(), - base::TimeDelta(), - net::LOAD_NORMAL, - "HTTP/1.1 200 OK\r\n\r\n", - UNKNOWN_TYPE, + GURL("http://foo.com"), net::ProxyServer::Direct(), base::TimeDelta(), + net::LOAD_NORMAL, "HTTP/1.1 200 OK\r\n\r\n", UNKNOWN_TYPE, + }, + { + GURL("http://foo.com"), origin, base::TimeDelta(), net::LOAD_NORMAL, + "HTTP/1.1 200 OK\r\n\r\n", UNKNOWN_TYPE, + }, + // The proxy is currently bypassed, but the response still came through + // the Data Reduction Proxy, so it should be classified as + // VIA_DATA_REDUCTION_PROXY. + { + GURL("http://foo.com"), origin, base::TimeDelta::FromMinutes(60), + net::LOAD_NORMAL, + "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n", + VIA_DATA_REDUCTION_PROXY, + }, + // The request was sent over a direct connection, but the response still + // has the Data Reduction Proxy Via header, so it should be classified as + // VIA_DATA_REDUCTION_PROXY. + { + GURL("http://foo.com"), net::ProxyServer::Direct(), base::TimeDelta(), + net::LOAD_NORMAL, + "HTTP/1.1 200 OK\r\nVia: 1.1 Chrome-Compression-Proxy\r\n\r\n", + VIA_DATA_REDUCTION_PROXY, + }, + // A 304 response with a DRP Via header should be classified as + // VIA_DATA_REDUCTION_PROXY. + { + GURL("http://foo.com"), net::ProxyServer::Direct(), base::TimeDelta(), + net::LOAD_NORMAL, + "HTTP/1.1 304 Not Modified\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n\r\n", + VIA_DATA_REDUCTION_PROXY, + }, + // A 304 response without a DRP Via header where the request was sent + // through the DRP should be classified as VIA_DATA_REDUCTION_PROXY. + { + GURL("http://foo.com"), origin, base::TimeDelta(), net::LOAD_NORMAL, + "HTTP/1.1 304 Not Modified\r\n\r\n", VIA_DATA_REDUCTION_PROXY, }, };
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc index ba064b0..92a19861 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.cc
@@ -6,11 +6,10 @@ #include <utility> -#include "base/bind.h" -#include "base/bind_helpers.h" #include "base/metrics/histogram_macros.h" #include "base/strings/string_number_conversions.h" #include "base/time/time.h" +#include "base/values.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_configurator.h" @@ -20,6 +19,7 @@ #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h" #include "components/data_reduction_proxy/core/common/lofi_decider.h" #include "net/base/load_flags.h" +#include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" #include "net/proxy/proxy_info.h" #include "net/proxy/proxy_server.h" @@ -91,6 +91,26 @@ received_content_length); } +// Given a |request| that went through the Data Reduction Proxy, this function +// estimates how many bytes would have been received if the response had been +// received directly from the origin using HTTP/1.1 with a content length of +// |adjusted_original_content_length|. +int64_t EstimateOriginalReceivedBytes( + const net::URLRequest& request, + int64_t adjusted_original_content_length) { + DCHECK_LE(0, adjusted_original_content_length); + + if (!request.status().is_success() || request.was_cached() || + !request.response_headers()) { + return request.GetTotalReceivedBytes(); + } + + // TODO(sclittle): Remove headers added by Data Reduction Proxy when computing + // original size. http://crbug/535701. + return request.response_headers()->raw_headers().size() + + adjusted_original_content_length; +} + } // namespace namespace data_reduction_proxy { @@ -202,93 +222,79 @@ if (data_reduction_proxy_bypass_stats_) data_reduction_proxy_bypass_stats_->OnUrlRequestCompleted(request, started); - if (data_reduction_proxy_io_data_ && request->response_info().headers && + net::HttpRequestHeaders request_headers; + if (data_reduction_proxy_io_data_ && request->response_headers() && request->response_headers()->HasHeaderValue( chrome_proxy_header(), chrome_proxy_lo_fi_directive())) { data_reduction_proxy_io_data_->lofi_ui_service()->OnLoFiReponseReceived( *request, false); - } else if (data_reduction_proxy_io_data_ && - request->response_info().headers && + } else if (data_reduction_proxy_io_data_ && request->response_headers() && request->response_headers()->HasHeaderValue( chrome_proxy_header(), chrome_proxy_lo_fi_preview_directive())) { data_reduction_proxy_io_data_->lofi_ui_service()->OnLoFiReponseReceived( *request, true); + RecordLoFiTransformationType(PREVIEW); + } else if (request->GetFullRequestHeaders(&request_headers) && + request_headers.HasHeader(chrome_proxy_header())) { + std::string header_value; + request_headers.GetHeader(chrome_proxy_header(), &header_value); + if (header_value.find(chrome_proxy_lo_fi_preview_directive()) != + std::string::npos) { + RecordLoFiTransformationType(NO_TRANSFORMATION_PREVIEW_REQUESTED); + } } - // For better accuracy, we use the actual bytes read instead of the length - // specified with the Content-Length header, which may be inaccurate, - // or missing, as is the case with chunked encoding. - int64_t received_content_length = request->received_response_content_length(); - if (!request->was_cached() && // Don't record cached content - received_content_length && // Zero-byte responses aren't useful. - request->response_info().network_accessed && // Network was accessed. - request->url().SchemeIsHTTPOrHTTPS()) { - int64_t original_content_length = - request->response_info().headers->GetInt64HeaderValue( - "x-original-content-length"); - base::TimeDelta freshness_lifetime = - request->response_info().headers->GetFreshnessLifetimes( - request->response_info().response_time).freshness; - DataReductionProxyRequestType request_type = - GetDataReductionProxyRequestType(*request, - configurator_->GetProxyConfig(), - *data_reduction_proxy_config_); - - int64_t adjusted_original_content_length = GetAdjustedOriginalContentLength( - request_type, original_content_length, received_content_length); - int64_t data_used = request->GetTotalReceivedBytes(); - // TODO(kundaji): Investigate why |compressed_size| can sometimes be - // less than |received_content_length|. Bug http://crbug/536139. - if (data_used < received_content_length) - data_used = received_content_length; - - int64_t original_size = data_used; - if (request_type == VIA_DATA_REDUCTION_PROXY) { - // TODO(kundaji): Remove headers added by data reduction proxy when - // computing original size. http://crbug/535701. - original_size = request->response_info().headers->raw_headers().size() + - adjusted_original_content_length; - } - - std::string mime_type; - if (request->status().status() == net::URLRequestStatus::SUCCESS) - request->GetMimeType(&mime_type); - - std::string data_usage_host = - request->first_party_for_cookies().HostNoBrackets(); - if (data_usage_host.empty()) { - data_usage_host = request->url().HostNoBrackets(); - } - - AccumulateDataUsage(data_used, original_size, request_type, data_usage_host, - mime_type); - - DCHECK(data_reduction_proxy_config_); - - RecordContentLengthHistograms( - // |data_reduction_proxy_io_data_| can be NULL for Webview. - data_reduction_proxy_io_data_ && - data_reduction_proxy_io_data_->IsEnabled() && - data_reduction_proxy_io_data_->lofi_decider() && - data_reduction_proxy_io_data_->lofi_decider()->IsUsingLoFiMode( - *request), - received_content_length, original_content_length, freshness_lifetime); - experiments_stats_->RecordBytes(request->request_time(), request_type, - received_content_length, - original_content_length); - - if (data_reduction_proxy_io_data_ && data_reduction_proxy_bypass_stats_) { - data_reduction_proxy_bypass_stats_->RecordBytesHistograms( - *request, data_reduction_proxy_io_data_->IsEnabled(), - configurator_->GetProxyConfig()); - } - - DVLOG(2) << __FUNCTION__ - << " received content length: " << received_content_length - << " original content length: " << original_content_length - << " url: " << request->url(); + if (!request->response_info().network_accessed || + !request->url().SchemeIsHTTPOrHTTPS() || + request->GetTotalReceivedBytes() == 0) { + return; } + + DataReductionProxyRequestType request_type = GetDataReductionProxyRequestType( + *request, configurator_->GetProxyConfig(), *data_reduction_proxy_config_); + + // Determine the original content length if present. + int64_t original_content_length = + request->response_headers() + ? request->response_headers()->GetInt64HeaderValue( + "x-original-content-length") + : -1; + + CalculateAndRecordDataUsage(*request, request_type, original_content_length); + + RecordContentLength(*request, request_type, original_content_length); +} + +void DataReductionProxyNetworkDelegate::CalculateAndRecordDataUsage( + const net::URLRequest& request, + DataReductionProxyRequestType request_type, + int64_t original_content_length) { + DCHECK_LE(-1, original_content_length); + int64_t data_used = request.GetTotalReceivedBytes(); + + // Estimate how many bytes would have been used if the DataReductionProxy was + // not used, and record the data usage. + int64_t original_size = data_used; + if (request_type == VIA_DATA_REDUCTION_PROXY && request.response_headers() && + !request.was_cached() && request.status().is_success()) { + original_size = EstimateOriginalReceivedBytes( + request, GetAdjustedOriginalContentLength( + request_type, original_content_length, + request.received_response_content_length())); + } + + std::string mime_type; + if (request.response_headers()) + request.response_headers()->GetMimeType(&mime_type); + + std::string data_usage_host = + request.first_party_for_cookies().HostNoBrackets(); + if (data_usage_host.empty()) + data_usage_host = request.url().HostNoBrackets(); + + AccumulateDataUsage(data_used, original_size, request_type, data_usage_host, + mime_type); } void DataReductionProxyNetworkDelegate::AccumulateDataUsage( @@ -308,6 +314,43 @@ total_original_received_bytes_ += original_size; } +void DataReductionProxyNetworkDelegate::RecordContentLength( + const net::URLRequest& request, + DataReductionProxyRequestType request_type, + int64_t original_content_length) { + if (!request.response_headers() || request.was_cached() || + request.received_response_content_length() == 0) { + return; + } + + // Record content length histograms for the request. + base::TimeDelta freshness_lifetime = + request.response_headers() + ->GetFreshnessLifetimes(request.response_info().response_time) + .freshness; + + RecordContentLengthHistograms( + // |data_reduction_proxy_io_data_| can be NULL for Webview. + data_reduction_proxy_io_data_ && + data_reduction_proxy_io_data_->IsEnabled() && + data_reduction_proxy_io_data_->lofi_decider() && + data_reduction_proxy_io_data_->lofi_decider()->IsUsingLoFiMode( + request), + request.received_response_content_length(), original_content_length, + freshness_lifetime); + + experiments_stats_->RecordBytes(request.request_time(), request_type, + request.received_response_content_length(), + original_content_length); + + if (data_reduction_proxy_io_data_ && data_reduction_proxy_bypass_stats_) { + // Record BypassedBytes histograms for the request. + data_reduction_proxy_bypass_stats_->RecordBytesHistograms( + request, data_reduction_proxy_io_data_->IsEnabled(), + configurator_->GetProxyConfig()); + } +} + void OnResolveProxyHandler(const GURL& url, int load_flags, const net::ProxyConfig& data_reduction_proxy_config, @@ -331,4 +374,10 @@ } } +void DataReductionProxyNetworkDelegate::RecordLoFiTransformationType( + LoFiTransformationType type) { + UMA_HISTOGRAM_ENUMERATION("DataReductionProxy.LoFi.TransformationType", type, + LO_FI_TRANSFORMATION_TYPES_INDEX_BOUNDARY); +} + } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h index b08a374..873ece2 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate.h
@@ -12,13 +12,16 @@ #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "base/values.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h" #include "net/base/layered_network_delegate.h" #include "net/proxy/proxy_retry_info.h" class GURL; +namespace base { +class Value; +} + namespace net { class HttpResponseHeaders; class HttpRequestHeaders; @@ -41,6 +44,16 @@ class DataReductionProxyIOData; class DataReductionProxyRequestOptions; +// Values of the UMA DataReductionProxy.LoFi.TransformationType histogram. +// This enum must remain synchronized with +// DataReductionProxyLoFiTransformationType in +// metrics/histograms/histograms.xml. +enum LoFiTransformationType { + PREVIEW = 0, + NO_TRANSFORMATION_PREVIEW_REQUESTED, + LO_FI_TRANSFORMATION_TYPES_INDEX_BOUNDARY, +}; + // DataReductionProxyNetworkDelegate is a LayeredNetworkDelegate that wraps a // NetworkDelegate and adds Data Reduction Proxy specific logic. class DataReductionProxyNetworkDelegate : public net::LayeredNetworkDelegate { @@ -77,8 +90,6 @@ base::Value* SessionNetworkStatsInfoToValue() const; private: - friend class DataReductionProxyNetworkDelegateTest; - // Called as the proxy is being resolved for |url|. Allows the delegate to // override the proxy resolution decision made by ProxyService. The delegate // may override the decision by modifying the ProxyInfo |result|. @@ -108,6 +119,14 @@ void OnCompletedInternal(net::URLRequest* request, bool started) override; + // Calculates actual data usage that went over the network at the HTTP layer + // (e.g. not including network layer overhead) and estimates original data + // usage for |request|. Passing in -1 for |original_content_length| indicates + // that the original content length of the response could not be determined. + void CalculateAndRecordDataUsage(const net::URLRequest& request, + DataReductionProxyRequestType request_type, + int64_t original_content_length); + // Posts to the UI thread to UpdateContentLengthPrefs in the data reduction // proxy metrics and updates |received_content_length_| and // |original_content_length_|. @@ -117,6 +136,18 @@ const std::string& data_usage_host, const std::string& mime_type); + // Record information such as histograms related to the Content-Length of + // |request|. |original_content_length| is the length of the resource if + // fetched over a direct connection without the Data Reduction Proxy, or -1 if + // no original content length is available. + void RecordContentLength(const net::URLRequest& request, + DataReductionProxyRequestType request_type, + int64_t original_content_length); + + // Records UMA that counts how many pages were transformed by various Lo-Fi + // transformations. + void RecordLoFiTransformationType(LoFiTransformationType type); + // Total size of all content that has been received over the network. int64_t total_received_bytes_;
diff --git a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc index 872c49d7..eff84c6 100644 --- a/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc +++ b/components/data_reduction_proxy/core/browser/data_reduction_proxy_network_delegate_unittest.cc
@@ -6,18 +6,23 @@ #include <stddef.h> #include <stdint.h> + #include <string> #include <utility> #include "base/command_line.h" #include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/message_loop/message_loop.h" #include "base/metrics/field_trial.h" +#include "base/numerics/safe_conversions.h" +#include "base/run_loop.h" #include "base/strings/string_number_conversions.h" #include "base/test/histogram_tester.h" #include "base/test/mock_entropy_provider.h" #include "base/time/time.h" +#include "base/values.h" #include "build/build_config.h" -#include "components/data_reduction_proxy/core/browser/data_reduction_proxy_bypass_stats.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_config_test_utils.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_metrics.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_request_options.h" @@ -29,16 +34,14 @@ #include "components/data_reduction_proxy/core/common/lofi_decider.h" #include "net/base/host_port_pair.h" #include "net/base/load_flags.h" +#include "net/base/net_errors.h" +#include "net/http/http_request_headers.h" #include "net/http/http_response_headers.h" #include "net/http/http_util.h" -#include "net/log/net_log.h" -#include "net/log/test_net_log.h" #include "net/proxy/proxy_config.h" #include "net/proxy/proxy_server.h" #include "net/socket/socket_test_util.h" #include "net/url_request/url_request.h" -#include "net/url_request/url_request_job_factory_impl.h" -#include "net/url_request/url_request_test_job.h" #include "net/url_request/url_request_test_util.h" #include "testing/gtest/include/gtest/gtest.h" @@ -130,47 +133,30 @@ bool is_preview_; }; -} // namespace - class DataReductionProxyNetworkDelegateTest : public testing::Test { public: - DataReductionProxyNetworkDelegateTest() : context_(true) { + DataReductionProxyNetworkDelegateTest() + : context_(true), + context_storage_(&context_), + test_context_(DataReductionProxyTestContext::Builder() + .WithClient(kClient) + .WithMockClientSocketFactory(&mock_socket_factory_) + .WithURLRequestContext(&context_) + .Build()) { context_.set_client_socket_factory(&mock_socket_factory_); - context_.Init(); - - test_context_ = DataReductionProxyTestContext::Builder() - .WithClient(kClient) - .WithMockClientSocketFactory(&mock_socket_factory_) - .WithURLRequestContext(&context_) - .Build(); - - data_reduction_proxy_network_delegate_.reset( - new DataReductionProxyNetworkDelegate( - scoped_ptr<net::NetworkDelegate>(new TestNetworkDelegate()), - config(), test_context_->io_data()->request_options(), - test_context_->configurator(), - test_context_->io_data()->experiments_stats(), - test_context_->net_log(), test_context_->event_creator())); - - bypass_stats_.reset(new DataReductionProxyBypassStats( - config(), test_context_->unreachable_callback())); - - data_reduction_proxy_network_delegate_->InitIODataAndUMA( - test_context_->io_data(), bypass_stats_.get()); + test_context_->AttachToURLRequestContext(&context_storage_); scoped_ptr<TestLoFiDecider> lofi_decider(new TestLoFiDecider()); lofi_decider_ = lofi_decider.get(); - io_data()->set_lofi_decider(std::move(lofi_decider)); + test_context_->io_data()->set_lofi_decider(std::move(lofi_decider)); scoped_ptr<TestLoFiUIService> lofi_ui_service(new TestLoFiUIService()); lofi_ui_service_ = lofi_ui_service.get(); - io_data()->set_lofi_ui_service(std::move(lofi_ui_service)); - } + test_context_->io_data()->set_lofi_ui_service(std::move(lofi_ui_service)); - const net::ProxyConfig& GetProxyConfig() const { return config_; } + context_.Init(); - MockDataReductionProxyConfig* config() const { - return test_context_->mock_config(); + test_context_->EnableDataReductionProxyWithSecureProxyCheckSuccess(); } static void VerifyLoFiHeader(bool expected_lofi_used, @@ -188,96 +174,101 @@ test_context_->settings()->WasLoFiModeActiveOnMainFrame()); } - void VerifyDidNotifyLoFiResponse(bool lofi_response) { + void VerifyDidNotifyLoFiResponse(bool lofi_response) const { EXPECT_EQ(lofi_response, lofi_ui_service_->DidNotifyLoFiResponse()); } - void VerifyLoFiPreviewResponse(bool is_preview) { + void VerifyLoFiPreviewResponse(bool is_preview) const { EXPECT_EQ(is_preview, lofi_ui_service_->is_preview()); } - int64_t total_received_bytes() { - return data_reduction_proxy_network_delegate_->total_received_bytes_; - } - - int64_t total_original_received_bytes() { - return data_reduction_proxy_network_delegate_ - ->total_original_received_bytes_; - } - - net::MockClientSocketFactory* mock_socket_factory() { - return &mock_socket_factory_; - } - - protected: // Each line in |response_headers| should end with "\r\n" and not '\0', and // the last line should have a second "\r\n". // An empty |response_headers| is allowed. It works by making this look like // an HTTP/0.9 response, since HTTP/0.9 responses don't have headers. scoped_ptr<net::URLRequest> FetchURLRequest( const GURL& url, + net::HttpRequestHeaders* request_headers, const std::string& response_headers, int64_t response_content_length) { - scoped_ptr<net::URLRequest> request = context_.CreateRequest( - url, net::IDLE, &delegate_); + const std::string response_body( + base::checked_cast<size_t>(response_content_length), ' '); + net::MockRead reads[] = {net::MockRead(response_headers.c_str()), + net::MockRead(response_body.c_str()), + net::MockRead(net::SYNCHRONOUS, net::OK)}; + net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0); + mock_socket_factory_.AddSocketDataProvider(&socket); - std::string response_content(response_content_length, ' '); - net::MockRead initial_mock_reads[] = { - net::MockRead(response_headers.c_str()), - net::MockRead(response_content.c_str()), - net::MockRead(net::SYNCHRONOUS, net::OK), - }; - net::StaticSocketDataProvider initial_socket_data_provider( - initial_mock_reads, arraysize(initial_mock_reads), nullptr, 0); - mock_socket_factory()->AddSocketDataProvider(&initial_socket_data_provider); + net::TestDelegate delegate; + scoped_ptr<net::URLRequest> request = + context_.CreateRequest(url, net::IDLE, &delegate); + if (request_headers) + request->SetExtraRequestHeaders(*request_headers); request->Start(); - test_context_->RunUntilIdle(); - - if (!response_headers.empty()) - EXPECT_TRUE(request->response_headers() != NULL); - + base::RunLoop().RunUntilIdle(); return request; } - void set_network_delegate(net::NetworkDelegate* delegate) { - network_delegate_ = delegate; - context_.set_network_delegate(network_delegate_); + int64_t total_received_bytes() const { + return GetSessionNetworkStatsInfoInt64("session_received_content_length"); + } + + int64_t total_original_received_bytes() const { + return GetSessionNetworkStatsInfoInt64("session_original_content_length"); + } + + net::MockClientSocketFactory* mock_socket_factory() { + return &mock_socket_factory_; + } + + net::TestURLRequestContext* context() { return &context_; } + + net::NetworkDelegate* network_delegate() const { + return context_.network_delegate(); } TestDataReductionProxyParams* params() const { return test_context_->config()->test_params(); } - TestDataReductionProxyIOData* io_data() const { - return test_context_->io_data(); + TestDataReductionProxyConfig* config() const { + return test_context_->config(); } - TestDataReductionProxyConfig* config() { return test_context_->config(); } - - TestLoFiDecider* lofi_decider() { return lofi_decider_; } - - scoped_ptr<DataReductionProxyNetworkDelegate> - data_reduction_proxy_network_delegate_; + TestLoFiDecider* lofi_decider() const { return lofi_decider_; } private: + int64_t GetSessionNetworkStatsInfoInt64(const char* key) const { + const DataReductionProxyNetworkDelegate* drp_network_delegate = + reinterpret_cast<const DataReductionProxyNetworkDelegate*>( + context_.network_delegate()); + + scoped_ptr<base::DictionaryValue> session_network_stats_info = + base::DictionaryValue::From(make_scoped_ptr( + drp_network_delegate->SessionNetworkStatsInfoToValue())); + EXPECT_TRUE(session_network_stats_info); + + std::string string_value; + EXPECT_TRUE(session_network_stats_info->GetString(key, &string_value)); + int64_t value = 0; + EXPECT_TRUE(base::StringToInt64(string_value, &value)); + return value; + } + base::MessageLoopForIO message_loop_; net::MockClientSocketFactory mock_socket_factory_; net::TestURLRequestContext context_; - net::TestDelegate delegate_; + net::URLRequestContextStorage context_storage_; - net::ProxyConfig config_; - net::NetworkDelegate* network_delegate_; TestLoFiDecider* lofi_decider_; TestLoFiUIService* lofi_ui_service_; scoped_ptr<DataReductionProxyTestContext> test_context_; - scoped_ptr<DataReductionProxyBypassStats> bypass_stats_; }; TEST_F(DataReductionProxyNetworkDelegateTest, AuthenticationTest) { - set_network_delegate(data_reduction_proxy_network_delegate_.get()); - scoped_ptr<net::URLRequest> fake_request( - FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0)); + scoped_ptr<net::URLRequest> fake_request(FetchURLRequest( + GURL("http://www.google.com/"), nullptr, std::string(), 0)); net::ProxyInfo data_reduction_proxy_info; std::string data_reduction_proxy; @@ -285,7 +276,7 @@ data_reduction_proxy_info.UseNamedProxy(data_reduction_proxy); net::HttpRequestHeaders headers; - data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( + network_delegate()->NotifyBeforeSendProxyHeaders( fake_request.get(), data_reduction_proxy_info, &headers); EXPECT_TRUE(headers.HasHeader(kChromeProxyHeader)); @@ -296,7 +287,6 @@ } TEST_F(DataReductionProxyNetworkDelegateTest, LoFiTransitions) { - set_network_delegate(data_reduction_proxy_network_delegate_.get()); // Enable Lo-Fi. const struct { bool lofi_switch_enabled; @@ -334,12 +324,12 @@ // Main frame loaded. Lo-Fi should be used. net::HttpRequestHeaders headers; - scoped_ptr<net::URLRequest> fake_request( - FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0)); + scoped_ptr<net::URLRequest> fake_request(FetchURLRequest( + GURL("http://www.google.com/"), nullptr, std::string(), 0)); fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME); lofi_decider()->SetIsUsingLoFiMode( config()->ShouldEnableLoFiMode(*fake_request.get())); - data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( + network_delegate()->NotifyBeforeSendProxyHeaders( fake_request.get(), data_reduction_proxy_info, &headers); VerifyLoFiHeader(true, headers); VerifyWasLoFiModeActiveOnMainFrame(true); @@ -348,10 +338,10 @@ { // Lo-Fi is already off. Lo-Fi should not be used. net::HttpRequestHeaders headers; - scoped_ptr<net::URLRequest> fake_request( - FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0)); + scoped_ptr<net::URLRequest> fake_request(FetchURLRequest( + GURL("http://www.google.com/"), nullptr, std::string(), 0)); lofi_decider()->SetIsUsingLoFiMode(false); - data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( + network_delegate()->NotifyBeforeSendProxyHeaders( fake_request.get(), data_reduction_proxy_info, &headers); VerifyLoFiHeader(false, headers); // Not a mainframe request, WasLoFiModeActiveOnMainFrame should still be @@ -362,11 +352,11 @@ { // Lo-Fi is already on. Lo-Fi should be used. net::HttpRequestHeaders headers; - scoped_ptr<net::URLRequest> fake_request( - FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0)); + scoped_ptr<net::URLRequest> fake_request(FetchURLRequest( + GURL("http://www.google.com/"), nullptr, std::string(), 0)); lofi_decider()->SetIsUsingLoFiMode(true); - data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( + network_delegate()->NotifyBeforeSendProxyHeaders( fake_request.get(), data_reduction_proxy_info, &headers); VerifyLoFiHeader(true, headers); // Not a mainframe request, WasLoFiModeActiveOnMainFrame should still be @@ -380,11 +370,11 @@ // Main frame request with Lo-Fi off. Lo-Fi should not be used. // State of Lo-Fi should persist until next page load. net::HttpRequestHeaders headers; - scoped_ptr<net::URLRequest> fake_request( - FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0)); + scoped_ptr<net::URLRequest> fake_request(FetchURLRequest( + GURL("http://www.google.com/"), nullptr, std::string(), 0)); fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME); lofi_decider()->SetIsUsingLoFiMode(false); - data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( + network_delegate()->NotifyBeforeSendProxyHeaders( fake_request.get(), data_reduction_proxy_info, &headers); VerifyLoFiHeader(false, headers); VerifyWasLoFiModeActiveOnMainFrame(false); @@ -393,10 +383,10 @@ { // Lo-Fi is off. Lo-Fi is still not used. net::HttpRequestHeaders headers; - scoped_ptr<net::URLRequest> fake_request( - FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0)); + scoped_ptr<net::URLRequest> fake_request(FetchURLRequest( + GURL("http://www.google.com/"), nullptr, std::string(), 0)); lofi_decider()->SetIsUsingLoFiMode(false); - data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( + network_delegate()->NotifyBeforeSendProxyHeaders( fake_request.get(), data_reduction_proxy_info, &headers); VerifyLoFiHeader(false, headers); // Not a mainframe request, WasLoFiModeActiveOnMainFrame should still be @@ -407,12 +397,12 @@ { // Main frame request. Lo-Fi should be used. net::HttpRequestHeaders headers; - scoped_ptr<net::URLRequest> fake_request( - FetchURLRequest(GURL("http://www.google.com/"), std::string(), 0)); + scoped_ptr<net::URLRequest> fake_request(FetchURLRequest( + GURL("http://www.google.com/"), nullptr, std::string(), 0)); fake_request->SetLoadFlags(net::LOAD_MAIN_FRAME); lofi_decider()->SetIsUsingLoFiMode( config()->ShouldEnableLoFiMode(*fake_request.get())); - data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( + network_delegate()->NotifyBeforeSendProxyHeaders( fake_request.get(), data_reduction_proxy_info, &headers); VerifyLoFiHeader(true, headers); VerifyWasLoFiModeActiveOnMainFrame(true); @@ -452,8 +442,6 @@ base::HistogramTester histogram_tester; - set_network_delegate(data_reduction_proxy_network_delegate_.get()); - std::string response_headers = "HTTP/1.1 200 OK\r\n" "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n" @@ -463,7 +451,7 @@ base::Int64ToString(kOriginalContentLength) + "\r\n\r\n"; scoped_ptr<net::URLRequest> fake_request( - FetchURLRequest(GURL("http://www.google.com/"), response_headers, + FetchURLRequest(GURL("http://www.google.com/"), nullptr, response_headers, kResponseContentLength)); base::TimeDelta freshness_lifetime = @@ -539,7 +527,7 @@ lofi_decider()->SetIsUsingLoFiMode( config()->ShouldEnableLoFiMode(*fake_request.get())); - fake_request = (FetchURLRequest(GURL("http://www.example.com/"), + fake_request = (FetchURLRequest(GURL("http://www.example.com/"), nullptr, response_headers, kResponseContentLength)); // Histograms are accumulative, so get the sum of all the tests so far. @@ -677,47 +665,12 @@ "; DIRECT"); EXPECT_FALSE(data_reduction_proxy_info.is_empty()); - data_reduction_proxy_network_delegate_->NotifyBeforeSendProxyHeaders( + network_delegate()->NotifyBeforeSendProxyHeaders( nullptr, data_reduction_proxy_info, &headers); EXPECT_TRUE(headers.HasHeader(kChromeProxyHeader)); } -TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternal) { - const int64_t kResponseContentLength = 140; - const int64_t kOriginalContentLength = 200; - - set_network_delegate(data_reduction_proxy_network_delegate_.get()); - - std::string raw_headers = - "HTTP/1.1 200 OK\n" - "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" - "Expires: Mon, 24 Nov 2014 12:45:26 GMT\n" - "Via: 1.1 Chrome-Compression-Proxy\n" - "x-original-content-length: " + - base::Int64ToString(kOriginalContentLength) + "\n"; - - HeadersToRaw(&raw_headers); - std::string response_headers = - net::HttpUtil::ConvertHeadersBackToHTTPResponse(raw_headers); - - FetchURLRequest(GURL("http://www.google.com/"), response_headers, - kResponseContentLength); - - EXPECT_EQ( - kResponseContentLength + static_cast<int64_t>(response_headers.size()), - total_received_bytes()); - // Original size computation does not currently take into account that "\r\n" - // is removed from each header line. - EXPECT_EQ(kOriginalContentLength + static_cast<int64_t>(raw_headers.size()), - total_original_received_bytes()); -} - TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternalLoFi) { - const int64_t kResponseContentLength = 140; - const int64_t kOriginalContentLength = 200; - - set_network_delegate(data_reduction_proxy_network_delegate_.get()); - // Enable Lo-Fi. const struct { bool lofi_response; @@ -726,34 +679,25 @@ }; for (size_t i = 0; i < arraysize(tests); ++i) { - std::string raw_headers = - "HTTP/1.1 200 OK\n" - "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" - "Expires: Mon, 24 Nov 2014 12:45:26 GMT\n" - "Via: 1.1 Chrome-Compression-Proxy\n" - "x-original-content-length: " + - base::Int64ToString(kOriginalContentLength) + "\n"; + std::string response_headers = + "HTTP/1.1 200 OK\r\n" + "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n" + "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "x-original-content-length: 200\r\n"; if (tests[i].lofi_response) - raw_headers += "Chrome-Proxy: q=low\n"; + response_headers += "Chrome-Proxy: q=low\r\n"; - HeadersToRaw(&raw_headers); - std::string response_headers = - net::HttpUtil::ConvertHeadersBackToHTTPResponse(raw_headers); - - FetchURLRequest(GURL("http://www.google.com/"), response_headers, - kResponseContentLength); + response_headers += "\r\n"; + FetchURLRequest(GURL("http://www.google.com/"), nullptr, response_headers, + 140); VerifyDidNotifyLoFiResponse(tests[i].lofi_response); } } TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedInternalLoFiPreview) { - const int64_t kResponseContentLength = 140; - const int64_t kOriginalContentLength = 200; - - set_network_delegate(data_reduction_proxy_network_delegate_.get()); - // Enable Lo-Fi. const struct { bool is_preview; @@ -762,27 +706,152 @@ }; for (size_t i = 0; i < arraysize(tests); ++i) { - std::string raw_headers = - "HTTP/1.1 200 OK\n" - "Date: Wed, 28 Nov 2007 09:40:09 GMT\n" - "Expires: Mon, 24 Nov 2014 12:45:26 GMT\n" - "Via: 1.1 Chrome-Compression-Proxy\n" - "x-original-content-length: " + - base::Int64ToString(kOriginalContentLength) + "\n"; + std::string response_headers = + "HTTP/1.1 200 OK\r\n" + "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n" + "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "x-original-content-length: 200\r\n"; if (tests[i].is_preview) - raw_headers += "Chrome-Proxy: q=preview\n"; + response_headers += "Chrome-Proxy: q=preview\r\n"; - HeadersToRaw(&raw_headers); - std::string response_headers = - net::HttpUtil::ConvertHeadersBackToHTTPResponse(raw_headers); - - FetchURLRequest(GURL("http://www.google.com/"), response_headers, - kResponseContentLength); + response_headers += "\r\n"; + FetchURLRequest(GURL("http://www.google.com/"), nullptr, response_headers, + 140); VerifyDidNotifyLoFiResponse(tests[i].is_preview); VerifyLoFiPreviewResponse(tests[i].is_preview); } } +TEST_F(DataReductionProxyNetworkDelegateTest, + TestLoFiTransformationTypeHistogram) { + const char kLoFiTransformationTypeHistogram[] = + "DataReductionProxy.LoFi.TransformationType"; + base::HistogramTester histogram_tester; + + net::HttpRequestHeaders request_headers; + request_headers.SetHeader("Chrome-Proxy", "q=preview"); + FetchURLRequest(GURL("http://www.google.com/"), &request_headers, + std::string(), 140); + histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram, + NO_TRANSFORMATION_PREVIEW_REQUESTED, 1); + + std::string response_headers = + "HTTP/1.1 200 OK\r\n" + "Chrome-Proxy: q=preview\r\n" + "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n" + "Expires: Mon, 24 Nov 2014 12:45:26 GMT\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "x-original-content-length: 200\r\n"; + + response_headers += "\r\n"; + FetchURLRequest(GURL("http://www.google.com/"), nullptr, response_headers, + 140); + + histogram_tester.ExpectBucketCount(kLoFiTransformationTypeHistogram, PREVIEW, + 1); +} + +TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedSizeFor200) { + int64_t baseline_received_bytes = total_received_bytes(); + int64_t baseline_original_received_bytes = total_original_received_bytes(); + + const char kDrpResponseHeaders[] = + "HTTP/1.1 200 OK\r\n" + "Date: Wed, 28 Nov 2007 09:40:09 GMT\r\n" + "Warning: 199 Misc-Agent \"some warning text\"\r\n" + "Via:\r\n" + "Via: 1.1 Chrome-Compression-Proxy-Suffix, 9.9 other-proxy\r\n" + "Via: 2.2 Chrome-Compression-Proxy\r\n" + "Warning: 214 Chrome-Compression-Proxy \"Transformation Applied\"\r\n" + "X-Original-Content-Length: 10000\r\n" + "Chrome-Proxy: q=low\r\n" + "Content-Length: 1000\r\n\r\n"; + + scoped_ptr<net::URLRequest> request = FetchURLRequest( + GURL("http://example.com/path/"), nullptr, kDrpResponseHeaders, 1000); + + EXPECT_EQ(request->GetTotalReceivedBytes(), + total_received_bytes() - baseline_received_bytes); + + const std::string raw_headers = net::HttpUtil::AssembleRawHeaders( + kDrpResponseHeaders, arraysize(kDrpResponseHeaders) - 1); + EXPECT_EQ(static_cast<int64_t>(raw_headers.size() + + 10000 /* original_response_body */), + total_original_received_bytes() - baseline_original_received_bytes); +} + +TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedSizeFor304) { + int64_t baseline_received_bytes = total_received_bytes(); + int64_t baseline_original_received_bytes = total_original_received_bytes(); + + const char kDrpResponseHeaders[] = + "HTTP/1.1 304 Not Modified\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "X-Original-Content-Length: 10000\r\n\r\n"; + + scoped_ptr<net::URLRequest> request = FetchURLRequest( + GURL("http://example.com/path/"), nullptr, kDrpResponseHeaders, 0); + + EXPECT_EQ(request->GetTotalReceivedBytes(), + total_received_bytes() - baseline_received_bytes); + + const std::string raw_headers = net::HttpUtil::AssembleRawHeaders( + kDrpResponseHeaders, arraysize(kDrpResponseHeaders) - 1); + EXPECT_EQ(static_cast<int64_t>(raw_headers.size() + + 10000 /* original_response_body */), + total_original_received_bytes() - baseline_original_received_bytes); +} + +TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedSizeForWriteError) { + int64_t baseline_received_bytes = total_received_bytes(); + int64_t baseline_original_received_bytes = total_original_received_bytes(); + + net::MockWrite writes[] = { + net::MockWrite("GET http://example.com/path/ HTTP/1.1\r\n" + "Host: example.com\r\n"), + net::MockWrite(net::ASYNC, net::ERR_ABORTED)}; + net::StaticSocketDataProvider socket(nullptr, 0, writes, arraysize(writes)); + mock_socket_factory()->AddSocketDataProvider(&socket); + + net::TestDelegate delegate; + scoped_ptr<net::URLRequest> request = context()->CreateRequest( + GURL("http://example.com/path/"), net::IDLE, &delegate); + request->Start(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(request->GetTotalReceivedBytes(), + total_received_bytes() - baseline_received_bytes); + EXPECT_EQ(request->GetTotalReceivedBytes(), + total_original_received_bytes() - baseline_original_received_bytes); +} + +TEST_F(DataReductionProxyNetworkDelegateTest, OnCompletedSizeForReadError) { + int64_t baseline_received_bytes = total_received_bytes(); + int64_t baseline_original_received_bytes = total_original_received_bytes(); + + net::MockRead reads[] = {net::MockRead("HTTP/1.1 200 OK\r\n" + "Via: 1.1 Chrome-Compression-Proxy\r\n" + "X-Original-Content-Length: 10000\r\n" + "Content-Length: 1000\r\n\r\n"), + net::MockRead(net::ASYNC, net::ERR_ABORTED)}; + net::StaticSocketDataProvider socket(reads, arraysize(reads), nullptr, 0); + mock_socket_factory()->AddSocketDataProvider(&socket); + + net::TestDelegate delegate; + scoped_ptr<net::URLRequest> request = context()->CreateRequest( + GURL("http://example.com/path/"), net::IDLE, &delegate); + request->Start(); + base::RunLoop().RunUntilIdle(); + + EXPECT_EQ(request->GetTotalReceivedBytes(), + total_received_bytes() - baseline_received_bytes); + EXPECT_EQ(request->GetTotalReceivedBytes(), + total_original_received_bytes() - baseline_original_received_bytes); +} + +} // namespace + } // namespace data_reduction_proxy
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc index 2846f17..2830400 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers.cc
@@ -16,6 +16,7 @@ #include "base/strings/string_util.h" #include "base/time/time.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h" +#include "components/data_reduction_proxy/core/common/data_reduction_proxy_params.h" #include "net/http/http_response_headers.h" #include "net/http/http_status_code.h" @@ -263,7 +264,11 @@ data_reduction_proxy_info->bypass_duration = TimeDelta::FromSeconds(1); return BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX; } - return BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER; + + // Missing the via header should not trigger bypass if the client is + // included in the tamper detection experiment. + if (!params::IsIncludedInTamperDetectionExperiment()) + return BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER; } // There is no bypass event. return BYPASS_EVENT_TYPE_MAX;
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc index c5dd6285..fdcc5458 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_headers_unittest.cc
@@ -10,6 +10,7 @@ #include <vector> #include "base/macros.h" +#include "base/metrics/field_trial.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_creator.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_event_storage_delegate_test_utils.h" #include "components/data_reduction_proxy/core/common/data_reduction_proxy_headers_test_utils.h" @@ -502,110 +503,146 @@ TEST_F(DataReductionProxyHeadersTest, GetDataReductionProxyBypassEventType) { const struct { const char* headers; + bool in_tamper_detection_experiment; DataReductionProxyBypassType expected_result; } tests[] = { - { "HTTP/1.1 200 OK\n" - "Chrome-Proxy: bypass=0\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_MEDIUM, - }, - { "HTTP/1.1 200 OK\n" - "Chrome-Proxy: bypass=1\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_SHORT, - }, - { "HTTP/1.1 200 OK\n" - "Chrome-Proxy: bypass=59\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_SHORT, - }, - { "HTTP/1.1 200 OK\n" - "Chrome-Proxy: bypass=60\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_MEDIUM, - }, - { "HTTP/1.1 200 OK\n" - "Chrome-Proxy: bypass=300\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_MEDIUM, - }, - { "HTTP/1.1 200 OK\n" - "Chrome-Proxy: bypass=301\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_LONG, - }, - { "HTTP/1.1 200 OK\n" - "Chrome-Proxy: block-once\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_CURRENT, - }, - { "HTTP/1.1 500 Internal Server Error\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR, - }, - { "HTTP/1.1 501 Not Implemented\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_MAX, - }, - { "HTTP/1.1 502 Bad Gateway\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY, - }, - { "HTTP/1.1 503 Service Unavailable\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE, - }, - { "HTTP/1.1 504 Gateway Timeout\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_MAX, - }, - { "HTTP/1.1 505 HTTP Version Not Supported\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_MAX, - }, - { "HTTP/1.1 304 Not Modified\n", - BYPASS_EVENT_TYPE_MAX, - }, - { "HTTP/1.1 200 OK\n", - BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER, - }, - { "HTTP/1.1 200 OK\n" - "Chrome-Proxy: bypass=59\n", - BYPASS_EVENT_TYPE_SHORT, - }, - { "HTTP/1.1 502 Bad Gateway\n", - BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY, - }, - { "HTTP/1.1 502 Bad Gateway\n" - "Chrome-Proxy: bypass=59\n", - BYPASS_EVENT_TYPE_SHORT, - }, - { "HTTP/1.1 502 Bad Gateway\n" - "Chrome-Proxy: bypass=59\n", - BYPASS_EVENT_TYPE_SHORT, - }, - { "HTTP/1.1 414 Request-URI Too Long\n", - BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX, - }, - { "HTTP/1.1 414 Request-URI Too Long\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_MAX, - }, - { "HTTP/1.1 407 Proxy Authentication Required\n", - BYPASS_EVENT_TYPE_MALFORMED_407, - }, - { "HTTP/1.1 407 Proxy Authentication Required\n" - "Proxy-Authenticate: Basic\n" - "Via: 1.1 Chrome-Compression-Proxy\n", - BYPASS_EVENT_TYPE_MAX, - } - }; + { + "HTTP/1.1 200 OK\n" + "Chrome-Proxy: bypass=0\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_MEDIUM, + }, + { + "HTTP/1.1 200 OK\n" + "Chrome-Proxy: bypass=1\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_SHORT, + }, + { + "HTTP/1.1 200 OK\n" + "Chrome-Proxy: bypass=59\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_SHORT, + }, + { + "HTTP/1.1 200 OK\n" + "Chrome-Proxy: bypass=60\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_MEDIUM, + }, + { + "HTTP/1.1 200 OK\n" + "Chrome-Proxy: bypass=300\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_MEDIUM, + }, + { + "HTTP/1.1 200 OK\n" + "Chrome-Proxy: bypass=301\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_LONG, + }, + { + "HTTP/1.1 200 OK\n" + "Chrome-Proxy: block-once\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_CURRENT, + }, + { + "HTTP/1.1 500 Internal Server Error\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_STATUS_500_HTTP_INTERNAL_SERVER_ERROR, + }, + { + "HTTP/1.1 501 Not Implemented\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_MAX, + }, + { + "HTTP/1.1 502 Bad Gateway\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY, + }, + { + "HTTP/1.1 503 Service Unavailable\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_STATUS_503_HTTP_SERVICE_UNAVAILABLE, + }, + { + "HTTP/1.1 504 Gateway Timeout\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_MAX, + }, + { + "HTTP/1.1 505 HTTP Version Not Supported\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_MAX, + }, + { + "HTTP/1.1 304 Not Modified\n", false, BYPASS_EVENT_TYPE_MAX, + }, + { + "HTTP/1.1 200 OK\n", false, + BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_OTHER, + }, + { + "HTTP/1.1 200 OK\n" + "Chrome-Proxy: bypass=59\n", + false, BYPASS_EVENT_TYPE_SHORT, + }, + { + "HTTP/1.1 502 Bad Gateway\n", false, + BYPASS_EVENT_TYPE_STATUS_502_HTTP_BAD_GATEWAY, + }, + { + "HTTP/1.1 502 Bad Gateway\n" + "Chrome-Proxy: bypass=59\n", + false, BYPASS_EVENT_TYPE_SHORT, + }, + { + "HTTP/1.1 502 Bad Gateway\n" + "Chrome-Proxy: bypass=59\n", + false, BYPASS_EVENT_TYPE_SHORT, + }, + { + "HTTP/1.1 414 Request-URI Too Long\n", false, + BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX, + }, + { + "HTTP/1.1 414 Request-URI Too Long\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_MAX, + }, + { + "HTTP/1.1 407 Proxy Authentication Required\n", false, + BYPASS_EVENT_TYPE_MALFORMED_407, + }, + { + "HTTP/1.1 407 Proxy Authentication Required\n" + "Proxy-Authenticate: Basic\n" + "Via: 1.1 Chrome-Compression-Proxy\n", + false, BYPASS_EVENT_TYPE_MAX, + }, + { + "HTTP/1.1 200 OK\n", true, BYPASS_EVENT_TYPE_MAX, + }, + { + "HTTP/1.1 414 Request-URI Too Long\n", true, + BYPASS_EVENT_TYPE_MISSING_VIA_HEADER_4XX, + }}; for (size_t i = 0; i < arraysize(tests); ++i) { std::string headers(tests[i].headers); HeadersToRaw(&headers); scoped_refptr<net::HttpResponseHeaders> parsed( new net::HttpResponseHeaders(headers)); DataReductionProxyInfo chrome_proxy_info; + + base::FieldTrialList trial_list(nullptr); + base::FieldTrialList::CreateFieldTrial( + "DataReductionProxyServerExperiments", + tests[i].in_tamper_detection_experiment ? "TamperDetection_Enabled" + : "TamperDetection_Disabled"); + EXPECT_EQ(tests[i].expected_result, GetDataReductionProxyBypassType( parsed.get(), &chrome_proxy_info)); }
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc index 6e2e90e..fe62c2f 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.cc
@@ -99,6 +99,11 @@ return FieldTrialList::FindFullName(GetLoFiFieldTrialName()) == kPreview; } +bool IsIncludedInTamperDetectionExperiment() { + return FieldTrialList::FindFullName("DataReductionProxyServerExperiments") + .find("TamperDetection_Enabled") == 0; +} + bool IsLoFiOnViaFlags() { return IsLoFiAlwaysOnViaFlags() || IsLoFiCellularOnlyViaFlags() || IsLoFiSlowConnectionsOnlyViaFlags();
diff --git a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h index 316ed5f..de5c528 100644 --- a/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h +++ b/components/data_reduction_proxy/core/common/data_reduction_proxy_params.h
@@ -63,6 +63,9 @@ // trial. bool IsIncludedInLoFiPreviewFieldTrial(); +// Returns true if this client is part of the tamper detection experiment. +bool IsIncludedInTamperDetectionExperiment(); + // Returns true if this client has any of the values to enable Lo-Fi mode for // the "data-reduction-proxy-lo-fi" command line switch. This includes the // "always-on", "cellular-only", and "slow-connections-only" values.
diff --git a/components/mus/gles2/command_buffer_local.cc b/components/mus/gles2/command_buffer_local.cc index 21ab722d..834722c 100644 --- a/components/mus/gles2/command_buffer_local.cc +++ b/components/mus/gles2/command_buffer_local.cc
@@ -83,6 +83,8 @@ next_image_id_(0), next_fence_sync_release_(1), flushed_fence_sync_release_(0), + sync_point_client_waiter_( + gpu_state->sync_point_manager()->CreateSyncPointClientWaiter()), weak_factory_(this) { weak_ptr_ = weak_factory_.GetWeakPtr(); } @@ -384,8 +386,18 @@ void CommandBufferLocal::SignalSyncToken(const gpu::SyncToken& sync_token, const base::Closure& callback) { DCHECK(CalledOnValidThread()); - // TODO(dyen) - NOTIMPLEMENTED(); + scoped_refptr<gpu::SyncPointClientState> release_state = + gpu_state_->sync_point_manager()->GetSyncPointClientState( + sync_token.namespace_id(), sync_token.command_buffer_id()); + if (!release_state || + release_state->IsFenceSyncReleased(sync_token.release_count())) { + callback.Run(); + return; + } + + sync_point_client_waiter_->WaitOutOfOrderNonThreadSafe( + release_state.get(), sync_token.release_count(), + client_thread_task_runner_, callback); } bool CommandBufferLocal::CanWaitUnverifiedSyncToken(
diff --git a/components/mus/gles2/command_buffer_local.h b/components/mus/gles2/command_buffer_local.h index beed42a..f234c86 100644 --- a/components/mus/gles2/command_buffer_local.h +++ b/components/mus/gles2/command_buffer_local.h
@@ -33,6 +33,10 @@ class GLSurface; } +namespace gpu { +class SyncPointClient; +} + namespace mus { class CommandBufferDriver; @@ -153,6 +157,9 @@ uint64_t next_fence_sync_release_; uint64_t flushed_fence_sync_release_; + // This sync point client is only for out of order Wait on client thread. + scoped_ptr<gpu::SyncPointClient> sync_point_client_waiter_; + base::WeakPtr<CommandBufferLocal> weak_ptr_; // This weak factory will be invalidated in the client thread, so all weak
diff --git a/components/nacl/loader/nacl_validation_query.cc b/components/nacl/loader/nacl_validation_query.cc index 034b8d6..1c69bbc 100644 --- a/components/nacl/loader/nacl_validation_query.cc +++ b/components/nacl/loader/nacl_validation_query.cc
@@ -10,7 +10,6 @@ #include "base/logging.h" #include "components/nacl/loader/nacl_validation_db.h" #include "crypto/nss_util.h" -#include "native_client/src/include/portability.h" #include "native_client/src/public/validation_cache.h" NaClValidationQueryContext::NaClValidationQueryContext(
diff --git a/components/nacl/renderer/plugin/nacl_subprocess.h b/components/nacl/renderer/plugin/nacl_subprocess.h index 9b2c684..93acb5b 100644 --- a/components/nacl/renderer/plugin/nacl_subprocess.h +++ b/components/nacl/renderer/plugin/nacl_subprocess.h
@@ -16,8 +16,6 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "components/nacl/renderer/plugin/service_runtime.h" -#include "native_client/src/include/nacl_macros.h" -#include "native_client/src/include/portability.h" namespace plugin { @@ -48,12 +46,12 @@ void Shutdown(); private: - NACL_DISALLOW_COPY_AND_ASSIGN(NaClSubprocess); - std::string description_; // The service runtime representing the NaCl module instance. scoped_ptr<ServiceRuntime> service_runtime_; + + DISALLOW_COPY_AND_ASSIGN(NaClSubprocess); }; } // namespace plugin
diff --git a/components/nacl/renderer/plugin/plugin.cc b/components/nacl/renderer/plugin/plugin.cc index dde2a2e..d85f1af 100644 --- a/components/nacl/renderer/plugin/plugin.cc +++ b/components/nacl/renderer/plugin/plugin.cc
@@ -15,10 +15,6 @@ #include "components/nacl/renderer/plugin/service_runtime.h" #include "components/nacl/renderer/plugin/utility.h" #include "components/nacl/renderer/ppb_nacl_private.h" -#include "native_client/src/include/nacl_base.h" -#include "native_client/src/include/nacl_macros.h" -#include "native_client/src/include/portability.h" -#include "native_client/src/include/portability_io.h" #include "ppapi/c/pp_errors.h" #include "ppapi/cpp/module.h"
diff --git a/components/nacl/renderer/plugin/plugin.h b/components/nacl/renderer/plugin/plugin.h index 46c5cfe..83574bb20 100644 --- a/components/nacl/renderer/plugin/plugin.h +++ b/components/nacl/renderer/plugin/plugin.h
@@ -21,7 +21,6 @@ #include "components/nacl/renderer/plugin/service_runtime.h" #include "components/nacl/renderer/plugin/utility.h" #include "components/nacl/renderer/ppb_nacl_private.h" -#include "native_client/src/include/nacl_macros.h" #include "ppapi/cpp/instance.h" #include "ppapi/cpp/private/uma_private.h" #include "ppapi/cpp/url_loader.h" @@ -97,7 +96,6 @@ const PPB_NaCl_Private* nacl_interface() const { return nacl_interface_; } private: - NACL_DISALLOW_COPY_AND_ASSIGN(Plugin); // The browser will invoke the destructor via the pp::Instance // pointer to this object, not from base's Delete(). ~Plugin() override; @@ -148,6 +146,8 @@ const PPB_NaCl_Private* nacl_interface_; pp::UMAPrivate uma_interface_; + + DISALLOW_COPY_AND_ASSIGN(Plugin); }; } // namespace plugin
diff --git a/components/nacl/renderer/plugin/plugin_error.h b/components/nacl/renderer/plugin/plugin_error.h index e1789cef..42825be 100644 --- a/components/nacl/renderer/plugin/plugin_error.h +++ b/components/nacl/renderer/plugin/plugin_error.h
@@ -15,7 +15,6 @@ #include "base/macros.h" #include "components/nacl/renderer/ppb_nacl_private.h" -#include "native_client/src/include/nacl_macros.h" namespace plugin { @@ -41,7 +40,7 @@ private: PP_NaClError error_code_; std::string message_; - NACL_DISALLOW_COPY_AND_ASSIGN(ErrorInfo); + DISALLOW_COPY_AND_ASSIGN(ErrorInfo); }; } // namespace plugin
diff --git a/components/nacl/renderer/plugin/pnacl_coordinator.h b/components/nacl/renderer/plugin/pnacl_coordinator.h index 999559d..b409c24 100644 --- a/components/nacl/renderer/plugin/pnacl_coordinator.h +++ b/components/nacl/renderer/plugin/pnacl_coordinator.h
@@ -15,7 +15,6 @@ #include "components/nacl/renderer/plugin/nacl_subprocess.h" #include "components/nacl/renderer/plugin/plugin_error.h" #include "components/nacl/renderer/plugin/pnacl_resources.h" -#include "native_client/src/include/nacl_macros.h" #include "ppapi/cpp/completion_callback.h" #include "ppapi/utility/completion_callback_factory.h" @@ -88,8 +87,6 @@ void BitcodeStreamDidFinish(int32_t pp_error); private: - NACL_DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator); - // BitcodeToNative is the factory method for PnaclCoordinators. // Therefore the constructor is private. PnaclCoordinator(Plugin* plugin, @@ -188,6 +185,8 @@ // It accesses fields of PnaclCoordinator so it must have a // shorter lifetime. scoped_ptr<PnaclTranslateThread> translate_thread_; + + DISALLOW_COPY_AND_ASSIGN(PnaclCoordinator); }; //----------------------------------------------------------------------
diff --git a/components/nacl/renderer/plugin/pnacl_resources.cc b/components/nacl/renderer/plugin/pnacl_resources.cc index 3fc80b9..dad0a1f 100644 --- a/components/nacl/renderer/plugin/pnacl_resources.cc +++ b/components/nacl/renderer/plugin/pnacl_resources.cc
@@ -11,7 +11,6 @@ #include "base/logging.h" #include "components/nacl/renderer/plugin/plugin.h" #include "components/nacl/renderer/plugin/utility.h" -#include "native_client/src/include/portability_io.h" #include "ppapi/c/pp_errors.h" namespace plugin {
diff --git a/components/nacl/renderer/plugin/pnacl_resources.h b/components/nacl/renderer/plugin/pnacl_resources.h index 25cb85fb..85288df 100644 --- a/components/nacl/renderer/plugin/pnacl_resources.h +++ b/components/nacl/renderer/plugin/pnacl_resources.h
@@ -7,7 +7,6 @@ #include "base/macros.h" #include "components/nacl/renderer/ppb_nacl_private.h" -#include "native_client/src/include/nacl_macros.h" #include "ppapi/cpp/completion_callback.h" namespace plugin { @@ -47,13 +46,13 @@ PP_NaClFileInfo TakeFileInfo(ResourceType type); private: - NACL_DISALLOW_COPY_AND_ASSIGN(PnaclResources); - // The plugin requesting the resource loading. Plugin* plugin_; bool use_subzero_; PnaclResourceEntry resources_[NUM_TYPES + 1]; + + DISALLOW_COPY_AND_ASSIGN(PnaclResources); }; } // namespace plugin
diff --git a/components/nacl/renderer/plugin/pnacl_translate_thread.h b/components/nacl/renderer/plugin/pnacl_translate_thread.h index 21248e33..1092d02 100644 --- a/components/nacl/renderer/plugin/pnacl_translate_thread.h +++ b/components/nacl/renderer/plugin/pnacl_translate_thread.h
@@ -13,7 +13,6 @@ #include "base/macros.h" #include "base/memory/scoped_ptr.h" #include "components/nacl/renderer/plugin/plugin_error.h" -#include "native_client/src/include/nacl_macros.h" #include "native_client/src/shared/platform/nacl_sync_checked.h" #include "native_client/src/shared/platform/nacl_threads.h" #include "ppapi/cpp/completion_callback.h" @@ -159,7 +158,7 @@ base::ProcessId ld_channel_peer_pid_; private: - NACL_DISALLOW_COPY_AND_ASSIGN(PnaclTranslateThread); + DISALLOW_COPY_AND_ASSIGN(PnaclTranslateThread); }; }
diff --git a/components/nacl/renderer/plugin/service_runtime.cc b/components/nacl/renderer/plugin/service_runtime.cc index c02e7dc..4d581f3 100644 --- a/components/nacl/renderer/plugin/service_runtime.cc +++ b/components/nacl/renderer/plugin/service_runtime.cc
@@ -14,9 +14,6 @@ #include "base/logging.h" #include "components/nacl/renderer/plugin/plugin.h" #include "components/nacl/renderer/plugin/utility.h" -#include "native_client/src/include/nacl_macros.h" -#include "native_client/src/include/portability_io.h" -#include "native_client/src/include/portability_string.h" #include "native_client/src/trusted/service_runtime/nacl_error_code.h" #include "ppapi/c/pp_errors.h" #include "ppapi/cpp/completion_callback.h"
diff --git a/components/nacl/renderer/plugin/service_runtime.h b/components/nacl/renderer/plugin/service_runtime.h index d5571ff..a0737253 100644 --- a/components/nacl/renderer/plugin/service_runtime.h +++ b/components/nacl/renderer/plugin/service_runtime.h
@@ -16,7 +16,6 @@ #include "base/process/process_handle.h" #include "components/nacl/renderer/plugin/utility.h" #include "ipc/ipc_sync_channel.h" -#include "native_client/src/include/nacl_macros.h" #include "native_client/src/shared/platform/nacl_sync.h" #include "ppapi/cpp/completion_callback.h" @@ -68,8 +67,6 @@ base::ProcessId get_process_id() { return process_id_; } private: - NACL_DISALLOW_COPY_AND_ASSIGN(ServiceRuntime); - Plugin* plugin_; PP_Instance pp_instance_; bool main_service_runtime_; @@ -77,6 +74,8 @@ scoped_ptr<IPC::SyncChannel> translator_channel_; base::ProcessId process_id_; + + DISALLOW_COPY_AND_ASSIGN(ServiceRuntime); }; } // namespace plugin
diff --git a/components/nacl/renderer/plugin/temporary_file.h b/components/nacl/renderer/plugin/temporary_file.h index 07bbdac..fe496f4d 100644 --- a/components/nacl/renderer/plugin/temporary_file.h +++ b/components/nacl/renderer/plugin/temporary_file.h
@@ -10,7 +10,6 @@ #include "base/files/file.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" -#include "native_client/src/include/nacl_macros.h" #include "ppapi/c/private/pp_file_handle.h" @@ -59,10 +58,10 @@ PP_FileHandle GetFileHandle(); private: - NACL_DISALLOW_COPY_AND_ASSIGN(TempFile); - Plugin* plugin_; base::File file_handle_; + + DISALLOW_COPY_AND_ASSIGN(TempFile); }; } // namespace plugin
diff --git a/components/nacl/renderer/plugin/utility.cc b/components/nacl/renderer/plugin/utility.cc index 6a31850..0a2536833 100644 --- a/components/nacl/renderer/plugin/utility.cc +++ b/components/nacl/renderer/plugin/utility.cc
@@ -9,8 +9,6 @@ #include <string.h> #include "components/nacl/renderer/plugin/utility.h" -#include "native_client/src/include/portability_io.h" -#include "native_client/src/include/portability_process.h" #include "ppapi/cpp/module.h" namespace plugin { @@ -63,47 +61,6 @@ return (NULL != env); } -bool IsValidIdentifierString(const char* strval, uint32_t* length) { - // This function is supposed to recognize valid ECMAScript identifiers, - // as described in - // http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-262.pdf - // It is currently restricted to only the ASCII subset. - // TODO(sehr): Recognize the full Unicode formulation of identifiers. - // TODO(sehr): Make this table-driven if efficiency becomes a problem. - if (NULL != length) { - *length = 0; - } - if (NULL == strval) { - return false; - } - static const char* kValidFirstChars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$_"; - static const char* kValidOtherChars = - "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$_" - "0123456789"; - if (NULL == strchr(kValidFirstChars, strval[0])) { - return false; - } - uint32_t pos; - for (pos = 1; ; ++pos) { - if (0 == pos) { - // Unsigned overflow. - return false; - } - int c = strval[pos]; - if (0 == c) { - break; - } - if (NULL == strchr(kValidOtherChars, c)) { - return false; - } - } - if (NULL != length) { - *length = pos; - } - return true; -} - // We cache the NaCl interface pointer and ensure that its set early on, on the // main thread. This allows GetNaClInterface() to be used from non-main threads. static const PPB_NaCl_Private* g_nacl_interface = NULL;
diff --git a/components/nacl/renderer/plugin/utility.h b/components/nacl/renderer/plugin/utility.h index 91d9e6c6..4bec52a7 100644 --- a/components/nacl/renderer/plugin/utility.h +++ b/components/nacl/renderer/plugin/utility.h
@@ -12,8 +12,6 @@ #include <stdint.h> #include "components/nacl/renderer/ppb_nacl_private.h" -#include "native_client/src/include/nacl_macros.h" -#include "native_client/src/include/portability.h" #include "native_client/src/shared/platform/nacl_threads.h" #include "native_client/src/shared/platform/nacl_time.h" #include "ppapi/c/private/pp_file_handle.h" @@ -22,14 +20,6 @@ namespace plugin { -// Tests that a string is a valid JavaScript identifier. According to the -// ECMAScript spec, this should be done in terms of unicode character -// categories. For now, we are simply limiting identifiers to the ASCII -// subset of that spec. If successful, it returns the length of the -// identifier in the location pointed to by length (if it is not NULL). -// TODO(sehr): add Unicode identifier support. -bool IsValidIdentifierString(const char* strval, uint32_t* length); - const PPB_NaCl_Private* GetNaClInterface(); void SetNaClInterface(const PPB_NaCl_Private* nacl_interface);
diff --git a/components/test_runner/web_content_settings.cc b/components/test_runner/web_content_settings.cc index 2d0ec1f..c0aa316 100644 --- a/components/test_runner/web_content_settings.cc +++ b/components/test_runner/web_content_settings.cc
@@ -61,7 +61,6 @@ bool WebContentSettings::allowDisplayingInsecureContent( bool enabled_per_settings, - const blink::WebSecurityOrigin&, const blink::WebURL&) { return enabled_per_settings || displaying_insecure_content_allowed_; }
diff --git a/components/test_runner/web_content_settings.h b/components/test_runner/web_content_settings.h index dab51ed..20f4b6e 100644 --- a/components/test_runner/web_content_settings.h +++ b/components/test_runner/web_content_settings.h
@@ -26,7 +26,6 @@ bool allowStorage(bool local) override; bool allowPlugins(bool enabledPerSettings) override; bool allowDisplayingInsecureContent(bool enabledPerSettings, - const blink::WebSecurityOrigin&, const blink::WebURL&) override; bool allowRunningInsecureContent(bool enabledPerSettings, const blink::WebSecurityOrigin&,
diff --git a/content/browser/appcache/appcache_interceptor.cc b/content/browser/appcache/appcache_interceptor.cc index 81985fe..050e66a 100644 --- a/content/browser/appcache/appcache_interceptor.cc +++ b/content/browser/appcache/appcache_interceptor.cc
@@ -9,6 +9,9 @@ #include "content/browser/appcache/appcache_request_handler.h" #include "content/browser/appcache/appcache_service_impl.h" #include "content/browser/appcache/appcache_url_request_job.h" +#include "content/browser/appcache/chrome_appcache_service.h" +#include "content/browser/bad_message.h" +#include "content/browser/loader/resource_message_filter.h" #include "content/common/appcache_interfaces.h" #include "net/url_request/url_request.h" @@ -76,10 +79,16 @@ void AppCacheInterceptor::CompleteCrossSiteTransfer( net::URLRequest* request, int new_process_id, - int new_host_id) { + int new_host_id, + ResourceMessageFilter* filter) { AppCacheRequestHandler* handler = GetHandler(request); if (!handler) return; + if (!handler->SanityCheckIsSameService(filter->appcache_service())) { + bad_message::ReceivedBadMessage(filter, + bad_message::ACI_WRONG_STORAGE_PARTITION); + return; + } DCHECK_NE(kAppCacheNoHostId, new_host_id); handler->CompleteCrossSiteTransfer(new_process_id, new_host_id);
diff --git a/content/browser/appcache/appcache_interceptor.h b/content/browser/appcache/appcache_interceptor.h index 0e50983..9d1abc31 100644 --- a/content/browser/appcache/appcache_interceptor.h +++ b/content/browser/appcache/appcache_interceptor.h
@@ -21,6 +21,7 @@ namespace content { class AppCacheRequestHandler; class AppCacheServiceImpl; +class ResourceMessageFilter; // An interceptor to hijack requests and potentially service them out of // the appcache. @@ -45,7 +46,8 @@ int old_process_id); static void CompleteCrossSiteTransfer(net::URLRequest* request, int new_process_id, - int new_host_id); + int new_host_id, + ResourceMessageFilter* filter); static void MaybeCompleteCrossSiteTransferInOldProcess( net::URLRequest* request, int old_process_id);
diff --git a/content/browser/appcache/appcache_request_handler.cc b/content/browser/appcache/appcache_request_handler.cc index c0222375..0a00878 100644 --- a/content/browser/appcache/appcache_request_handler.cc +++ b/content/browser/appcache/appcache_request_handler.cc
@@ -187,6 +187,7 @@ if (!host_) return; AppCacheBackendImpl* backend = host_->service()->GetBackend(old_process_id); + DCHECK(backend) << "appcache detected likely storage partition mismatch"; old_process_id_ = old_process_id; old_host_id_ = host_->host_id(); host_for_cross_site_transfer_ = backend->TransferHostOut(host_->host_id()); @@ -199,6 +200,7 @@ return; DCHECK_EQ(host_, host_for_cross_site_transfer_.get()); AppCacheBackendImpl* backend = host_->service()->GetBackend(new_process_id); + DCHECK(backend) << "appcache detected likely storage partition mismatch"; backend->TransferHostIn(new_host_id, std::move(host_for_cross_site_transfer_)); }
diff --git a/content/browser/appcache/appcache_request_handler.h b/content/browser/appcache/appcache_request_handler.h index d7b55e5a..7665d10e 100644 --- a/content/browser/appcache/appcache_request_handler.h +++ b/content/browser/appcache/appcache_request_handler.h
@@ -25,6 +25,7 @@ namespace content { class AppCacheRequestHandlerTest; +class AppCacheService; class AppCacheURLRequestJob; // An instance is created for each net::URLRequest. The instance survives all @@ -58,6 +59,12 @@ void CompleteCrossSiteTransfer(int new_process_id, int new_host_id); void MaybeCompleteCrossSiteTransferInOldProcess(int old_process_id); + // Useful for detecting storage partition mismatches in the context + // of cross site transfer navigations. + bool SanityCheckIsSameService(AppCacheService* service) { + return !host_ || (host_->service() == service); + } + static bool IsMainResourceType(ResourceType type) { return IsResourceTypeFrame(type) || type == RESOURCE_TYPE_SHARED_WORKER;
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h index 219cc12..4f01fe9 100644 --- a/content/browser/bad_message.h +++ b/content/browser/bad_message.h
@@ -126,6 +126,8 @@ RFMF_RENDERER_FAKED_ITS_OWN_DEATH = 102, DWNLD_INVALID_SAVABLE_RESOURCE_LINKS_RESPONSE = 103, DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE = 104, + BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN = 105, + ACI_WRONG_STORAGE_PARTITION = 106, // Please add new elements here. The naming convention is abbreviated class // name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
diff --git a/content/browser/bluetooth/bluetooth_allowed_devices_map.cc b/content/browser/bluetooth/bluetooth_allowed_devices_map.cc new file mode 100644 index 0000000..36fce422 --- /dev/null +++ b/content/browser/bluetooth/bluetooth_allowed_devices_map.cc
@@ -0,0 +1,155 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/bluetooth/bluetooth_allowed_devices_map.h" + +#include <vector> + +#include "base/base64.h" +#include "base/logging.h" +#include "base/stl_util.h" +#include "base/strings/string_util.h" +#include "content/common/bluetooth/bluetooth_scan_filter.h" +#include "crypto/random.h" +#include "device/bluetooth/bluetooth_uuid.h" + +using device::BluetoothUUID; + +namespace content { + +namespace { +const size_t kIdLength = 16 /* 128bits */; + +std::string GetBase64Id() { + std::string bytes( + kIdLength + 1 /* to avoid bytes being reallocated by WriteInto */, '\0'); + + crypto::RandBytes( + base::WriteInto(&bytes /* str */, kIdLength + 1 /* length_with_null */), + kIdLength); + + base::Base64Encode(bytes, &bytes); + + return bytes; +} +} // namespace + +BluetoothAllowedDevicesMap::BluetoothAllowedDevicesMap() {} +BluetoothAllowedDevicesMap::~BluetoothAllowedDevicesMap() {} + +const std::string& BluetoothAllowedDevicesMap::AddDevice( + const url::Origin& origin, + const std::string& device_address, + const std::vector<BluetoothScanFilter>& filters, + const std::vector<BluetoothUUID>& optional_services) { + VLOG(1) << "Adding a device to Map of Allowed Devices."; + + // "Unique" Origins generate the same key in maps. The set of "unique" + // Origins that generate the same key does not intersect the set of + // potentially trustworthy origins; since Bluetooth is only available for + // potntially trustworthy origins we should never receive a request from a + // "unique" Origin. + // See url::Origin for what constitutes a "unique" Origin and the + // Secure Contexts spec for what constitutes a Trusworthy Origin: + // https://w3c.github.io/webappsec-secure-contexts/ + CHECK(!origin.unique()); + + if (ContainsKey(origin_to_device_address_to_id_map_[origin], + device_address)) { + VLOG(1) << "Device already in map of allowed devices."; + return origin_to_device_address_to_id_map_[origin][device_address]; + } + const std::string device_id = GenerateDeviceId(); + VLOG(1) << "Id generated for device: " << device_id; + + origin_to_device_address_to_id_map_[origin][device_address] = device_id; + origin_to_device_id_to_address_map_[origin][device_id] = device_address; + origin_to_device_id_to_services_map_[origin][device_id] = + UnionOfServices(filters, optional_services); + + CHECK(device_id_set_.insert(device_id).second); + + return origin_to_device_address_to_id_map_[origin][device_address]; +} + +void BluetoothAllowedDevicesMap::RemoveDevice( + const url::Origin& origin, + const std::string& device_address) { + const std::string device_id = GetDeviceId(origin, device_address); + DCHECK(!device_id.empty()); + + // 1. Remove from all three maps. + CHECK(origin_to_device_address_to_id_map_[origin].erase(device_address)); + CHECK(origin_to_device_id_to_address_map_[origin].erase(device_id)); + CHECK(origin_to_device_id_to_services_map_[origin].erase(device_id)); + + // 2. Remove empty map for origin. + if (origin_to_device_address_to_id_map_[origin].empty()) { + CHECK(origin_to_device_address_to_id_map_.erase(origin)); + CHECK(origin_to_device_id_to_address_map_.erase(origin)); + CHECK(origin_to_device_id_to_services_map_.erase(origin)); + } + + // 3. Remove from set of ids. + CHECK(device_id_set_.erase(device_id)); +} + +const std::string& BluetoothAllowedDevicesMap::GetDeviceId( + const url::Origin& origin, + const std::string& device_address) { + auto address_map_iter = origin_to_device_address_to_id_map_.find(origin); + if (address_map_iter == origin_to_device_address_to_id_map_.end()) { + return base::EmptyString(); + } + + const auto& device_address_to_id_map = address_map_iter->second; + + auto id_iter = device_address_to_id_map.find(device_address); + if (id_iter == device_address_to_id_map.end()) { + return base::EmptyString(); + } + return id_iter->second; +} + +const std::string& BluetoothAllowedDevicesMap::GetDeviceAddress( + const url::Origin& origin, + const std::string& device_id) { + auto id_map_iter = origin_to_device_id_to_address_map_.find(origin); + if (id_map_iter == origin_to_device_id_to_address_map_.end()) { + return base::EmptyString(); + } + + const auto& device_id_to_address_map = id_map_iter->second; + + auto id_iter = device_id_to_address_map.find(device_id); + + return id_iter == device_id_to_address_map.end() ? base::EmptyString() + : id_iter->second; +} + +std::string BluetoothAllowedDevicesMap::GenerateDeviceId() { + std::string device_id = GetBase64Id(); + while (ContainsKey(device_id_set_, device_id)) { + LOG(WARNING) << "Generated repeated id."; + device_id = GetBase64Id(); + } + return device_id; +} + +std::set<std::string> BluetoothAllowedDevicesMap::UnionOfServices( + const std::vector<BluetoothScanFilter>& filters, + const std::vector<BluetoothUUID>& optional_services) { + std::set<std::string> unionOfServices; + for (const auto& filter : filters) { + for (const BluetoothUUID& uuid : filter.services) { + unionOfServices.insert(uuid.canonical_value()); + } + } + for (const BluetoothUUID& uuid : optional_services) { + unionOfServices.insert(uuid.canonical_value()); + } + return unionOfServices; +} + +} // namespace content
diff --git a/content/browser/bluetooth/bluetooth_allowed_devices_map.h b/content/browser/bluetooth/bluetooth_allowed_devices_map.h new file mode 100644 index 0000000..d774e9e --- /dev/null +++ b/content/browser/bluetooth/bluetooth_allowed_devices_map.h
@@ -0,0 +1,86 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_ +#define CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_ + +#include <map> +#include <set> +#include <vector> + +#include "base/memory/scoped_ptr.h" +#include "content/common/content_export.h" +#include "url/origin.h" + +namespace device { +class BluetoothUUID; +} + +namespace content { + +struct BluetoothScanFilter; + +// Keeps track of which origins are allowed to access which devices and +// their services. +// +// |AddDevice| generates device ids, which are random strings that are unique +// in the map. +class CONTENT_EXPORT BluetoothAllowedDevicesMap final { + public: + BluetoothAllowedDevicesMap(); + ~BluetoothAllowedDevicesMap(); + + // Adds the Bluetooth Device with |device_address| to the map of allowed + // devices for that origin. Generates and returns a device id. + const std::string& AddDevice( + const url::Origin& origin, + const std::string& device_address, + const std::vector<BluetoothScanFilter>& filters, + const std::vector<device::BluetoothUUID>& optional_services); + + // Removes the Bluetooth Device with |device_address| from the map of allowed + // devices for |origin|. + void RemoveDevice(const url::Origin& origin, + const std::string& device_address); + + // TODO(ortuno): Add function to check if origin is allowed to access + // a device's service and add tests for that function. + // https://crbug.com/493460 + + // Returns the Bluetooth Device's id for |origin|. Returns an empty string + // if |origin| is not allowed to access the device. + const std::string& GetDeviceId(const url::Origin& origin, + const std::string& device_address); + + // For |device_id| in |origin|, returns the Bluetooth device's address. If + // there is no such |device_id| in |origin|, returns an empty string. + const std::string& GetDeviceAddress(const url::Origin& origin, + const std::string& device_id); + + private: + typedef std::map<std::string, std::string> DeviceAddressToIdMap; + typedef std::map<std::string, std::string> DeviceIdToAddressMap; + typedef std::map<std::string, std::set<std::string>> DeviceIdToServicesMap; + + // Returns an id guaranteed to be unique for the map. The id is randomly + // generated so that an origin can't guess the id used in another origin. + std::string GenerateDeviceId(); + std::set<std::string> UnionOfServices( + const std::vector<BluetoothScanFilter>& filters, + const std::vector<device::BluetoothUUID>& optional_services); + + std::map<url::Origin, DeviceAddressToIdMap> + origin_to_device_address_to_id_map_; + std::map<url::Origin, DeviceIdToAddressMap> + origin_to_device_id_to_address_map_; + std::map<url::Origin, DeviceIdToServicesMap> + origin_to_device_id_to_services_map_; + + // Keep track of all device_ids in the map. + std::set<std::string> device_id_set_; +}; + +} // namespace content + +#endif // CONTENT_BROWSER_BLUETOOTH_BLUETOOTH_ALLOWED_DEVICES_MAP_
diff --git a/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc b/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc new file mode 100644 index 0000000..2d5243a --- /dev/null +++ b/content/browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc
@@ -0,0 +1,167 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/browser/bluetooth/bluetooth_allowed_devices_map.h" + +#include "base/strings/string_util.h" +#include "content/common/bluetooth/bluetooth_scan_filter.h" +#include "device/bluetooth/bluetooth_uuid.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "url/gurl.h" + +namespace content { +namespace { +const url::Origin test_origin1(GURL("https://www.example1.com")); +const url::Origin test_origin2(GURL("https://www.example2.com")); + +const std::string device_address1 = "00:00:00"; +const std::string device_address2 = "11:11:11"; + +const std::vector<content::BluetoothScanFilter> filters = + std::vector<BluetoothScanFilter>(); +const std::vector<device::BluetoothUUID> optional_services = + std::vector<device::BluetoothUUID>(); +} // namespace + +class BluetoothAllowedDevicesMapTest : public testing::Test {}; + +TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceToMap) { + BluetoothAllowedDevicesMap allowed_devices_map; + + const std::string& device_id = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + + // Test that we can retrieve the device address/id. + EXPECT_EQ(device_id, + allowed_devices_map.GetDeviceId(test_origin1, device_address1)); + EXPECT_EQ(device_address1, + allowed_devices_map.GetDeviceAddress(test_origin1, device_id)); +} + +TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceToMapTwice) { + BluetoothAllowedDevicesMap allowed_devices_map; + const std::string& device_id1 = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + const std::string& device_id2 = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + + EXPECT_EQ(device_id1, device_id2); + + // Test that we can retrieve the device address/id. + EXPECT_EQ(device_id1, + allowed_devices_map.GetDeviceId(test_origin1, device_address1)); + EXPECT_EQ(device_address1, + allowed_devices_map.GetDeviceAddress(test_origin1, device_id1)); +} + +TEST_F(BluetoothAllowedDevicesMapTest, AddTwoDevicesFromSameOriginToMap) { + BluetoothAllowedDevicesMap allowed_devices_map; + const std::string& device_id1 = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + const std::string& device_id2 = allowed_devices_map.AddDevice( + test_origin1, device_address2, filters, optional_services); + + EXPECT_NE(device_id1, device_id2); + + // Test that we can retrieve the device address/id. + EXPECT_EQ(device_id1, + allowed_devices_map.GetDeviceId(test_origin1, device_address1)); + EXPECT_EQ(device_id2, + allowed_devices_map.GetDeviceId(test_origin1, device_address2)); + + EXPECT_EQ(device_address1, + allowed_devices_map.GetDeviceAddress(test_origin1, device_id1)); + EXPECT_EQ(device_address2, + allowed_devices_map.GetDeviceAddress(test_origin1, device_id2)); +} + +TEST_F(BluetoothAllowedDevicesMapTest, AddTwoDevicesFromTwoOriginsToMap) { + BluetoothAllowedDevicesMap allowed_devices_map; + const std::string& device_id1 = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + const std::string& device_id2 = allowed_devices_map.AddDevice( + test_origin2, device_address2, filters, optional_services); + + EXPECT_NE(device_id1, device_id2); + + // Test that the wrong origin doesn't have access to the device. + + EXPECT_EQ(base::EmptyString(), + allowed_devices_map.GetDeviceId(test_origin1, device_address2)); + EXPECT_EQ(base::EmptyString(), + allowed_devices_map.GetDeviceId(test_origin2, device_address1)); + + EXPECT_EQ(base::EmptyString(), + allowed_devices_map.GetDeviceAddress(test_origin1, device_id2)); + EXPECT_EQ(base::EmptyString(), + allowed_devices_map.GetDeviceAddress(test_origin2, device_id1)); + + // Test that we can retrieve the device address/id. + EXPECT_EQ(device_id1, + allowed_devices_map.GetDeviceId(test_origin1, device_address1)); + EXPECT_EQ(device_id2, + allowed_devices_map.GetDeviceId(test_origin2, device_address2)); + + EXPECT_EQ(device_address1, + allowed_devices_map.GetDeviceAddress(test_origin1, device_id1)); + EXPECT_EQ(device_address2, + allowed_devices_map.GetDeviceAddress(test_origin2, device_id2)); +} + +TEST_F(BluetoothAllowedDevicesMapTest, AddDeviceFromTwoOriginsToMap) { + BluetoothAllowedDevicesMap allowed_devices_map; + const std::string& device_id1 = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + const std::string& device_id2 = allowed_devices_map.AddDevice( + test_origin2, device_address1, filters, optional_services); + + EXPECT_NE(device_id1, device_id2); + + // Test that the wrong origin doesn't have access to the device. + EXPECT_EQ(base::EmptyString(), + allowed_devices_map.GetDeviceAddress(test_origin1, device_id2)); + EXPECT_EQ(base::EmptyString(), + allowed_devices_map.GetDeviceAddress(test_origin2, device_id1)); +} + +TEST_F(BluetoothAllowedDevicesMapTest, AddRemoveAddDeviceToMap) { + BluetoothAllowedDevicesMap allowed_devices_map; + const std::string device_id_first_time = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + + allowed_devices_map.RemoveDevice(test_origin1, device_address1); + + const std::string device_id_second_time = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + + EXPECT_NE(device_id_first_time, device_id_second_time); +} + +TEST_F(BluetoothAllowedDevicesMapTest, RemoveDeviceFromMap) { + BluetoothAllowedDevicesMap allowed_devices_map; + + const std::string& device_id = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + + allowed_devices_map.RemoveDevice(test_origin1, device_address1); + + EXPECT_EQ(base::EmptyString(), + allowed_devices_map.GetDeviceId(test_origin1, device_id)); + EXPECT_EQ(base::EmptyString(), allowed_devices_map.GetDeviceAddress( + test_origin1, device_address1)); +} + +TEST_F(BluetoothAllowedDevicesMapTest, CorrectIdFormat) { + BluetoothAllowedDevicesMap allowed_devices_map; + + const std::string& device_id = allowed_devices_map.AddDevice( + test_origin1, device_address1, filters, optional_services); + + EXPECT_TRUE(device_id.size() == 24) + << "Expected Lenghth of a 128bit string encoded to Base64."; + EXPECT_TRUE((device_id[22] == '=') && (device_id[23] == '=')) + << "Expected padding characters for a 128bit string encoded to Base64."; +} + +} // namespace content
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.cc b/content/browser/bluetooth/bluetooth_dispatcher_host.cc index fcb4ada..deb626df 100644 --- a/content/browser/bluetooth/bluetooth_dispatcher_host.cc +++ b/content/browser/bluetooth/bluetooth_dispatcher_host.cc
@@ -279,6 +279,7 @@ IPC_BEGIN_MESSAGE_MAP(BluetoothDispatcherHost, message) IPC_MESSAGE_HANDLER(BluetoothHostMsg_RequestDevice, OnRequestDevice) IPC_MESSAGE_HANDLER(BluetoothHostMsg_ConnectGATT, OnConnectGATT) + IPC_MESSAGE_HANDLER(BluetoothHostMsg_Disconnect, OnDisconnect) IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetPrimaryService, OnGetPrimaryService) IPC_MESSAGE_HANDLER(BluetoothHostMsg_GetCharacteristic, OnGetCharacteristic) IPC_MESSAGE_HANDLER(BluetoothHostMsg_ReadValue, OnReadValue) @@ -321,8 +322,7 @@ characteristic_to_service_.clear(); characteristic_id_to_notify_session_.clear(); active_characteristic_threads_.clear(); - connections_.clear(); - devices_with_discovered_services_.clear(); + device_id_to_connection_map_.clear(); } set_adapter(std::move(mock_adapter)); @@ -340,10 +340,12 @@ public: RequestDeviceSession(int thread_id, int request_id, + url::Origin origin, const std::vector<BluetoothScanFilter>& filters, const std::vector<BluetoothUUID>& optional_services) : thread_id(thread_id), request_id(request_id), + origin(origin), filters(filters), optional_services(optional_services) {} @@ -369,6 +371,7 @@ const int thread_id; const int request_id; + const url::Origin origin; const std::vector<BluetoothScanFilter> filters; const std::vector<BluetoothUUID> optional_services; scoped_ptr<BluetoothChooser> chooser; @@ -432,7 +435,6 @@ void BluetoothDispatcherHost::set_adapter( scoped_refptr<device::BluetoothAdapter> adapter) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - connections_.clear(); if (adapter_.get()) adapter_->RemoveObserver(this); adapter_ = adapter; @@ -521,12 +523,10 @@ device::BluetoothAdapter* adapter, device::BluetoothDevice* device) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - const std::string& device_id = device->GetAddress(); - VLOG(1) << "Services discovered for device: " << device_id; + const std::string& device_address = device->GetAddress(); + VLOG(1) << "Services discovered for device: " << device_address; - devices_with_discovered_services_.insert(device_id); - - auto iter = pending_primary_services_requests_.find(device_id); + auto iter = pending_primary_services_requests_.find(device_address); if (iter == pending_primary_services_requests_.end()) { return; } @@ -556,7 +556,7 @@ break; } } - DCHECK(!ContainsKey(pending_primary_services_requests_, device_id)) + DCHECK(!ContainsKey(pending_primary_services_requests_, device_address)) << "Sending get-service responses unexpectedly queued another request."; } @@ -661,7 +661,8 @@ // Create storage for the information that backs the chooser, and show the // chooser. RequestDeviceSession* const session = new RequestDeviceSession( - thread_id, request_id, filters, optional_services); + thread_id, request_id, render_frame_host->GetLastCommittedOrigin(), + filters, optional_services); int chooser_id = request_device_sessions_.Add(session); BluetoothChooser::EventHandler chooser_event_handler = @@ -672,6 +673,8 @@ if (WebContentsDelegate* delegate = web_contents->GetDelegate()) { session->chooser = delegate->RunBluetoothChooser( web_contents, chooser_event_handler, + // TODO(ortuno): Replace with GetLastCommittedOrigin. + // http://crbug.com/577451 render_frame_host->GetLastCommittedURL().GetOrigin()); } } @@ -713,17 +716,14 @@ void BluetoothDispatcherHost::OnConnectGATT(int thread_id, int request_id, + int frame_routing_id, const std::string& device_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::CONNECT_GATT); const base::TimeTicks start_time = base::TimeTicks::Now(); - // TODO(ortuno): Right now it's pointless to check if the domain has access to - // the device, because any domain can connect to any device. But once - // permissions are implemented we should check that the domain has access to - // the device. https://crbug.com/484745 - - const CacheQueryResult query_result = QueryCacheForDevice(device_id); + const CacheQueryResult query_result = + QueryCacheForDevice(GetOrigin(frame_routing_id), device_id); if (query_result.outcome != CacheQueryOutcome::SUCCESS) { RecordConnectGATTOutcome(query_result.outcome); @@ -732,6 +732,17 @@ return; } + // If we are already connected no need to connect again. + auto connection_iter = device_id_to_connection_map_.find(device_id); + if (connection_iter != device_id_to_connection_map_.end()) { + if (connection_iter->second->IsConnected()) { + VLOG(1) << "Already connected."; + Send(new BluetoothMsg_ConnectGATTSuccess(thread_id, request_id, + device_id)); + return; + } + } + query_result.device->CreateGattConnection( base::Bind(&BluetoothDispatcherHost::OnGATTConnectionCreated, weak_ptr_on_ui_thread_, thread_id, request_id, device_id, @@ -741,21 +752,46 @@ start_time)); } +void BluetoothDispatcherHost::OnDisconnect(int thread_id, + int frame_routing_id, + const std::string& device_id) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + RecordWebBluetoothFunctionCall( + UMAWebBluetoothFunction::REMOTE_GATT_SERVER_DISCONNECT); + + // Make sure the origin is allowed to access the device. We perform this check + // in case a hostile renderer is trying to disconnect a device that the + // renderer is not allowed to access. + if (allowed_devices_map_.GetDeviceAddress(GetOrigin(frame_routing_id), + device_id) + .empty()) { + bad_message::ReceivedBadMessage( + this, bad_message::BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN); + return; + } + + // The last BluetoothGattConnection for a device closes the connection when + // it's destroyed. + if (device_id_to_connection_map_.erase(device_id)) { + VLOG(1) << "Disconnecting device: " << device_id; + } +} + void BluetoothDispatcherHost::OnGetPrimaryService( int thread_id, int request_id, + int frame_routing_id, const std::string& device_id, const std::string& service_uuid) { DCHECK_CURRENTLY_ON(BrowserThread::UI); RecordWebBluetoothFunctionCall(UMAWebBluetoothFunction::GET_PRIMARY_SERVICE); RecordGetPrimaryServiceService(BluetoothUUID(service_uuid)); - // TODO(ortuno): Check if device_id is in "allowed devices" - // https://crbug.com/493459 // TODO(ortuno): Check if service_uuid is in "allowed services" // https://crbug.com/493460 - const CacheQueryResult query_result = QueryCacheForDevice(device_id); + const CacheQueryResult query_result = + QueryCacheForDevice(GetOrigin(frame_routing_id), device_id); if (query_result.outcome != CacheQueryOutcome::SUCCESS) { RecordGetPrimaryServiceOutcome(query_result.outcome); @@ -788,7 +824,7 @@ } // 3. - if (IsServicesDiscoveryCompleteForDevice(device_id)) { + if (query_result.device->IsGattServicesDiscoveryComplete()) { VLOG(1) << "Service not found in device."; RecordGetPrimaryServiceOutcome(UMAGetPrimaryServiceOutcome::NOT_FOUND); Send(new BluetoothMsg_GetPrimaryServiceError( @@ -799,7 +835,7 @@ VLOG(1) << "Adding service request to pending requests."; // 4. AddToPendingPrimaryServicesRequest( - device_id, + query_result.device->GetAddress(), PrimaryServicesRequest(thread_id, request_id, service_uuid, PrimaryServicesRequest::GET_PRIMARY_SERVICE)); } @@ -807,6 +843,7 @@ void BluetoothDispatcherHost::OnGetCharacteristic( int thread_id, int request_id, + int frame_routing_id, const std::string& service_instance_id, const std::string& characteristic_uuid) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -814,7 +851,7 @@ RecordGetCharacteristicCharacteristic(characteristic_uuid); const CacheQueryResult query_result = - QueryCacheForService(service_instance_id); + QueryCacheForService(GetOrigin(frame_routing_id), service_instance_id); if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { return; @@ -857,13 +894,14 @@ void BluetoothDispatcherHost::OnReadValue( int thread_id, int request_id, + int frame_routing_id, const std::string& characteristic_instance_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); RecordWebBluetoothFunctionCall( UMAWebBluetoothFunction::CHARACTERISTIC_READ_VALUE); - const CacheQueryResult query_result = - QueryCacheForCharacteristic(characteristic_instance_id); + const CacheQueryResult query_result = QueryCacheForCharacteristic( + GetOrigin(frame_routing_id), characteristic_instance_id); if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { return; @@ -886,6 +924,7 @@ void BluetoothDispatcherHost::OnWriteValue( int thread_id, int request_id, + int frame_routing_id, const std::string& characteristic_instance_id, const std::vector<uint8_t>& value) { DCHECK_CURRENTLY_ON(BrowserThread::UI); @@ -903,8 +942,8 @@ return; } - const CacheQueryResult query_result = - QueryCacheForCharacteristic(characteristic_instance_id); + const CacheQueryResult query_result = QueryCacheForCharacteristic( + GetOrigin(frame_routing_id), characteristic_instance_id); if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { return; @@ -927,6 +966,7 @@ void BluetoothDispatcherHost::OnStartNotifications( int thread_id, int request_id, + int frame_routing_id, const std::string& characteristic_instance_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); RecordWebBluetoothFunctionCall( @@ -944,8 +984,8 @@ // TODO(ortuno): Check if notify/indicate bit is set. // http://crbug.com/538869 - const CacheQueryResult query_result = - QueryCacheForCharacteristic(characteristic_instance_id); + const CacheQueryResult query_result = QueryCacheForCharacteristic( + GetOrigin(frame_routing_id), characteristic_instance_id); if (query_result.outcome == CacheQueryOutcome::BAD_RENDERER) { return; @@ -968,11 +1008,20 @@ void BluetoothDispatcherHost::OnStopNotifications( int thread_id, int request_id, + int frame_routing_id, const std::string& characteristic_instance_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); RecordWebBluetoothFunctionCall( UMAWebBluetoothFunction::CHARACTERISTIC_STOP_NOTIFICATIONS); + // Check the origin is allowed to access the device. We perform this check in + // case a hostile renderer is trying to stop notifications for a device + // that the renderer is not allowed to access. + if (!CanFrameAccessCharacteristicInstance(frame_routing_id, + characteristic_instance_id)) { + return; + } + auto notify_session_iter = characteristic_id_to_notify_session_.find(characteristic_instance_id); if (notify_session_iter == characteristic_id_to_notify_session_.end()) { @@ -987,13 +1036,20 @@ void BluetoothDispatcherHost::OnRegisterCharacteristicObject( int thread_id, + int frame_routing_id, const std::string& characteristic_instance_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + // Make sure the origin is allowed to access the device. + if (!CanFrameAccessCharacteristicInstance(frame_routing_id, + characteristic_instance_id)) { + return; + } active_characteristic_threads_[characteristic_instance_id].insert(thread_id); } void BluetoothDispatcherHost::OnUnregisterCharacteristicObject( int thread_id, + int frame_routing_id, const std::string& characteristic_instance_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); auto active_iter = @@ -1119,6 +1175,8 @@ DCHECK_EQ(static_cast<int>(event), static_cast<int>(BluetoothChooser::Event::SELECTED)); + // |device_id| is the Device Address that RequestDeviceSession passed to + // chooser->AddDevice(). const device::BluetoothDevice* const device = adapter_->GetDevice(device_id); if (device == nullptr) { VLOG(1) << "Device " << device_id << " no longer in adapter"; @@ -1135,8 +1193,12 @@ for (BluetoothUUID uuid : device->GetUUIDs()) VLOG(1) << "\t" << uuid.canonical_value(); + const std::string& device_id_for_origin = allowed_devices_map_.AddDevice( + session->origin, device->GetAddress(), session->filters, + session->optional_services); + content::BluetoothDevice device_ipc( - device->GetAddress(), // id + device_id_for_origin, // id device->GetName(), // name content::BluetoothDevice::ValidatePower( device->GetInquiryTxPower()), // tx_power @@ -1162,7 +1224,7 @@ base::TimeTicks start_time, scoped_ptr<device::BluetoothGattConnection> connection) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - connections_.push_back(std::move(connection)); + device_id_to_connection_map_[device_id] = std::move(connection); RecordConnectGATTTimeSuccess(base::TimeTicks::Now() - start_time); RecordConnectGATTOutcome(UMAConnectGATTOutcome::SUCCESS); Send(new BluetoothMsg_ConnectGATTSuccess(thread_id, request_id, device_id)); @@ -1189,13 +1251,13 @@ int thread_id, int request_id) { const std::string& service_identifier = service.GetIdentifier(); - const std::string& device_id = service.GetDevice()->GetAddress(); + const std::string& device_address = service.GetDevice()->GetAddress(); auto insert_result = - service_to_device_.insert(make_pair(service_identifier, device_id)); + service_to_device_.insert(make_pair(service_identifier, device_address)); // If a value is already in map, DCHECK it's valid. if (!insert_result.second) - DCHECK_EQ(insert_result.first->second, device_id); + DCHECK_EQ(insert_result.first->second, device_address); RecordGetPrimaryServiceOutcome(UMAGetPrimaryServiceOutcome::SUCCESS); Send(new BluetoothMsg_GetPrimaryServiceSuccess(thread_id, request_id, @@ -1276,9 +1338,19 @@ } BluetoothDispatcherHost::CacheQueryResult -BluetoothDispatcherHost::QueryCacheForDevice(const std::string& device_id) { +BluetoothDispatcherHost::QueryCacheForDevice(const url::Origin& origin, + const std::string& device_id) { + const std::string& device_address = + allowed_devices_map_.GetDeviceAddress(origin, device_id); + if (device_address.empty()) { + bad_message::ReceivedBadMessage( + this, bad_message::BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN); + return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER); + } + CacheQueryResult result; - result.device = adapter_->GetDevice(device_id); + result.device = adapter_->GetDevice(device_address); + // When a device can't be found in the BluetoothAdapter, that generally // indicates that it's gone out of range. We reject with a NetworkError in // that case. @@ -1291,6 +1363,7 @@ BluetoothDispatcherHost::CacheQueryResult BluetoothDispatcherHost::QueryCacheForService( + const url::Origin& origin, const std::string& service_instance_id) { auto device_iter = service_to_device_.find(service_instance_id); @@ -1300,10 +1373,16 @@ return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER); } - // TODO(ortuno): Check if domain has access to device. - // https://crbug.com/493459 + const std::string& device_id = + allowed_devices_map_.GetDeviceId(origin, device_iter->second); + // Kill the renderer if the origin is not allowed to access the device. + if (device_id.empty()) { + bad_message::ReceivedBadMessage( + this, bad_message::BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN); + return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER); + } - CacheQueryResult result = QueryCacheForDevice(device_iter->second); + CacheQueryResult result = QueryCacheForDevice(origin, device_id); if (result.outcome != CacheQueryOutcome::SUCCESS) { return result; @@ -1318,6 +1397,7 @@ BluetoothDispatcherHost::CacheQueryResult BluetoothDispatcherHost::QueryCacheForCharacteristic( + const url::Origin& origin, const std::string& characteristic_instance_id) { auto characteristic_iter = characteristic_to_service_.find(characteristic_instance_id); @@ -1329,7 +1409,8 @@ return CacheQueryResult(CacheQueryOutcome::BAD_RENDERER); } - CacheQueryResult result = QueryCacheForService(characteristic_iter->second); + CacheQueryResult result = + QueryCacheForService(origin, characteristic_iter->second); if (result.outcome != CacheQueryOutcome::SUCCESS) { return result; } @@ -1344,15 +1425,23 @@ return result; } -bool BluetoothDispatcherHost::IsServicesDiscoveryCompleteForDevice( - const std::string& device_id) { - return ContainsKey(devices_with_discovered_services_, device_id); +void BluetoothDispatcherHost::AddToPendingPrimaryServicesRequest( + const std::string& device_address, + const PrimaryServicesRequest& request) { + pending_primary_services_requests_[device_address].push_back(request); } -void BluetoothDispatcherHost::AddToPendingPrimaryServicesRequest( - const std::string& device_id, - const PrimaryServicesRequest& request) { - pending_primary_services_requests_[device_id].push_back(request); +url::Origin BluetoothDispatcherHost::GetOrigin(int frame_routing_id) { + return RenderFrameHostImpl::FromID(render_process_id_, frame_routing_id) + ->GetLastCommittedOrigin(); +} + +bool BluetoothDispatcherHost::CanFrameAccessCharacteristicInstance( + int frame_routing_id, + const std::string& characteristic_instance_id) { + return QueryCacheForCharacteristic(GetOrigin(frame_routing_id), + characteristic_instance_id) + .outcome != CacheQueryOutcome::BAD_RENDERER; } void BluetoothDispatcherHost::ShowBluetoothOverviewLink() {
diff --git a/content/browser/bluetooth/bluetooth_dispatcher_host.h b/content/browser/bluetooth/bluetooth_dispatcher_host.h index d45271d0..bbfddde8 100644 --- a/content/browser/bluetooth/bluetooth_dispatcher_host.h +++ b/content/browser/bluetooth/bluetooth_dispatcher_host.h
@@ -13,6 +13,7 @@ #include "base/macros.h" #include "base/memory/scoped_vector.h" #include "base/memory/weak_ptr.h" +#include "content/browser/bluetooth/bluetooth_allowed_devices_map.h" #include "content/public/browser/bluetooth_chooser.h" #include "content/public/browser/browser_message_filter.h" #include "device/bluetooth/bluetooth_adapter.h" @@ -104,33 +105,45 @@ const std::vector<device::BluetoothUUID>& optional_services); void OnConnectGATT(int thread_id, int request_id, + int frame_routing_id, const std::string& device_id); + void OnDisconnect(int thread_id, + int frame_routing_id, + const std::string& device_id); void OnGetPrimaryService(int thread_id, int request_id, + int frame_routing_id, const std::string& device_id, const std::string& service_uuid); void OnGetCharacteristic(int thread_id, int request_id, + int frame_routing_id, const std::string& service_instance_id, const std::string& characteristic_uuid); void OnReadValue(int thread_id, int request_id, + int frame_routing_id, const std::string& characteristic_instance_id); void OnWriteValue(int thread_id, int request_id, + int frame_routing_id, const std::string& characteristic_instance_id, const std::vector<uint8_t>& value); void OnStartNotifications(int thread_id, int request_id, + int frame_routing_id, const std::string& characteristic_instance_id); void OnStopNotifications(int thread_id, int request_id, + int frame_routing_id, const std::string& characteristic_instance_id); void OnRegisterCharacteristicObject( int thread_id, + int frame_routing_id, const std::string& characteristic_instance_id); void OnUnregisterCharacteristicObject( int thread_id, + int frame_routing_id, const std::string& characteristic_instance_id); // Callbacks for BluetoothAdapter::StartDiscoverySession. @@ -210,30 +223,37 @@ // was already recorded and since there renderer crashed there is no need to // send a response. - // Queries the platform cache for a Device with |device_id|. Fills in the - // |outcome| field and the |device| field if successful. - CacheQueryResult QueryCacheForDevice(const std::string& device_id); + // Queries the platform cache for a Device with |device_id| for |origin|. + // Fills in the |outcome| field and the |device| field if successful. + CacheQueryResult QueryCacheForDevice(const url::Origin& origin, + const std::string& device_id); // Queries the platform cache for a Service with |service_instance_id|. Fills // in the |outcome| field, and |device| and |service| fields if successful. - CacheQueryResult QueryCacheForService(const std::string& service_instance_id); + CacheQueryResult QueryCacheForService(const url::Origin& origin, + const std::string& service_instance_id); // Queries the platform cache for a characteristic with // |characteristic_instance_id|. Fills in the |outcome| field, and |device|, // |service| and |characteristic| fields if successful. CacheQueryResult QueryCacheForCharacteristic( + const url::Origin& origin, const std::string& characteristic_instance_id); - // Returns true if all services have been discovered for the device. - // When the host gets a ServiceChanged indication, it automatically - // re-discovers services, and only forwards the ServiceChanged event to this - // class when it's done re-discovering. - bool IsServicesDiscoveryCompleteForDevice(const std::string& device_id); - // Adds the PrimaryServicesRequest to the vector of pending services requests // for that device. void AddToPendingPrimaryServicesRequest( - const std::string& device_id, + const std::string& device_address, const PrimaryServicesRequest& request); + // Returns the origin for the frame with "frame_routing_id" in + // render_process_id_. + url::Origin GetOrigin(int frame_routing_id); + + // Returns true if the frame has permission to access the characteristic + // with |characteristic_instance_id|. + bool CanFrameAccessCharacteristicInstance( + int frame_routing_id, + const std::string& characteristic_instance_id); + // Show help pages from the chooser dialog. void ShowBluetoothOverviewLink(); void ShowBluetoothPairingLink(); @@ -248,8 +268,10 @@ // again everywhere a requestDevice() reply is sent. IDMap<RequestDeviceSession, IDMapOwnPointer> request_device_sessions_; + BluetoothAllowedDevicesMap allowed_devices_map_; + // Maps to get the object's parent based on it's instanceID - // Map of service_instance_id to device_id. + // Map of service_instance_id to device_address. std::map<std::string, std::string> service_to_device_; // Map of characteristic_instance_id to service_instance_id. std::map<std::string, std::string> characteristic_to_service_; @@ -279,14 +301,11 @@ base::Timer discovery_session_timer_; // Retain BluetoothGattConnection objects to keep connections open. - // TODO(scheib): Destroy as connections are closed. http://crbug.com/539643 - ScopedVector<device::BluetoothGattConnection> connections_; + std::map<std::string, scoped_ptr<device::BluetoothGattConnection>> + device_id_to_connection_map_; - // Keeps track of which devices have had their services discovered. - std::set<std::string> devices_with_discovered_services_; - - // Map of device_id's to primary-services requests that need responses when - // that device's service discovery completes. + // Map of device_address's to primary-services requests that need responses + // when that device's service discovery completes. std::map<std::string, std::vector<PrimaryServicesRequest>> pending_primary_services_requests_;
diff --git a/content/browser/bluetooth/bluetooth_metrics.h b/content/browser/bluetooth/bluetooth_metrics.h index fa50859..5786ccc 100644 --- a/content/browser/bluetooth/bluetooth_metrics.h +++ b/content/browser/bluetooth/bluetooth_metrics.h
@@ -31,6 +31,7 @@ CHARACTERISTIC_WRITE_VALUE = 5, CHARACTERISTIC_START_NOTIFICATIONS = 6, CHARACTERISTIC_STOP_NOTIFICATIONS = 7, + REMOTE_GATT_SERVER_DISCONNECT = 8, // NOTE: Add new actions immediately above this line. Make sure to update // the enum list in tools/metrics/histograms/histograms.xml accordingly. COUNT
diff --git a/content/browser/download/save_package.cc b/content/browser/download/save_package.cc index fe660b4..5b7d6a6 100644 --- a/content/browser/download/save_package.cc +++ b/content/browser/download/save_package.cc
@@ -1095,9 +1095,8 @@ wait_state_ = RESOURCES_LIST; DCHECK_EQ(0, number_of_frames_pending_response_); - web_contents()->ForEachFrame(base::Bind( - &SavePackage::GetSavableResourceLinksForFrame, - base::Unretained(this))); // Safe, because ForEachFrame is synchronous. + number_of_frames_pending_response_ = web_contents()->SendToAllFrames( + new FrameMsg_GetSavableResourceLinks(MSG_ROUTING_NONE)); DCHECK_LT(0, number_of_frames_pending_response_); // Enqueue the main frame separately (because this frame won't show up in any @@ -1110,11 +1109,6 @@ main_frame_tree_node->current_url()); } -void SavePackage::GetSavableResourceLinksForFrame(RenderFrameHost* target) { - number_of_frames_pending_response_++; - target->Send(new FrameMsg_GetSavableResourceLinks(target->GetRoutingID())); -} - void SavePackage::OnSavableResourceLinksResponse( RenderFrameHostImpl* sender, const std::vector<GURL>& resources_list,
diff --git a/content/browser/download/save_package.h b/content/browser/download/save_package.h index f28cf3a..eabf657 100644 --- a/content/browser/download/save_package.h +++ b/content/browser/download/save_package.h
@@ -184,8 +184,7 @@ bool need_html_ext, base::FilePath::StringType* generated_name); - // Main routine that initiates asking all frames for their savable resources, - // using GetSavableResourceLinksForFrame to send IPC to individual frames. + // Main routine that initiates asking all frames for their savable resources. // // Responses are received asynchronously by OnSavableResourceLinks... methods // and pending responses are counted/tracked by @@ -197,10 +196,7 @@ // EnqueueFrame. void GetSavableResourceLinks(); - // Asks a given frame for its savable resources. - void GetSavableResourceLinksForFrame(RenderFrameHost* target); - - // Response from |sender| frame to GetSavableResourceLinksForFrame request. + // Response from |sender| frame to GetSavableResourceLinks request. void OnSavableResourceLinksResponse( RenderFrameHostImpl* sender, const std::vector<GURL>& resources_list, @@ -222,18 +218,17 @@ const Referrer& referrer, SaveFileCreateInfo::SaveFileSource save_source); - // Helper to enqueue a savable resource reported by - // GetSavableResourceLinksForFrame. + // Helper to enqueue a savable resource reported by GetSavableResourceLinks. void EnqueueSavableResource(int container_frame_tree_node_id, const GURL& url, const Referrer& referrer); - // Helper to enqueue a subframe reported by GetSavableResourceLinksForFrame. + // Helper to enqueue a subframe reported by GetSavableResourceLinks. void EnqueueFrame(int container_frame_tree_node_id, int frame_tree_node_id, const GURL& frame_original_url); - // Response to GetSavableResourceLinksForFrame that indicates an error - // when processing the frame associated with |sender|. + // Response to GetSavableResourceLinks that indicates an error when processing + // the frame associated with |sender|. void OnSavableResourceLinksError(RenderFrameHostImpl* sender); // Helper tracking how many |number_of_frames_pending_response_| we have
diff --git a/content/browser/loader/resource_dispatcher_host_impl.cc b/content/browser/loader/resource_dispatcher_host_impl.cc index 529b9781..022f410c 100644 --- a/content/browser/loader/resource_dispatcher_host_impl.cc +++ b/content/browser/loader/resource_dispatcher_host_impl.cc
@@ -1233,7 +1233,8 @@ AppCacheInterceptor::CompleteCrossSiteTransfer( loader->request(), child_id, - request_data.appcache_host_id); + request_data.appcache_host_id, + filter_); ServiceWorkerRequestHandler* handler = ServiceWorkerRequestHandler::GetHandler(loader->request());
diff --git a/content/browser/media/android/browser_media_player_manager.cc b/content/browser/media/android/browser_media_player_manager.cc index c512f31..e036cb1 100644 --- a/content/browser/media/android/browser_media_player_manager.cc +++ b/content/browser/media/android/browser_media_player_manager.cc
@@ -143,6 +143,7 @@ bool hide_url_log, BrowserDemuxerAndroid* demuxer) { switch (media_player_params.type) { + case MEDIA_PLAYER_TYPE_REMOTE_ONLY: case MEDIA_PLAYER_TYPE_URL: { const std::string user_agent = GetContentClient()->GetUserAgent(); MediaPlayerBridge* media_player_bridge = new MediaPlayerBridge( @@ -156,6 +157,10 @@ weak_ptr_factory_.GetWeakPtr()), media_player_params.frame_url, media_player_params.allow_credentials); + + if (media_player_params.type == MEDIA_PLAYER_TYPE_REMOTE_ONLY) + return media_player_bridge; + bool should_block = false; bool extract_metadata = // Initialize the player will cause MediaMetadataExtractor to decode
diff --git a/content/browser/media/android/browser_media_player_manager.h b/content/browser/media/android/browser_media_player_manager.h index 428214d..76177503 100644 --- a/content/browser/media/android/browser_media_player_manager.h +++ b/content/browser/media/android/browser_media_player_manager.h
@@ -15,7 +15,6 @@ #include "content/browser/android/content_video_view.h" #include "content/browser/media/android/media_session_observer.h" #include "content/common/content_export.h" -#include "content/common/media/media_player_messages_enums_android.h" #include "ipc/ipc_message.h" #include "media/base/android/media_player_android.h" #include "media/base/android/media_player_manager.h"
diff --git a/content/browser/renderer_host/p2p/socket_host.cc b/content/browser/renderer_host/p2p/socket_host.cc index ef6b588..973d60a 100644 --- a/content/browser/renderer_host/p2p/socket_host.cc +++ b/content/browser/renderer_host/p2p/socket_host.cc
@@ -11,34 +11,14 @@ #include "content/browser/renderer_host/p2p/socket_host_udp.h" #include "content/browser/renderer_host/render_process_host_impl.h" #include "content/public/browser/browser_thread.h" -#include "crypto/hmac.h" -#include "third_party/webrtc/base/asyncpacketsocket.h" -#include "third_party/webrtc/base/byteorder.h" -#include "third_party/webrtc/base/messagedigest.h" -#include "third_party/webrtc/p2p/base/stun.h" +#include "third_party/libjingle/source/talk/media/base/rtputils.h" +#include "third_party/libjingle/source/talk/media/base/turnutils.h" namespace { const uint32_t kStunMagicCookie = 0x2112A442; -const size_t kMinRtpHeaderLength = 12; const size_t kMinRtcpHeaderLength = 8; -const size_t kRtpExtensionHeaderLength = 4; const size_t kDtlsRecordHeaderLength = 13; -const size_t kTurnChannelHeaderLength = 4; -const size_t kAbsSendTimeExtensionLength = 3; -const size_t kOneByteHeaderLength = 1; -const size_t kMaxRtpPacketLength = 2048; - -// Fake auth tag written by the render process if external authentication is -// enabled. HMAC in packet will be compared against this value before updating -// packet with actual HMAC value. -static const unsigned char kFakeAuthTag[10] = { - 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd, 0xba, 0xdd -}; - -bool IsTurnChannelData(const char* data, size_t length) { - return length >= kTurnChannelHeaderLength && ((*data & 0xC0) == 0x40); -} bool IsDtlsPacket(const char* data, size_t length) { const uint8_t* u = reinterpret_cast<const uint8_t*>(data); @@ -54,406 +34,10 @@ return (type >= 64 && type < 96); } -bool IsTurnSendIndicationPacket(const char* data, size_t length) { - if (length < content::P2PSocketHost::kStunHeaderSize) { - return false; - } - - uint16_t type = rtc::GetBE16(data); - return (type == cricket::TURN_SEND_INDICATION); -} - -bool IsRtpPacket(const char* data, size_t length) { - return (length >= kMinRtpHeaderLength) && ((*data & 0xC0) == 0x80); -} - -// Verifies rtp header and message length. -bool ValidateRtpHeader(const char* rtp, size_t length, size_t* header_length) { - if (header_length) { - *header_length = 0; - } - - if (length < kMinRtpHeaderLength) { - return false; - } - - size_t cc_count = rtp[0] & 0x0F; - size_t header_length_without_extension = kMinRtpHeaderLength + 4 * cc_count; - if (header_length_without_extension > length) { - return false; - } - - // If extension bit is not set, we are done with header processing, as input - // length is verified above. - if (!(rtp[0] & 0x10)) { - if (header_length) - *header_length = header_length_without_extension; - - return true; - } - - rtp += header_length_without_extension; - - if (header_length_without_extension + kRtpExtensionHeaderLength > length) { - return false; - } - - // Getting extension profile length. - // Length is in 32 bit words. - uint16_t extension_length_in_32bits = rtc::GetBE16(rtp + 2); - size_t extension_length = extension_length_in_32bits * 4; - - size_t rtp_header_length = extension_length + - header_length_without_extension + - kRtpExtensionHeaderLength; - - // Verify input length against total header size. - if (rtp_header_length > length) { - return false; - } - - if (header_length) { - *header_length = rtp_header_length; - } - return true; -} - -void UpdateAbsSendTimeExtensionValue(char* extension_data, - size_t length, - uint32_t abs_send_time) { - // Absolute send time in RTP streams. - // - // The absolute send time is signaled to the receiver in-band using the - // general mechanism for RTP header extensions [RFC5285]. The payload - // of this extension (the transmitted value) is a 24-bit unsigned integer - // containing the sender's current time in seconds as a fixed point number - // with 18 bits fractional part. - // - // The form of the absolute send time extension block: - // - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | ID | len=2 | absolute send time | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - if (length != kAbsSendTimeExtensionLength) { - NOTREACHED(); - return; - } - - // Now() has resolution ~1-15ms - uint32_t now_second = abs_send_time; - if (!now_second) { - uint64_t now_us = - (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds(); - // Convert second to 24-bit unsigned with 18 bit fractional part - now_second = - ((now_us << 18) / base::Time::kMicrosecondsPerSecond) & 0x00FFFFFF; - } - // TODO(mallinath) - Add SetBE24 to byteorder.h in libjingle. - extension_data[0] = static_cast<uint8_t>(now_second >> 16); - extension_data[1] = static_cast<uint8_t>(now_second >> 8); - extension_data[2] = static_cast<uint8_t>(now_second); -} - -// Assumes |length| is actual packet length + tag length. Updates HMAC at end of -// the RTP packet. -void UpdateRtpAuthTag(char* rtp, - size_t length, - const rtc::PacketOptions& options) { - // If there is no key, return. - if (options.packet_time_params.srtp_auth_key.empty()) { - return; - } - - size_t tag_length = options.packet_time_params.srtp_auth_tag_len; - - // ROC (rollover counter) is at the beginning of the auth tag. - const size_t kRocLength = 4; - if (tag_length < kRocLength || tag_length > length) { - NOTREACHED(); - return; - } - - crypto::HMAC hmac(crypto::HMAC::SHA1); - if (!hmac.Init(reinterpret_cast<const unsigned char*>( - &options.packet_time_params.srtp_auth_key[0]), - options.packet_time_params.srtp_auth_key.size())) { - NOTREACHED(); - return; - } - - if (tag_length > hmac.DigestLength()) { - NOTREACHED(); - return; - } - - char* auth_tag = rtp + (length - tag_length); - - // We should have a fake HMAC value @ auth_tag. - DCHECK_EQ(0, memcmp(auth_tag, kFakeAuthTag, tag_length)); - - // Copy ROC after end of rtp packet. - memcpy(auth_tag, &options.packet_time_params.srtp_packet_index, kRocLength); - // Authentication of a RTP packet will have RTP packet + ROC size. - int auth_required_length = length - tag_length + kRocLength; - - unsigned char output[64]; - if (!hmac.Sign(base::StringPiece(rtp, auth_required_length), - output, sizeof(output))) { - NOTREACHED(); - return; - } - // Copy HMAC from output to packet. This is required as auth tag length - // may not be equal to the actual HMAC length. - memcpy(auth_tag, output, tag_length); -} - } // namespace namespace content { -namespace packet_processing_helpers { - -bool ApplyPacketOptions(char* data, - size_t length, - const rtc::PacketOptions& options, - uint32_t abs_send_time) { - DCHECK(data != NULL); - DCHECK(length > 0); - // if there is no valid |rtp_sendtime_extension_id| and |srtp_auth_key| in - // PacketOptions, nothing to be updated in this packet. - if (options.packet_time_params.rtp_sendtime_extension_id == -1 && - options.packet_time_params.srtp_auth_key.empty()) { - return true; - } - - DCHECK(!IsDtlsPacket(data, length)); - DCHECK(!IsRtcpPacket(data, length)); - - // If there is a srtp auth key present then packet must be a RTP packet. - // RTP packet may have been wrapped in a TURN Channel Data or - // TURN send indication. - size_t rtp_start_pos; - size_t rtp_length; - if (!GetRtpPacketStartPositionAndLength( - data, length, &rtp_start_pos, &rtp_length)) { - // This method should never return false. - NOTREACHED(); - return false; - } - - // Skip to rtp packet. - char* start = data + rtp_start_pos; - // If packet option has non default value (-1) for sendtime extension id, - // then we should parse the rtp packet to update the timestamp. Otherwise - // just calculate HMAC and update packet with it. - if (options.packet_time_params.rtp_sendtime_extension_id != -1) { - UpdateRtpAbsSendTimeExtension( - start, - rtp_length, - options.packet_time_params.rtp_sendtime_extension_id, - abs_send_time); - } - - UpdateRtpAuthTag(start, rtp_length, options); - return true; -} - -bool GetRtpPacketStartPositionAndLength(const char* packet, - size_t length, - size_t* rtp_start_pos, - size_t* rtp_packet_length) { - if (length < kMinRtpHeaderLength || length > kMaxRtpPacketLength) { - return false; - } - - size_t rtp_begin; - size_t rtp_length = 0; - if (IsTurnChannelData(packet, length)) { - // Turn Channel Message header format. - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | Channel Number | Length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | | - // / Application Data / - // / / - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - rtp_begin = kTurnChannelHeaderLength; - rtp_length = rtc::GetBE16(&packet[2]); - if (length < rtp_length + kTurnChannelHeaderLength) { - return false; - } - } else if (IsTurnSendIndicationPacket(packet, length)) { - // Validate STUN message length. - const size_t stun_message_length = rtc::GetBE16(&packet[2]); - if (stun_message_length + P2PSocketHost::kStunHeaderSize != length) { - return false; - } - - // First skip mandatory stun header which is of 20 bytes. - rtp_begin = P2PSocketHost::kStunHeaderSize; - // Loop through STUN attributes until we find STUN DATA attribute. - bool data_attr_present = false; - while (rtp_begin < length) { - // Keep reading STUN attributes until we hit DATA attribute. - // Attribute will be a TLV structure. - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | Type | Length | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | Value (variable) .... - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // The value in the length field MUST contain the length of the Value - // part of the attribute, prior to padding, measured in bytes. Since - // STUN aligns attributes on 32-bit boundaries, attributes whose content - // is not a multiple of 4 bytes are padded with 1, 2, or 3 bytes of - // padding so that its value contains a multiple of 4 bytes. The - // padding bits are ignored, and may be any value. - uint16_t attr_type, attr_length; - const int kAttrHeaderLength = sizeof(attr_type) + sizeof(attr_length); - - if (length < rtp_begin + kAttrHeaderLength) { - return false; - } - - // Getting attribute type and length. - attr_type = rtc::GetBE16(&packet[rtp_begin]); - attr_length = rtc::GetBE16( - &packet[rtp_begin + sizeof(attr_type)]); - - rtp_begin += kAttrHeaderLength; // Skip STUN_DATA_ATTR header. - - // Checking for bogus attribute length. - if (length < rtp_begin + attr_length) { - return false; - } - - if (attr_type != cricket::STUN_ATTR_DATA) { - rtp_begin += attr_length; - if ((attr_length % 4) != 0) { - rtp_begin += (4 - (attr_length % 4)); - } - continue; - } - - data_attr_present = true; - rtp_length = attr_length; - - // We found STUN_DATA_ATTR. We can skip parsing rest of the packet. - break; - } - - if (!data_attr_present) { - // There is no data attribute present in the message. We can't do anything - // with the message. - return false; - } - - } else { - // This is a raw RTP packet. - rtp_begin = 0; - rtp_length = length; - } - - // Making sure we have a valid RTP packet at the end. - if (IsRtpPacket(packet + rtp_begin, rtp_length) && - ValidateRtpHeader(packet + rtp_begin, rtp_length, NULL)) { - *rtp_start_pos = rtp_begin; - *rtp_packet_length = rtp_length; - return true; - } - return false; -} - -// ValidateRtpHeader must be called before this method to make sure, we have -// a sane rtp packet. -bool UpdateRtpAbsSendTimeExtension(char* rtp, - size_t length, - int extension_id, - uint32_t abs_send_time) { - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // |V=2|P|X| CC |M| PT | sequence number | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | timestamp | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | synchronization source (SSRC) identifier | - // +=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ - // | contributing source (CSRC) identifiers | - // | .... | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - // Return if extension bit is not set. - if (!(rtp[0] & 0x10)) { - return true; - } - - size_t cc_count = rtp[0] & 0x0F; - size_t header_length_without_extension = kMinRtpHeaderLength + 4 * cc_count; - - rtp += header_length_without_extension; - - // Getting extension profile ID and length. - uint16_t profile_id = rtc::GetBE16(rtp); - // Length is in 32 bit words. - uint16_t extension_length_in_32bits = rtc::GetBE16(rtp + 2); - size_t extension_length = extension_length_in_32bits * 4; - - rtp += kRtpExtensionHeaderLength; // Moving past extension header. - - bool found = false; - // WebRTC is using one byte header extension. - // TODO(mallinath) - Handle two byte header extension. - if (profile_id == 0xBEDE) { // OneByte extension header - // 0 - // 0 1 2 3 4 5 6 7 - // +-+-+-+-+-+-+-+-+ - // | ID |length | - // +-+-+-+-+-+-+-+-+ - - // 0 1 2 3 - // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | 0xBE | 0xDE | length=3 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | ID | L=0 | data | ID | L=1 | data... - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // ...data | 0 (pad) | 0 (pad) | ID | L=3 | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - // | data | - // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - const char* extension_start = rtp; - const char* extension_end = extension_start + extension_length; - - while (rtp < extension_end) { - const int id = (*rtp & 0xF0) >> 4; - const size_t length = (*rtp & 0x0F) + 1; - if (rtp + kOneByteHeaderLength + length > extension_end) { - return false; - } - // The 4-bit length is the number minus one of data bytes of this header - // extension element following the one-byte header. - if (id == extension_id) { - UpdateAbsSendTimeExtensionValue( - rtp + kOneByteHeaderLength, length, abs_send_time); - found = true; - break; - } - rtp += kOneByteHeaderLength + length; - // Counting padding bytes. - while ((rtp < extension_end) && (*rtp == 0)) { - ++rtp; - } - } - } - return found; -} - -} // packet_processing_helpers - P2PSocketHost::P2PSocketHost(IPC::Sender* message_sender, int socket_id, ProtocolType protocol_type) @@ -622,17 +206,19 @@ size_t rtp_packet_pos = 0; size_t rtp_packet_length = length; - if (!packet_processing_helpers::GetRtpPacketStartPositionAndLength( - packet, length, &rtp_packet_pos, &rtp_packet_length)) { + if (!cricket::UnwrapTurnPacket(reinterpret_cast<const uint8_t*>(packet), + length, &rtp_packet_pos, &rtp_packet_length)) { return; } packet += rtp_packet_pos; size_t header_length = 0; - bool valid = ValidateRtpHeader(packet, rtp_packet_length, &header_length); + bool valid = + cricket::ValidateRtpHeader(reinterpret_cast<const uint8_t*>(packet), + rtp_packet_length, &header_length); if (!valid) { - DCHECK(false); + NOTREACHED(); return; }
diff --git a/content/browser/renderer_host/p2p/socket_host.h b/content/browser/renderer_host/p2p/socket_host.h index 37ffddb..0b14f0f 100644 --- a/content/browser/renderer_host/p2p/socket_host.h +++ b/content/browser/renderer_host/p2p/socket_host.h
@@ -31,33 +31,6 @@ namespace content { class P2PMessageThrottler; -namespace packet_processing_helpers { - -// This method can handle only RTP packet, otherwise this method must not be -// called. It will try to do, 1. update absolute send time extension header -// if present with current time and 2. update HMAC in RTP packet. -// If abs_send_time is 0, ApplyPacketOption will get current time from system. -CONTENT_EXPORT bool ApplyPacketOptions(char* data, - size_t length, - const rtc::PacketOptions& options, - uint32_t abs_send_time); - -// Helper method which finds RTP ofset and length if the packet is encapsulated -// in a TURN Channel Message or TURN Send Indication message. -CONTENT_EXPORT bool GetRtpPacketStartPositionAndLength( - const char* data, - size_t length, - size_t* rtp_start_pos, - size_t* rtp_packet_length); - -// Helper method which updates absoulute send time extension if present. -CONTENT_EXPORT bool UpdateRtpAbsSendTimeExtension(char* rtp, - size_t length, - int extension_id, - uint32_t abs_send_time); - -} // packet_processing_helpers - // Base class for P2P sockets. class CONTENT_EXPORT P2PSocketHost { public:
diff --git a/content/browser/renderer_host/p2p/socket_host_tcp.cc b/content/browser/renderer_host/p2p/socket_host_tcp.cc index cd93a12..9fa9fc4 100644 --- a/content/browser/renderer_host/p2p/socket_host_tcp.cc +++ b/content/browser/renderer_host/p2p/socket_host_tcp.cc
@@ -23,7 +23,7 @@ #include "net/socket/tcp_client_socket.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" -#include "third_party/webrtc/base/asyncpacketsocket.h" +#include "third_party/libjingle/source/talk/media/base/rtputils.h" namespace { @@ -528,10 +528,10 @@ *reinterpret_cast<uint16_t*>(buffer->data()) = base::HostToNet16(data.size()); memcpy(buffer->data() + kPacketHeaderSize, &data[0], data.size()); - packet_processing_helpers::ApplyPacketOptions( - buffer->data() + kPacketHeaderSize, - buffer->BytesRemaining() - kPacketHeaderSize, - options, 0); + cricket::ApplyPacketOptions( + reinterpret_cast<uint8_t*>(buffer->data()) + kPacketHeaderSize, + buffer->BytesRemaining() - kPacketHeaderSize, options.packet_time_params, + (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds()); WriteOrQueue(buffer); } @@ -601,8 +601,10 @@ new net::DrainableIOBuffer(new net::IOBuffer(size), size); memcpy(buffer->data(), &data[0], data.size()); - packet_processing_helpers::ApplyPacketOptions( - buffer->data(), data.size(), options, 0); + cricket::ApplyPacketOptions( + reinterpret_cast<uint8_t*>(buffer->data()), data.size(), + options.packet_time_params, + (base::TimeTicks::Now() - base::TimeTicks()).InMicroseconds()); if (pad_bytes) { char padding[4] = {0};
diff --git a/content/browser/renderer_host/p2p/socket_host_udp.cc b/content/browser/renderer_host/p2p/socket_host_udp.cc index 0dbfcec4..668d495 100644 --- a/content/browser/renderer_host/p2p/socket_host_udp.cc +++ b/content/browser/renderer_host/p2p/socket_host_udp.cc
@@ -19,7 +19,7 @@ #include "net/base/io_buffer.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" -#include "third_party/webrtc/base/asyncpacketsocket.h" +#include "third_party/libjingle/source/talk/media/base/rtputils.h" namespace { @@ -294,9 +294,10 @@ } base::TimeTicks send_time = base::TimeTicks::Now(); - - packet_processing_helpers::ApplyPacketOptions( - packet.data->data(), packet.size, packet.packet_options, 0); + cricket::ApplyPacketOptions(reinterpret_cast<uint8_t*>(packet.data->data()), + packet.size, + packet.packet_options.packet_time_params, + (send_time - base::TimeTicks()).InMicroseconds()); auto callback_binding = base::Bind(&P2PSocketHostUdp::OnSend, base::Unretained(this), packet.id, packet.packet_options.packet_id, send_time);
diff --git a/content/browser/renderer_host/p2p/socket_host_unittest.cc b/content/browser/renderer_host/p2p/socket_host_unittest.cc deleted file mode 100644 index c92e9d7..0000000 --- a/content/browser/renderer_host/p2p/socket_host_unittest.cc +++ /dev/null
@@ -1,386 +0,0 @@ -// Copyright (c) 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/renderer_host/p2p/socket_host.h" - -#include <stddef.h> - -#include <vector> - -#include "base/memory/scoped_ptr.h" -#include "content/browser/renderer_host/p2p/socket_host_test_utils.h" -#include "net/base/ip_endpoint.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -static unsigned char kFakeTag[4] = { 0xba, 0xdd, 0xba, 0xdd }; -static unsigned char kTestKey[] = "12345678901234567890"; -static unsigned char kTestAstValue[3] = { 0xaa, 0xbb, 0xcc }; - -// Rtp message with invalid length. -static unsigned char kRtpMsgWithInvalidLength[] = { - 0x94, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xAA, 0xBB, 0xCC, 0XDD, // SSRC - 0xDD, 0xCC, 0xBB, 0xAA // Only 1 CSRC, but CC count is 4. -}; - -// Rtp message with single byte header extension, invalid extension length. -static unsigned char kRtpMsgWithInvalidExtnLength[] = { - 0x90, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xBE, 0xDE, 0x0A, 0x00 // Extn length - 0x0A00 -}; - -// Valid rtp Message with 2 byte header extension. -static unsigned char kRtpMsgWith2ByteExtnHeader[] = { - 0x90, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xAA, 0xBB, 0xCC, 0XDD, // SSRC - 0x10, 0x00, 0x00, 0x01, // 2 Byte header extension - 0x01, 0x00, 0x00, 0x00 -}; - -// Stun Indication message with Zero length -static unsigned char kTurnSendIndicationMsgWithNoAttributes[] = { - 0x00, 0x16, 0x00, 0x00, // Zero length - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', -}; - -// Stun Send Indication message with invalid length in stun header. -static unsigned char kTurnSendIndicationMsgWithInvalidLength[] = { - 0x00, 0x16, 0xFF, 0x00, // length of 0xFF00 - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', -}; - -// Stun Send Indication message with no DATA attribute in message. -static unsigned char kTurnSendIndicatinMsgWithNoDataAttribute[] = { - 0x00, 0x16, 0x00, 0x08, // length of - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 0x00, 0x20, 0x00, 0x04, // Mapped address. - 0x00, 0x00, 0x00, 0x00 -}; - -// A valid STUN indication message with a valid RTP header in data attribute -// payload field and no extension bit set. -static unsigned char kTurnSendIndicationMsgWithoutRtpExtension[] = { - 0x00, 0x16, 0x00, 0x18, // length of - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 0x00, 0x20, 0x00, 0x04, // Mapped address. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x13, 0x00, 0x0C, // Data attribute. - 0x80, 0x00, 0x00, 0x00, // RTP packet. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -// A valid STUN indication message with a valid RTP header and a extension -// header. -static unsigned char kTurnSendIndicationMsgWithAbsSendTimeExtension[] = { - 0x00, 0x16, 0x00, 0x24, // length of - 0x21, 0x12, 0xA4, 0x42, // magic cookie - '0', '1', '2', '3', // transaction id - '4', '5', '6', '7', - '8', '9', 'a', 'b', - 0x00, 0x20, 0x00, 0x04, // Mapped address. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x13, 0x00, 0x18, // Data attribute. - 0x90, 0x00, 0x00, 0x00, // RTP packet. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xBE, 0xDE, 0x00, 0x02, - 0x22, 0xaa, 0xbb, 0xcc, - 0x32, 0xaa, 0xbb, 0xcc, -}; - -// A valid TURN channel header, but not RTP packet. -static unsigned char kTurnChannelMsgNoRtpPacket[] = { - 0x40, 0x00, 0x00, 0x04, - 0xaa, 0xbb, 0xcc, 0xdd, -}; - -// Turn ChannelMessage with zero length of payload. -static unsigned char kTurnChannelMsgWithZeroLength[] = { - 0x40, 0x00, 0x00, 0x00 -}; - -// Turn ChannelMessage, wrapping a RTP packet without extension. -static unsigned char kTurnChannelMsgWithRtpPacket[] = { - 0x40, 0x00, 0x00, 0x0C, - 0x80, 0x00, 0x00, 0x00, // RTP packet. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, -}; - -// Turn ChannelMessage, wrapping a RTP packet with AbsSendTime Extension. -static unsigned char kTurnChannelMsgWithAbsSendTimeExtension[] = { - 0x40, 0x00, 0x00, 0x14, - 0x90, 0x00, 0x00, 0x00, // RTP packet. - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xBE, 0xDE, 0x00, 0x01, - 0x32, 0xaa, 0xbb, 0xcc, -}; - -// RTP packet with single byte extension header of length 4 bytes. -// Extension id = 3 and length = 3 -static unsigned char kRtpMsgWithAbsSendTimeExtension[] = { - 0x90, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0xBE, 0xDE, 0x00, 0x02, - 0x22, 0x00, 0x02, 0x1c, - 0x32, 0xaa, 0xbb, 0xcc, -}; - -// Index of AbsSendTimeExtn data in message |kRtpMsgWithAbsSendTimeExtension|. -static const int kAstIndexInRtpMsg = 21; - -namespace content { - -// This test verifies parsing of all invalid raw packets. -TEST(P2PSocketHostTest, TestInvalidRawRtpMessages) { - size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX; - EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kRtpMsgWithInvalidLength), - sizeof(kRtpMsgWithInvalidLength), - &start_pos, &rtp_length)); - EXPECT_EQ(SIZE_MAX, start_pos); - EXPECT_EQ(SIZE_MAX, rtp_length); - - EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kRtpMsgWithInvalidExtnLength), - sizeof(kRtpMsgWithInvalidExtnLength), - &start_pos, &rtp_length)); - EXPECT_EQ(SIZE_MAX, start_pos); - EXPECT_EQ(SIZE_MAX, rtp_length); -} - -// Verify invalid TURN send indication messages. Messages are proper STUN -// messages with incorrect values in attributes. -TEST(P2PSocketHostTest, TestInvalidTurnSendIndicationMessages) { - // Initializing out params to very large value. - size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX; - EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnSendIndicationMsgWithNoAttributes), - sizeof(kTurnSendIndicationMsgWithNoAttributes), - &start_pos, &rtp_length)); - EXPECT_EQ(SIZE_MAX, start_pos); - EXPECT_EQ(SIZE_MAX, rtp_length); - - EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnSendIndicationMsgWithInvalidLength), - sizeof(kTurnSendIndicationMsgWithInvalidLength), - &start_pos, &rtp_length)); - EXPECT_EQ(SIZE_MAX, start_pos); - EXPECT_EQ(SIZE_MAX, rtp_length); - - EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnSendIndicatinMsgWithNoDataAttribute), - sizeof(kTurnSendIndicatinMsgWithNoDataAttribute), - &start_pos, &rtp_length)); - EXPECT_EQ(SIZE_MAX, start_pos); - EXPECT_EQ(SIZE_MAX, rtp_length); -} - -// This test verifies incorrectly formed TURN channel messages. -TEST(P2PSocketHostTest, TestInvalidTurnChannelMessages) { - size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX; - EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnChannelMsgNoRtpPacket), - sizeof(kTurnChannelMsgNoRtpPacket), - &start_pos, &rtp_length)); - EXPECT_EQ(SIZE_MAX, start_pos); - EXPECT_EQ(SIZE_MAX, rtp_length); - - EXPECT_FALSE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnChannelMsgWithZeroLength), - sizeof(kTurnChannelMsgWithZeroLength), - &start_pos, &rtp_length)); - EXPECT_EQ(SIZE_MAX, start_pos); - EXPECT_EQ(SIZE_MAX, rtp_length); -} - -// This test verifies parsing of a valid RTP packet which has 2byte header -// extension instead of a 1 byte header extension. -TEST(P2PSocketHostTest, TestValid2ByteExtnHdrRtpMessage) { - size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX; - EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kRtpMsgWith2ByteExtnHeader), - sizeof(kRtpMsgWith2ByteExtnHeader), - &start_pos, &rtp_length)); - EXPECT_EQ(20U, rtp_length); - EXPECT_EQ(0U, start_pos); -} - -// This test verifies parsing of a valid RTP packet which has 1 byte header -// AbsSendTime extension in it. -TEST(P2PSocketHostTest, TestValidRtpPacketWithAbsSendTimeExtension) { - size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX; - EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kRtpMsgWithAbsSendTimeExtension), - sizeof(kRtpMsgWithAbsSendTimeExtension), - &start_pos, &rtp_length)); - EXPECT_EQ(24U, rtp_length); - EXPECT_EQ(0U, start_pos); -} - -// This test verifies parsing of a valid TURN Send Indication messages. -TEST(P2PSocketHostTest, TestValidTurnSendIndicationMessages) { - size_t start_pos = SIZE_MAX, rtp_length = SIZE_MAX; - EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnSendIndicationMsgWithoutRtpExtension), - sizeof(kTurnSendIndicationMsgWithoutRtpExtension), - &start_pos, &rtp_length)); - EXPECT_EQ(12U, rtp_length); - EXPECT_EQ(32U, start_pos); - - start_pos = SIZE_MAX, rtp_length = SIZE_MAX; - EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnSendIndicationMsgWithAbsSendTimeExtension), - sizeof(kTurnSendIndicationMsgWithAbsSendTimeExtension), - &start_pos, &rtp_length)); - EXPECT_EQ(24U, rtp_length); - EXPECT_EQ(32U, start_pos); -} - -// This test verifies parsing of valid TURN Channel Messages. -TEST(P2PSocketHostTest, TestValidTurnChannelMessages) { - size_t start_pos = 0, rtp_length = 0; - EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnChannelMsgWithRtpPacket), - sizeof(kTurnChannelMsgWithRtpPacket), &start_pos, &rtp_length)); - EXPECT_EQ(12U, rtp_length); - EXPECT_EQ(4U, start_pos); - - start_pos = 0, rtp_length = 0; - EXPECT_TRUE(packet_processing_helpers::GetRtpPacketStartPositionAndLength( - reinterpret_cast<char*>(kTurnChannelMsgWithAbsSendTimeExtension), - sizeof(kTurnChannelMsgWithAbsSendTimeExtension), - &start_pos, &rtp_length)); - EXPECT_EQ(20U, rtp_length); - EXPECT_EQ(4U, start_pos); -} - -// Verify handling of a 2 byte extension header RTP messsage. Currently we don't -// handle this kind of message. -TEST(P2PSocketHostTest, TestUpdateAbsSendTimeExtensionIn2ByteHeaderExtn) { - EXPECT_FALSE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension( - reinterpret_cast<char*>(kRtpMsgWith2ByteExtnHeader), - sizeof(kRtpMsgWith2ByteExtnHeader), - 3, - 0)); -} - -// Verify finding an extension ID in the TURN send indication message. -TEST(P2PSocketHostTest, TestUpdateAbsSendTimeExtensionInTurnSendIndication) { - EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension( - reinterpret_cast<char*>(kTurnSendIndicationMsgWithoutRtpExtension), - sizeof(kTurnSendIndicationMsgWithoutRtpExtension), - 3, - 0)); - - EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension( - reinterpret_cast<char*>(kTurnSendIndicationMsgWithAbsSendTimeExtension), - sizeof(kTurnSendIndicationMsgWithAbsSendTimeExtension), - 3, - 0)); -} - -// Test without any packet options variables set. This method should return -// without HMAC value in the packet. -TEST(P2PSocketHostTest, TestApplyPacketOptionsWithDefaultValues) { - unsigned char fake_tag[4] = { 0xba, 0xdd, 0xba, 0xdd }; - rtc::PacketOptions options; - std::vector<char> rtp_packet; - rtp_packet.resize(sizeof(kRtpMsgWithAbsSendTimeExtension) + 4); // tag length - memcpy(&rtp_packet[0], kRtpMsgWithAbsSendTimeExtension, - sizeof(kRtpMsgWithAbsSendTimeExtension)); - memcpy(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], fake_tag, 4); - EXPECT_TRUE( - packet_processing_helpers::ApplyPacketOptions( - &rtp_packet[0], rtp_packet.size(), options, 0)); - // Making sure we have't updated the HMAC. - EXPECT_EQ(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], - fake_tag, 4)); - - // Verify AbsouluteSendTime extension field is not modified. - EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg], - kTestAstValue, sizeof(kTestAstValue))); -} - -// Veirfy HMAC is updated when packet option parameters are set. -TEST(P2PSocketHostTest, TestApplyPacketOptionsWithAuthParams) { - rtc::PacketOptions options; - options.packet_time_params.srtp_auth_key.resize(20); - options.packet_time_params.srtp_auth_key.assign( - kTestKey, kTestKey + sizeof(kTestKey)); - options.packet_time_params.srtp_auth_tag_len = 4; - - std::vector<char> rtp_packet; - rtp_packet.resize(sizeof(kRtpMsgWithAbsSendTimeExtension) + 4); // tag length - memcpy(&rtp_packet[0], kRtpMsgWithAbsSendTimeExtension, - sizeof(kRtpMsgWithAbsSendTimeExtension)); - memcpy(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], kFakeTag, 4); - EXPECT_TRUE(packet_processing_helpers::ApplyPacketOptions( - &rtp_packet[0], rtp_packet.size(), options, 0)); - // HMAC should be different from fake_tag. - EXPECT_NE(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], - kFakeTag, sizeof(kFakeTag))); - - // Verify AbsouluteSendTime extension field is not modified. - EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg], - kTestAstValue, sizeof(kTestAstValue))); -} - -// Verify finding an extension ID in a raw rtp message. -TEST(P2PSocketHostTest, TestUpdateAbsSendTimeExtensionInRtpPacket) { - EXPECT_TRUE(packet_processing_helpers::UpdateRtpAbsSendTimeExtension( - reinterpret_cast<char*>(kRtpMsgWithAbsSendTimeExtension), - sizeof(kRtpMsgWithAbsSendTimeExtension), - 3, - 0)); -} - -// Verify we update both AbsSendTime extension header and HMAC. -TEST(P2PSocketHostTest, TestApplyPacketOptionsWithAuthParamsAndAbsSendTime) { - rtc::PacketOptions options; - options.packet_time_params.srtp_auth_key.resize(20); - options.packet_time_params.srtp_auth_key.assign( - kTestKey, kTestKey + sizeof(kTestKey)); - options.packet_time_params.srtp_auth_tag_len = 4; - options.packet_time_params.rtp_sendtime_extension_id = 3; - // 3 is also present in the test message. - - std::vector<char> rtp_packet; - rtp_packet.resize(sizeof(kRtpMsgWithAbsSendTimeExtension) + 4); // tag length - memcpy(&rtp_packet[0], kRtpMsgWithAbsSendTimeExtension, - sizeof(kRtpMsgWithAbsSendTimeExtension)); - memcpy(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], kFakeTag, 4); - EXPECT_TRUE(packet_processing_helpers::ApplyPacketOptions( - &rtp_packet[0], rtp_packet.size(), options, 0xccbbaa)); - // HMAC should be different from fake_tag. - EXPECT_NE(0, memcmp(&rtp_packet[sizeof(kRtpMsgWithAbsSendTimeExtension)], - kFakeTag, sizeof(kFakeTag))); - - // ApplyPackets should have the new timestamp passed as input. - unsigned char timestamp_array[3] = { 0xcc, 0xbb, 0xaa }; - EXPECT_EQ(0, memcmp(&rtp_packet[kAstIndexInRtpMsg], - timestamp_array, sizeof(timestamp_array))); -} - -} // namespace content
diff --git a/content/browser/renderer_host/render_process_host_impl.cc b/content/browser/renderer_host/render_process_host_impl.cc index d3443ea..7fe67ce 100644 --- a/content/browser/renderer_host/render_process_host_impl.cc +++ b/content/browser/renderer_host/render_process_host_impl.cc
@@ -144,6 +144,7 @@ #include "content/public/browser/worker_service.h" #include "content/public/common/child_process_host.h" #include "content/public/common/content_constants.h" +#include "content/public/common/content_features.h" #include "content/public/common/content_switches.h" #include "content/public/common/mojo_channel_switches.h" #include "content/public/common/process_type.h" @@ -2494,7 +2495,17 @@ is_process_backgrounded_ = child_process_launcher_->GetProcess().IsProcessBackgrounded(); +#if defined(OS_WIN) + // Experiment with not setting the initial priority of a renderer, as this + // might be a visible tab but since no widgets are currently present, it + // will get backgrounded. See https://crbug.com/560446. + if (base::FeatureList::IsEnabled( + features::kUpdateRendererPriorityOnStartup)) { + UpdateProcessPriority(); + } +#else UpdateProcessPriority(); +#endif } // NOTE: This needs to be before sending queued messages because
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc index eee0310..ccadfb2 100644 --- a/content/browser/web_contents/web_contents_impl.cc +++ b/content/browser/web_contents/web_contents_impl.cc
@@ -206,7 +206,10 @@ return true; } -void SendToAllFramesInternal(IPC::Message* message, RenderFrameHost* rfh) { +void SendToAllFramesInternal(int* number_of_messages, + IPC::Message* message, + RenderFrameHost* rfh) { + *number_of_messages = *number_of_messages + 1; IPC::Message* message_copy = new IPC::Message(*message); message_copy->set_routing_id(rfh->GetRoutingID()); rfh->Send(message_copy); @@ -789,9 +792,12 @@ frame_tree_.ForEach(base::Bind(&ForEachFrameInternal, on_frame)); } -void WebContentsImpl::SendToAllFrames(IPC::Message* message) { - ForEachFrame(base::Bind(&SendToAllFramesInternal, message)); +int WebContentsImpl::SendToAllFrames(IPC::Message* message) { + int number_of_messages = 0; + ForEachFrame( + base::Bind(&SendToAllFramesInternal, &number_of_messages, message)); delete message; + return number_of_messages; } RenderViewHostImpl* WebContentsImpl::GetRenderViewHost() const {
diff --git a/content/browser/web_contents/web_contents_impl.h b/content/browser/web_contents/web_contents_impl.h index a247d03..f0e8b0b 100644 --- a/content/browser/web_contents/web_contents_impl.h +++ b/content/browser/web_contents/web_contents_impl.h
@@ -244,7 +244,7 @@ int frame_tree_node_id) override; void ForEachFrame( const base::Callback<void(RenderFrameHost*)>& on_frame) override; - void SendToAllFrames(IPC::Message* message) override; + int SendToAllFrames(IPC::Message* message) override; RenderViewHostImpl* GetRenderViewHost() const override; int GetRoutingID() const override; RenderWidgetHostView* GetRenderWidgetHostView() const override;
diff --git a/content/browser/webui/web_ui_data_source_unittest.cc b/content/browser/webui/web_ui_data_source_unittest.cc index 0cfc752..492415c 100644 --- a/content/browser/webui/web_ui_data_source_unittest.cc +++ b/content/browser/webui/web_ui_data_source_unittest.cc
@@ -1,4 +1,4 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. @@ -31,7 +31,6 @@ if (message_id == kDummyStringId) return base::UTF8ToUTF16(kDummyString); return base::string16(); - } base::RefCountedStaticMemory* GetDataResourceBytes( @@ -48,7 +47,7 @@ } }; -} +} // namespace class WebUIDataSourceTest : public testing::Test { public: @@ -56,12 +55,9 @@ ~WebUIDataSourceTest() override {} WebUIDataSourceImpl* source() { return source_.get(); } - void StartDataRequest(const std::string& path) { - source_->StartDataRequest( - path, - 0, 0, - base::Bind(&WebUIDataSourceTest::SendResult, - base::Unretained(this))); + void StartDataRequest(const std::string& path, + const URLDataSource::GotDataCallback& callback) { + source_->StartDataRequest(path, 0, 0, callback); } std::string GetMimeType(const std::string& path) const { @@ -74,8 +70,10 @@ return true; } + void RequestFilterQueryStringCallback( + scoped_refptr<base::RefCountedMemory> data); + protected: - scoped_refptr<base::RefCountedMemory> result_data_; std::string request_path_; private: @@ -88,61 +86,88 @@ source_ = make_scoped_refptr(source_impl); } - // Store response for later comparisons. - void SendResult(scoped_refptr<base::RefCountedMemory> data) { - result_data_ = data; - } - TestBrowserThreadBundle thread_bundle_; scoped_refptr<WebUIDataSourceImpl> source_; TestClient client_; }; -TEST_F(WebUIDataSourceTest, EmptyStrings) { - source()->SetJsonPath("strings.js"); - StartDataRequest("strings.js"); - std::string result(result_data_->front_as<char>(), result_data_->size()); +void EmptyStringsCallback(scoped_refptr<base::RefCountedMemory> data) { + std::string result(data->front_as<char>(), data->size()); EXPECT_NE(result.find("loadTimeData.data = {"), std::string::npos); EXPECT_NE(result.find("};"), std::string::npos); } +TEST_F(WebUIDataSourceTest, EmptyStrings) { + source()->SetJsonPath("strings.js"); + StartDataRequest("strings.js", base::Bind(&EmptyStringsCallback)); +} + +void SomeStringsCallback(scoped_refptr<base::RefCountedMemory> data) { + std::string result(data->front_as<char>(), data->size()); + EXPECT_NE(result.find("\"planet\":\"pluto\""), std::string::npos); + EXPECT_NE(result.find("\"button\":\"foo\""), std::string::npos); +} + TEST_F(WebUIDataSourceTest, SomeStrings) { source()->SetJsonPath("strings.js"); source()->AddString("planet", base::ASCIIToUTF16("pluto")); source()->AddLocalizedString("button", kDummyStringId); - StartDataRequest("strings.js"); - std::string result(result_data_->front_as<char>(), result_data_->size()); - EXPECT_NE(result.find("\"planet\":\"pluto\""), std::string::npos); - EXPECT_NE(result.find("\"button\":\"foo\""), std::string::npos); + StartDataRequest("strings.js", base::Bind(&SomeStringsCallback)); +} + +void DefaultResourceFoobarCallback(scoped_refptr<base::RefCountedMemory> data) { + std::string result(data->front_as<char>(), data->size()); + EXPECT_NE(result.find(kDummyDefaultResource), std::string::npos); +} + +void DefaultResourceStringsCallback( + scoped_refptr<base::RefCountedMemory> data) { + std::string result(data->front_as<char>(), data->size()); + EXPECT_NE(result.find(kDummyDefaultResource), std::string::npos); } TEST_F(WebUIDataSourceTest, DefaultResource) { source()->SetDefaultResource(kDummyDefaultResourceId); - StartDataRequest("foobar"); - std::string result(result_data_->front_as<char>(), result_data_->size()); - EXPECT_NE(result.find(kDummyDefaultResource), std::string::npos); - StartDataRequest("strings.js"); - result = std::string(result_data_->front_as<char>(), result_data_->size()); + StartDataRequest("foobar", base::Bind(&DefaultResourceFoobarCallback)); + StartDataRequest("strings.js", base::Bind(&DefaultResourceStringsCallback)); +} + +void NamedResourceFoobarCallback(scoped_refptr<base::RefCountedMemory> data) { + std::string result(data->front_as<char>(), data->size()); + EXPECT_NE(result.find(kDummyResource), std::string::npos); +} + +void NamedResourceStringsCallback(scoped_refptr<base::RefCountedMemory> data) { + std::string result(data->front_as<char>(), data->size()); EXPECT_NE(result.find(kDummyDefaultResource), std::string::npos); } TEST_F(WebUIDataSourceTest, NamedResource) { source()->SetDefaultResource(kDummyDefaultResourceId); source()->AddResourcePath("foobar", kDummyResourceId); - StartDataRequest("foobar"); - std::string result(result_data_->front_as<char>(), result_data_->size()); + StartDataRequest("foobar", base::Bind(&NamedResourceFoobarCallback)); + StartDataRequest("strings.js", base::Bind(&NamedResourceStringsCallback)); +} + +void NamedResourceWithQueryStringCallback( + scoped_refptr<base::RefCountedMemory> data) { + std::string result(data->front_as<char>(), data->size()); EXPECT_NE(result.find(kDummyResource), std::string::npos); - StartDataRequest("strings.js"); - result = std::string(result_data_->front_as<char>(), result_data_->size()); - EXPECT_NE(result.find(kDummyDefaultResource), std::string::npos); } TEST_F(WebUIDataSourceTest, NamedResourceWithQueryString) { source()->SetDefaultResource(kDummyDefaultResourceId); source()->AddResourcePath("foobar", kDummyResourceId); - StartDataRequest("foobar?query?string"); - std::string result(result_data_->front_as<char>(), result_data_->size()); - EXPECT_NE(result.find(kDummyResource), std::string::npos); + StartDataRequest("foobar?query?string", + base::Bind(&NamedResourceWithQueryStringCallback)); +} + +void WebUIDataSourceTest::RequestFilterQueryStringCallback( + scoped_refptr<base::RefCountedMemory> data) { + std::string result(data->front_as<char>(), data->size()); + // Check that the query string is passed to the request filter (and not + // trimmed). + EXPECT_EQ("foobar?query?string", request_path_); } TEST_F(WebUIDataSourceTest, RequestFilterQueryString) { @@ -151,10 +176,10 @@ base::Bind(&WebUIDataSourceTest::HandleRequest, base::Unretained(this))); source()->SetDefaultResource(kDummyDefaultResourceId); source()->AddResourcePath("foobar", kDummyResourceId); - StartDataRequest("foobar?query?string"); - // Check that the query string is passed to the request filter (and not - // trimmed). - EXPECT_EQ("foobar?query?string", request_path_); + StartDataRequest( + "foobar?query?string", + base::Bind(&WebUIDataSourceTest::RequestFilterQueryStringCallback, + base::Unretained(this))); } TEST_F(WebUIDataSourceTest, MimeType) {
diff --git a/content/child/runtime_features.cc b/content/child/runtime_features.cc index 03c2495..514df27 100644 --- a/content/child/runtime_features.cc +++ b/content/child/runtime_features.cc
@@ -30,9 +30,6 @@ namespace content { static void SetRuntimeFeatureDefaultsForPlatform() { - // Enable non-standard "apple-touch-icon" and "apple-touch-icon-precomposed". - WebRuntimeFeatures::enableTouchIconLoading(true); - #if defined(OS_ANDROID) // MSE/EME implementation needs Android MediaCodec API. if (!media::MediaCodecUtil::IsMediaCodecAvailable()) {
diff --git a/content/common/bluetooth/bluetooth_messages.h b/content/common/bluetooth/bluetooth_messages.h index 52255700..b93af6cb 100644 --- a/content/common/bluetooth/bluetooth_messages.h +++ b/content/common/bluetooth/bluetooth_messages.h
@@ -226,56 +226,71 @@ std::vector<device::BluetoothUUID> /* optional_services */) // Connects to a bluetooth device. -IPC_MESSAGE_CONTROL3(BluetoothHostMsg_ConnectGATT, +IPC_MESSAGE_CONTROL4(BluetoothHostMsg_ConnectGATT, int /* thread_id */, int /* request_id */, + int /* frame_routing_id */, + std::string /* device_id */) + +// Disconnect from a device. +IPC_MESSAGE_CONTROL3(BluetoothHostMsg_Disconnect, + int /* thread_id */, + int /* frame_routing_id */, std::string /* device_id */) // Gets primary service from bluetooth device. -IPC_MESSAGE_CONTROL4(BluetoothHostMsg_GetPrimaryService, +IPC_MESSAGE_CONTROL5(BluetoothHostMsg_GetPrimaryService, int /* thread_id */, int /* request_id */, + int /* frame_routing_id */, std::string /* device_id */, std::string /* service_uuid */) // Gets a GATT Characteristic within a GATT Service. -IPC_MESSAGE_CONTROL4(BluetoothHostMsg_GetCharacteristic, +IPC_MESSAGE_CONTROL5(BluetoothHostMsg_GetCharacteristic, int /* thread_id */, int /* request_id */, + int /* frame_routing_id */, std::string /* service_instance_id */, std::string /* characteristic_uuid */) // Reads the characteristics value from a bluetooth device. -IPC_MESSAGE_CONTROL3(BluetoothHostMsg_ReadValue, +IPC_MESSAGE_CONTROL4(BluetoothHostMsg_ReadValue, int /* thread_id */, int /* request_id */, + int /* frame_routing_id */, std::string /* characteristic_instance_id */) // Writes a value to a bluetooth device's characteristic. -IPC_MESSAGE_CONTROL4(BluetoothHostMsg_WriteValue, +IPC_MESSAGE_CONTROL5(BluetoothHostMsg_WriteValue, int /* thread_id */, int /* request_id */, + int /* frame_routing_id */, std::string /* characteristic_instance_id */, std::vector<uint8_t> /* value */) // Subscribes to notifications from a device's characteristic. -IPC_MESSAGE_CONTROL3(BluetoothHostMsg_StartNotifications, +IPC_MESSAGE_CONTROL4(BluetoothHostMsg_StartNotifications, int /* thread_id */, int /* request_id */, + int /* frame_routing_id */, std::string /* characteristic_instance_id */) // Unsubscribes from notifications from a device's characteristic. -IPC_MESSAGE_CONTROL3(BluetoothHostMsg_StopNotifications, +IPC_MESSAGE_CONTROL4(BluetoothHostMsg_StopNotifications, int /* thread_id */, int /* request_id */, + int /* frame_routing_id */, std::string /* characteristic_instance_id */) // Register to receive characteristic value changed events. -IPC_MESSAGE_CONTROL2(BluetoothHostMsg_RegisterCharacteristic, +IPC_MESSAGE_CONTROL3(BluetoothHostMsg_RegisterCharacteristic, int /* thread_id */, + int /* frame_routing_id */, std::string /* characteristics_instance_id */) // Unregister from characteristic value changed events. -IPC_MESSAGE_CONTROL2(BluetoothHostMsg_UnregisterCharacteristic, +IPC_MESSAGE_CONTROL3(BluetoothHostMsg_UnregisterCharacteristic, int /* thread_id */, + int /* frame_routing_id */, std::string /* characteristics_instance_id */)
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc index 21bdb8b..40a3239 100644 --- a/content/common/gpu/media/dxva_video_decode_accelerator_win.cc +++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.cc
@@ -859,6 +859,23 @@ } RETURN_ON_HR_FAILURE(hr, "Failed to create video format converter", false); + + base::win::ScopedComPtr<IMFAttributes> converter_attributes; + hr = video_format_converter_mft_->GetAttributes( + converter_attributes.Receive()); + RETURN_ON_HR_FAILURE(hr, "Failed to get converter attributes", false); + + hr = converter_attributes->SetUINT32(MF_XVP_PLAYBACK_MODE, TRUE); + RETURN_ON_HR_FAILURE( + hr, + "Failed to set MF_XVP_PLAYBACK_MODE attribute on converter", + false); + + hr = converter_attributes->SetUINT32(MF_LOW_LATENCY, FALSE); + RETURN_ON_HR_FAILURE( + hr, + "Failed to set MF_LOW_LATENCY attribute on converter", + false); return true; } @@ -1268,23 +1285,7 @@ bool DXVAVideoDecodeAccelerator::SetDecoderOutputMediaType( const GUID& subtype) { - base::win::ScopedComPtr<IMFMediaType> out_media_type; - - for (uint32_t i = 0; SUCCEEDED( - decoder_->GetOutputAvailableType(0, i, out_media_type.Receive())); - ++i) { - GUID out_subtype = {0}; - HRESULT hr = out_media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype); - RETURN_ON_HR_FAILURE(hr, "Failed to get output major type", false); - - if (out_subtype == subtype) { - hr = decoder_->SetOutputType(0, out_media_type.get(), 0); // No flags - RETURN_ON_HR_FAILURE(hr, "Failed to set decoder output type", false); - return true; - } - out_media_type.Release(); - } - return false; + return SetTransformOutputType(decoder_.get(), subtype, 0, 0); } bool DXVAVideoDecodeAccelerator::SendMFTMessage(MFT_MESSAGE_TYPE msg, @@ -2186,29 +2187,6 @@ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set input sub type", PLATFORM_FAILURE, false); - hr = media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, - "Failed to set attributes on media type", PLATFORM_FAILURE, false); - - hr = media_type->SetUINT32(MF_MT_INTERLACE_MODE, - MFVideoInterlace_Progressive); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, - "Failed to set attributes on media type", PLATFORM_FAILURE, false); - - base::win::ScopedComPtr<IMFAttributes> converter_attributes; - hr = video_format_converter_mft_->GetAttributes( - converter_attributes.Receive()); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to get converter attributes", - PLATFORM_FAILURE, false); - - hr = converter_attributes->SetUINT32(MF_XVP_PLAYBACK_MODE, TRUE); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter attributes", - PLATFORM_FAILURE, false); - - hr = converter_attributes->SetUINT32(MF_LOW_LATENCY, FALSE); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter attributes", - PLATFORM_FAILURE, false); - hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, height); RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set media type attributes", PLATFORM_FAILURE, false); @@ -2224,50 +2202,31 @@ RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to set converter input type", PLATFORM_FAILURE, false); - base::win::ScopedComPtr<IMFMediaType> out_media_type; - - for (uint32_t i = 0; - SUCCEEDED(video_format_converter_mft_->GetOutputAvailableType( - 0, i, out_media_type.Receive())); - ++i) { - GUID out_subtype = {0}; - hr = out_media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, "Failed to get output major type", - PLATFORM_FAILURE, false); - - if (out_subtype == MFVideoFormat_ARGB32) { - hr = out_media_type->SetUINT32(MF_MT_ALL_SAMPLES_INDEPENDENT, TRUE); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, - "Failed to set attributes on media type", PLATFORM_FAILURE, false); - - hr = out_media_type->SetUINT32(MF_MT_INTERLACE_MODE, - MFVideoInterlace_Progressive); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, - "Failed to set attributes on media type", PLATFORM_FAILURE, false); - - hr = MFSetAttributeSize(out_media_type.get(), MF_MT_FRAME_SIZE, width, - height); - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, - "Failed to set media type attributes", PLATFORM_FAILURE, false); - - hr = video_format_converter_mft_->SetOutputType( - 0, out_media_type.get(), 0); // No flags - if (FAILED(hr)) { - base::debug::Alias(&hr); - // TODO(ananta) - // Remove this CHECK when the change to use DX11 for H/W decoding - // stablizes. - CHECK(false); - } - RETURN_AND_NOTIFY_ON_HR_FAILURE(hr, - "Failed to set converter output type", PLATFORM_FAILURE, false); - - dx11_video_format_converter_media_type_needs_init_ = false; - return true; - } - out_media_type.Release(); + // It appears that we fail to set MFVideoFormat_ARGB32 as the output media + // type in certain configurations. Try to fallback to MFVideoFormat_RGB32 + // in such cases. If both fail, then bail. + bool media_type_set = + SetTransformOutputType(video_format_converter_mft_.get(), + MFVideoFormat_ARGB32, + width, + height); + if (!media_type_set) { + media_type_set = + SetTransformOutputType(video_format_converter_mft_.get(), + MFVideoFormat_RGB32, + width, + height); } - return false; + + if (!media_type_set) { + // Remove this once this stabilizes in the field. + CHECK(false); + LOG(ERROR) << "Failed to find a matching RGB output type in the converter"; + return false; + } + + dx11_video_format_converter_media_type_needs_init_ = false; + return true; } bool DXVAVideoDecodeAccelerator::GetVideoFrameDimensions( @@ -2308,4 +2267,41 @@ return true; } +bool DXVAVideoDecodeAccelerator::SetTransformOutputType( + IMFTransform* transform, + const GUID& output_type, + int width, + int height) { + HRESULT hr = E_FAIL; + base::win::ScopedComPtr<IMFMediaType> media_type; + + for (uint32_t i = 0; + SUCCEEDED(transform->GetOutputAvailableType( + 0, i, media_type.Receive())); + ++i) { + GUID out_subtype = {0}; + hr = media_type->GetGUID(MF_MT_SUBTYPE, &out_subtype); + RETURN_ON_HR_FAILURE(hr, "Failed to get output major type", false); + + if (out_subtype == output_type) { + if (width && height) { + hr = MFSetAttributeSize(media_type.get(), MF_MT_FRAME_SIZE, width, + height); + RETURN_ON_HR_FAILURE(hr, "Failed to set media type attributes", false); + } + hr = transform->SetOutputType(0, media_type.get(), 0); // No flags + if (FAILED(hr)) { + base::debug::Alias(&hr); + // TODO(ananta) + // Remove this CHECK when this stabilizes in the field. + CHECK(false); + } + RETURN_ON_HR_FAILURE(hr, "Failed to set output type", false); + return true; + } + media_type.Release(); + } + return false; +} + } // namespace content
diff --git a/content/common/gpu/media/dxva_video_decode_accelerator_win.h b/content/common/gpu/media/dxva_video_decode_accelerator_win.h index 7ebd63ad..d3aeda6 100644 --- a/content/common/gpu/media/dxva_video_decode_accelerator_win.h +++ b/content/common/gpu/media/dxva_video_decode_accelerator_win.h
@@ -246,6 +246,17 @@ // Returns true on success. bool GetVideoFrameDimensions(IMFSample* sample, int* width, int* height); + // Sets the output type on the |transform| to the GUID identified by the + // the |output_type| parameter. The GUID can be MFVideoFormat_RGB32, + // MFVideoFormat_ARGB32, MFVideoFormat_NV12, etc. + // Additionally if the |width| and |height| parameters are non zero, then + // this function also sets the MF_MT_FRAME_SIZE attribute on the type. + // Returns true on success. + bool SetTransformOutputType(IMFTransform* transform, + const GUID& output_type, + int width, + int height); + // To expose client callbacks from VideoDecodeAccelerator. media::VideoDecodeAccelerator::Client* client_;
diff --git a/content/common/media/media_player_messages_android.h b/content/common/media/media_player_messages_android.h index c314f8c..b4e0ba6e 100644 --- a/content/common/media/media_player_messages_android.h +++ b/content/common/media/media_player_messages_android.h
@@ -7,9 +7,9 @@ #include "base/time/time.h" #include "content/common/content_export.h" -#include "content/common/media/media_player_messages_enums_android.h" #include "ipc/ipc_message_macros.h" #include "media/base/android/demuxer_stream_player_params.h" +#include "media/blink/renderer_media_player_interface.h" #include "ui/gfx/geometry/rect_f.h" #include "url/gurl.h"
diff --git a/content/common/media/media_player_messages_enums_android.h b/content/common/media/media_player_messages_enums_android.h deleted file mode 100644 index 50dec95..0000000 --- a/content/common/media/media_player_messages_enums_android.h +++ /dev/null
@@ -1,15 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_ANDROID_H_ -#define CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_ANDROID_H_ - -// Dictates which type of media playback is being initialized. -enum MediaPlayerHostMsg_Initialize_Type { - MEDIA_PLAYER_TYPE_URL, - MEDIA_PLAYER_TYPE_MEDIA_SOURCE, - MEDIA_PLAYER_TYPE_LAST = MEDIA_PLAYER_TYPE_MEDIA_SOURCE -}; - -#endif // CONTENT_COMMON_MEDIA_MEDIA_PLAYER_MESSAGES_ENUMS_ANDROID_H_
diff --git a/content/content_browser.gypi b/content/content_browser.gypi index 62f09c2..bc4ed21 100644 --- a/content/content_browser.gypi +++ b/content/content_browser.gypi
@@ -438,6 +438,8 @@ 'browser/background_sync/background_sync_status.h', 'browser/bad_message.cc', 'browser/bad_message.h', + 'browser/bluetooth/bluetooth_allowed_devices_map.cc', + 'browser/bluetooth/bluetooth_allowed_devices_map.h', 'browser/bluetooth/bluetooth_dispatcher_host.cc', 'browser/bluetooth/bluetooth_dispatcher_host.h', 'browser/bluetooth/bluetooth_metrics.cc',
diff --git a/content/content_common.gypi b/content/content_common.gypi index f18b3b40..f7cfbdda 100644 --- a/content/content_common.gypi +++ b/content/content_common.gypi
@@ -433,7 +433,6 @@ 'common/media/media_param_traits.cc', 'common/media/media_param_traits.h', 'common/media/media_player_messages_android.h', - 'common/media/media_player_messages_enums_android.h', 'common/media/media_session_messages_android.h', 'common/media/media_stream_messages.h', 'common/media/media_stream_options.cc',
diff --git a/content/content_tests.gypi b/content/content_tests.gypi index 58d4d8a2..179de64 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi
@@ -203,6 +203,7 @@ 'browser/background_sync/background_sync_browsertest.cc', 'browser/battery_status/battery_monitor_impl_browsertest.cc', 'browser/battery_status/battery_monitor_integration_browsertest.cc', + 'browser/bluetooth/bluetooth_allowed_devices_map_unittest.cc', 'browser/bookmarklet_browsertest.cc', 'browser/browser_side_navigation_browsertest.cc', 'browser/child_process_launcher_browsertest.cc', @@ -764,7 +765,6 @@ 'browser/renderer_host/p2p/socket_host_test_utils.cc', 'browser/renderer_host/p2p/socket_host_test_utils.h', 'browser/renderer_host/p2p/socket_host_udp_unittest.cc', - 'browser/renderer_host/p2p/socket_host_unittest.cc', 'renderer/media/audio_repetition_detector_unittest.cc', 'renderer/media/audio_track_recorder_unittest.cc', 'renderer/media/canvas_capture_handler_unittest.cc',
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnectionImpl.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnectionImpl.java index 674cf87..fb90345 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnectionImpl.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessConnectionImpl.java
@@ -104,16 +104,24 @@ private boolean mBound = false; private final int mBindFlags; + private final ChildProcessLauncher.ChildProcessCreationParams mCreationParams; private Intent createServiceBindIntent() { + final String packageName = mCreationParams != null + ? mCreationParams.getPackageName() : mContext.getPackageName(); Intent intent = new Intent(); - intent.setClassName(mContext, mServiceClass.getName() + mServiceNumber); - intent.setPackage(mContext.getPackageName()); + intent.setComponent( + new ComponentName(packageName, mServiceClass.getName() + mServiceNumber)); return intent; } - public ChildServiceConnection(int bindFlags) { + public ChildServiceConnection(int bindFlags, + ChildProcessLauncher.ChildProcessCreationParams creationParams) { + if (creationParams != null) { + bindFlags = creationParams.addExtraBindFlags(bindFlags); + } mBindFlags = bindFlags; + mCreationParams = creationParams; } boolean bind(String[] commandLine) { @@ -201,7 +209,8 @@ ChildProcessConnection.DeathCallback deathCallback, Class<? extends ChildProcessService> serviceClass, ChromiumLinkerParams chromiumLinkerParams, - boolean alwaysInForeground) { + boolean alwaysInForeground, + ChildProcessLauncher.ChildProcessCreationParams creationParams) { mContext = context; mServiceNumber = number; mInSandbox = inSandbox; @@ -211,12 +220,12 @@ mAlwaysInForeground = alwaysInForeground; int initialFlags = Context.BIND_AUTO_CREATE; if (mAlwaysInForeground) initialFlags |= Context.BIND_IMPORTANT; - mInitialBinding = new ChildServiceConnection(initialFlags); + mInitialBinding = new ChildServiceConnection(initialFlags, creationParams); mStrongBinding = new ChildServiceConnection( - Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT); + Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT, creationParams); mWaivedBinding = new ChildServiceConnection( - Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY); - mModerateBinding = new ChildServiceConnection(Context.BIND_AUTO_CREATE); + Context.BIND_AUTO_CREATE | Context.BIND_WAIVE_PRIORITY, creationParams); + mModerateBinding = new ChildServiceConnection(Context.BIND_AUTO_CREATE, creationParams); } @Override
diff --git a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java index 0fa969b..71ad6d0 100644 --- a/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java +++ b/content/public/android/java/src/org/chromium/content/browser/ChildProcessLauncher.java
@@ -53,6 +53,44 @@ private static final String SWITCH_UTILITY_PROCESS = "utility"; private static final String SWITCH_GPU_PROCESS = "gpu-process"; + /** + * Allows specifying the package name for looking up child services + * configuration and classes into (if it differs from the application + * package name, like in the case of Android WebView). Also allows + * specifying additional child service binging flags. + */ + public static class ChildProcessCreationParams { + private final String mPackageName; + private final int mExtraBindFlags; + + public ChildProcessCreationParams(String packageName, int extraBindFlags) { + mPackageName = packageName; + mExtraBindFlags = extraBindFlags; + } + + public String getPackageName() { + return mPackageName; + } + + /** + * Adds required extra flags to the given child service binding flags and returns them. + * Does not modify the state of the ChildProcessCreationParams instance. + * + * @param bindFlags Source bind flags to modify. + * @return Bind flags with extra flags added. + */ + public int addExtraBindFlags(int bindFlags) { + return bindFlags | mExtraBindFlags; + } + } + + /** + * Sets ChildProcessCreationParams to be used when creating child services. + */ + public static void setChildProcessCreationParams(ChildProcessCreationParams params) { + sChildProcessCreationParams = params; + } + private static class ChildConnectionAllocator { // Connections to services. Indices of the array correspond to the service numbers. private final ChildProcessConnection[] mChildProcessConnections; @@ -79,7 +117,8 @@ public ChildProcessConnection allocate( Context context, ChildProcessConnection.DeathCallback deathCallback, ChromiumLinkerParams chromiumLinkerParams, - boolean alwaysInForeground) { + boolean alwaysInForeground, + ChildProcessCreationParams creationParams) { synchronized (mConnectionLock) { if (mFreeConnectionIndices.isEmpty()) { Log.d(TAG, "Ran out of services to allocate."); @@ -89,7 +128,7 @@ assert mChildProcessConnections[slot] == null; mChildProcessConnections[slot] = new ChildProcessConnectionImpl(context, slot, mInSandbox, deathCallback, mChildClass, chromiumLinkerParams, - alwaysInForeground); + alwaysInForeground, creationParams); Log.d(TAG, "Allocator allocated a connection, sandbox: %b, slot: %d", mInSandbox, slot); return mChildProcessConnections[slot]; @@ -211,6 +250,7 @@ } } + private static ChildProcessCreationParams sChildProcessCreationParams; private static final PendingSpawnQueue sPendingSpawnQueue = new PendingSpawnQueue(); // Service class for child process. As the default value it uses SandboxedProcessService0 and @@ -229,7 +269,9 @@ private static int getNumberOfServices(Context context, boolean inSandbox) { try { PackageManager packageManager = context.getPackageManager(); - ApplicationInfo appInfo = packageManager.getApplicationInfo(context.getPackageName(), + final String packageName = sChildProcessCreationParams != null + ? sChildProcessCreationParams.getPackageName() : context.getPackageName(); + ApplicationInfo appInfo = packageManager.getApplicationInfo(packageName, PackageManager.GET_META_DATA); int numServices = appInfo.metaData.getInt(inSandbox ? NUM_SANDBOXED_SERVICES_KEY : NUM_PRIVILEGED_SERVICES_KEY, -1); @@ -289,7 +331,7 @@ }; initConnectionAllocatorsIfNecessary(context); return getConnectionAllocator(inSandbox).allocate(context, deathCallback, - chromiumLinkerParams, alwaysInForeground); + chromiumLinkerParams, alwaysInForeground, sChildProcessCreationParams); } private static boolean sLinkerInitialized = false; @@ -325,8 +367,8 @@ private static ChildProcessConnection allocateBoundConnection(Context context, String[] commandLine, boolean inSandbox, boolean alwaysInForeground) { ChromiumLinkerParams chromiumLinkerParams = getLinkerParamsForNewConnection(); - ChildProcessConnection connection = - allocateConnection(context, inSandbox, chromiumLinkerParams, alwaysInForeground); + ChildProcessConnection connection = allocateConnection(context, inSandbox, + chromiumLinkerParams, alwaysInForeground); if (connection != null) { connection.start(commandLine);
diff --git a/content/public/browser/web_contents.h b/content/public/browser/web_contents.h index bc13dc9..a96ed1c 100644 --- a/content/public/browser/web_contents.h +++ b/content/public/browser/web_contents.h
@@ -228,9 +228,10 @@ virtual void ForEachFrame( const base::Callback<void(RenderFrameHost*)>& on_frame) = 0; - // Sends the given IPC to all frames in the currently active view. This is a - // convenience method instead of calling ForEach. - virtual void SendToAllFrames(IPC::Message* message) = 0; + // Sends the given IPC to all frames in the currently active view and returns + // the number of sent messages (i.e. the number of processed frames). This is + // a convenience method instead of calling ForEach. + virtual int SendToAllFrames(IPC::Message* message) = 0; // Gets the current RenderViewHost for this tab. virtual RenderViewHost* GetRenderViewHost() const = 0;
diff --git a/content/public/common/content_features.cc b/content/public/common/content_features.cc index c0b3a7f..32c4a35c 100644 --- a/content/public/common/content_features.cc +++ b/content/public/common/content_features.cc
@@ -11,8 +11,8 @@ // Enables brotli "Accept-Encoding" advertising and "Content-Encoding" support. // Brotli format specification: http://www.ietf.org/id/draft-alakuijala-brotli -const base::Feature kBrotliEncoding = { - "brotli-encoding", base::FEATURE_DISABLED_BY_DEFAULT}; +const base::Feature kBrotliEncoding{"brotli-encoding", + base::FEATURE_DISABLED_BY_DEFAULT}; // Downloads resumption will be controllable via a flag until it's enabled // permanently. See https://crbug.com/7648 @@ -23,6 +23,12 @@ const base::Feature kExperimentalFramework{"ExperimentalFramework", base::FEATURE_DISABLED_BY_DEFAULT}; +// Control whether the priority of a renderer is set when the process is +// launched. This is in response to a bug seen on Windows. See +// https://crbug.com/560446 +const base::Feature kUpdateRendererPriorityOnStartup{ + "UpdateRendererPriorityOnStartup", base::FEATURE_ENABLED_BY_DEFAULT}; + // An experimental User Agent Intervention on WebFonts loading. const base::Feature kWebFontsIntervention{"WebFontsIntervention", base::FEATURE_DISABLED_BY_DEFAULT};
diff --git a/content/public/common/content_features.h b/content/public/common/content_features.h index 0fe8feb..77d264f 100644 --- a/content/public/common/content_features.h +++ b/content/public/common/content_features.h
@@ -19,6 +19,7 @@ CONTENT_EXPORT extern const base::Feature kBrotliEncoding; CONTENT_EXPORT extern const base::Feature kDownloadResumption; CONTENT_EXPORT extern const base::Feature kExperimentalFramework; +CONTENT_EXPORT extern const base::Feature kUpdateRendererPriorityOnStartup; CONTENT_EXPORT extern const base::Feature kWebFontsIntervention; #if defined(OS_ANDROID)
diff --git a/content/renderer/bluetooth/bluetooth_dispatcher.cc b/content/renderer/bluetooth/bluetooth_dispatcher.cc index 82bad22c..ebc7cb2 100644 --- a/content/renderer/bluetooth/bluetooth_dispatcher.cc +++ b/content/renderer/bluetooth/bluetooth_dispatcher.cc
@@ -70,16 +70,19 @@ // Struct that holds a pending Start/StopNotifications request. struct BluetoothNotificationsRequest { BluetoothNotificationsRequest( + int frame_routing_id, const std::string characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic, blink::WebBluetoothNotificationsCallbacks* callbacks, NotificationsRequestType type) - : characteristic_instance_id(characteristic_instance_id), + : frame_routing_id(frame_routing_id), + characteristic_instance_id(characteristic_instance_id), characteristic(characteristic), callbacks(callbacks), type(type) {} ~BluetoothNotificationsRequest() {} + const int frame_routing_id; const std::string characteristic_instance_id; // The characteristic object is owned by the execution context on // the blink side which can destroy the object at any point. Since the @@ -216,61 +219,76 @@ } void BluetoothDispatcher::connectGATT( + int frame_routing_id, const blink::WebString& device_id, blink::WebBluetoothConnectGATTCallbacks* callbacks) { int request_id = pending_connect_requests_.Add(callbacks); Send(new BluetoothHostMsg_ConnectGATT(CurrentWorkerId(), request_id, - device_id.utf8())); + frame_routing_id, device_id.utf8())); +} + +void BluetoothDispatcher::disconnect(int frame_routing_id, + const blink::WebString& device_id) { + Send(new BluetoothHostMsg_Disconnect(CurrentWorkerId(), frame_routing_id, + device_id.utf8())); } void BluetoothDispatcher::getPrimaryService( + int frame_routing_id, const blink::WebString& device_id, const blink::WebString& service_uuid, blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks) { int request_id = pending_primary_service_requests_.Add( new BluetoothPrimaryServiceRequest(device_id, service_uuid, callbacks)); Send(new BluetoothHostMsg_GetPrimaryService( - CurrentWorkerId(), request_id, device_id.utf8(), service_uuid.utf8())); + CurrentWorkerId(), request_id, frame_routing_id, device_id.utf8(), + service_uuid.utf8())); } void BluetoothDispatcher::getCharacteristic( + int frame_routing_id, const blink::WebString& service_instance_id, const blink::WebString& characteristic_uuid, blink::WebBluetoothGetCharacteristicCallbacks* callbacks) { int request_id = pending_characteristic_requests_.Add(new BluetoothCharacteristicRequest( service_instance_id, characteristic_uuid, callbacks)); - Send(new BluetoothHostMsg_GetCharacteristic(CurrentWorkerId(), request_id, - service_instance_id.utf8(), - characteristic_uuid.utf8())); + Send(new BluetoothHostMsg_GetCharacteristic( + CurrentWorkerId(), request_id, frame_routing_id, + service_instance_id.utf8(), characteristic_uuid.utf8())); } void BluetoothDispatcher::readValue( + int frame_routing_id, const blink::WebString& characteristic_instance_id, blink::WebBluetoothReadValueCallbacks* callbacks) { int request_id = pending_read_value_requests_.Add(callbacks); Send(new BluetoothHostMsg_ReadValue(CurrentWorkerId(), request_id, + frame_routing_id, characteristic_instance_id.utf8())); } void BluetoothDispatcher::writeValue( + int frame_routing_id, const blink::WebString& characteristic_instance_id, const blink::WebVector<uint8_t>& value, blink::WebBluetoothWriteValueCallbacks* callbacks) { int request_id = pending_write_value_requests_.Add(callbacks); Send(new BluetoothHostMsg_WriteValue( - CurrentWorkerId(), request_id, characteristic_instance_id.utf8(), + CurrentWorkerId(), request_id, frame_routing_id, + characteristic_instance_id.utf8(), std::vector<uint8_t>(value.begin(), value.end()))); } void BluetoothDispatcher::startNotifications( + int frame_routing_id, const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic, blink::WebBluetoothNotificationsCallbacks* callbacks) { - int request_id = QueueNotificationRequest(characteristic_instance_id.utf8(), - characteristic, callbacks, - NotificationsRequestType::START); + int request_id = QueueNotificationRequest( + frame_routing_id, characteristic_instance_id.utf8(), characteristic, + callbacks, NotificationsRequestType::START); // The Notification subscription's state can change after a request // finishes. To avoid resolving with a soon-to-be-invalid state we queue // requests. @@ -283,12 +301,13 @@ } void BluetoothDispatcher::stopNotifications( + int frame_routing_id, const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic, blink::WebBluetoothNotificationsCallbacks* callbacks) { - int request_id = QueueNotificationRequest(characteristic_instance_id.utf8(), - characteristic, callbacks, - NotificationsRequestType::STOP); + int request_id = QueueNotificationRequest( + frame_routing_id, characteristic_instance_id.utf8(), characteristic, + callbacks, NotificationsRequestType::STOP); if (HasNotificationRequestResponsePending( characteristic_instance_id.utf8())) { return; @@ -298,6 +317,7 @@ } void BluetoothDispatcher::characteristicObjectRemoved( + int frame_routing_id, const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic) { // We need to remove references to the object from the following: @@ -309,7 +329,7 @@ // TODO(ortuno): We should only unregister a characteristic once // there are no characteristic objects that have listeners attached. // https://crbug.com/541388 - UnregisterCharacteristicObject(characteristic_instance_id); + UnregisterCharacteristicObject(frame_routing_id, characteristic_instance_id); // 2 // If the object is in the queue we null the characteristic. If this is the @@ -356,11 +376,12 @@ // We pass in the characteristic so that ResolveOrSendStopNotificationsRequest // can remove the characteristic from ActiveNotificationSubscriptions. ResolveOrSendStopNotificationsRequest(QueueNotificationRequest( - characteristic_instance_id.utf8(), characteristic, + frame_routing_id, characteristic_instance_id.utf8(), characteristic, nullptr /* callbacks */, NotificationsRequestType::STOP)); } void BluetoothDispatcher::registerCharacteristicObject( + int frame_routing_id, const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic) { // TODO(ortuno): After the Object manager is implemented, there will @@ -373,7 +394,7 @@ std::make_pair(characteristic_instance_id.utf8(), characteristic)); Send(new BluetoothHostMsg_RegisterCharacteristic( - CurrentWorkerId(), characteristic_instance_id.utf8())); + CurrentWorkerId(), frame_routing_id, characteristic_instance_id.utf8())); } void BluetoothDispatcher::WillStopCurrentWorkerThread() { @@ -381,13 +402,15 @@ } int BluetoothDispatcher::QueueNotificationRequest( + int frame_routing_id, const std::string& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic, blink::WebBluetoothNotificationsCallbacks* callbacks, NotificationsRequestType type) { int request_id = pending_notifications_requests_.Add(new BluetoothNotificationsRequest( - characteristic_instance_id, characteristic, callbacks, type)); + frame_routing_id, characteristic_instance_id, characteristic, + callbacks, type)); notification_requests_queues_[characteristic_instance_id].push(request_id); return request_id; @@ -473,6 +496,7 @@ int request_id) { BluetoothNotificationsRequest* request = pending_notifications_requests_.Lookup(request_id); + const int frame_routing_id = request->frame_routing_id; const std::string& characteristic_instance_id = request->characteristic_instance_id; blink::WebBluetoothGATTCharacteristic* characteristic = @@ -495,6 +519,7 @@ } Send(new BluetoothHostMsg_StartNotifications(CurrentWorkerId(), request_id, + frame_routing_id, characteristic_instance_id)); } @@ -505,6 +530,7 @@ // requests. BluetoothNotificationsRequest* request = pending_notifications_requests_.Lookup(request_id); + const int frame_routing_id = request->frame_routing_id; const std::string& characteristic_instance_id = request->characteristic_instance_id; blink::WebBluetoothGATTCharacteristic* characteristic = @@ -516,6 +542,7 @@ if (RemoveFromActiveNotificationSubscriptions(characteristic_instance_id, characteristic)) { Send(new BluetoothHostMsg_StopNotifications(CurrentWorkerId(), request_id, + frame_routing_id, characteristic_instance_id)); return; } @@ -532,12 +559,14 @@ } void BluetoothDispatcher::UnregisterCharacteristicObject( + int frame_routing_id, const blink::WebString& characteristic_instance_id) { int removed = active_characteristics_.erase(characteristic_instance_id.utf8()); if (removed != 0) { Send(new BluetoothHostMsg_UnregisterCharacteristic( - CurrentWorkerId(), characteristic_instance_id.utf8())); + CurrentWorkerId(), frame_routing_id, + characteristic_instance_id.utf8())); } } @@ -708,8 +737,9 @@ // which would result in the subscription continuing. if (request->characteristic == nullptr) { QueueNotificationRequest( - request->characteristic_instance_id, nullptr /* characteristic */, - nullptr /* callbacks */, NotificationsRequestType::STOP); + request->frame_routing_id, request->characteristic_instance_id, + nullptr /* characteristic */, nullptr /* callbacks */, + NotificationsRequestType::STOP); } request->callbacks->onSuccess();
diff --git a/content/renderer/bluetooth/bluetooth_dispatcher.h b/content/renderer/bluetooth/bluetooth_dispatcher.h index 6dbd5ea..73d69d15 100644 --- a/content/renderer/bluetooth/bluetooth_dispatcher.h +++ b/content/renderer/bluetooth/bluetooth_dispatcher.h
@@ -64,32 +64,42 @@ void requestDevice(int frame_routing_id, const blink::WebRequestDeviceOptions& options, blink::WebBluetoothRequestDeviceCallbacks* callbacks); - void connectGATT(const blink::WebString& device_id, + void connectGATT(int frame_routing_id, + const blink::WebString& device_id, blink::WebBluetoothConnectGATTCallbacks* callbacks); + void disconnect(int frame_routing_id, const blink::WebString& device_id); void getPrimaryService( + int frame_routing_id, const blink::WebString& device_id, const blink::WebString& service_uuid, blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks); void getCharacteristic( + int frame_routing_id, const blink::WebString& service_instance_id, const blink::WebString& characteristic_uuid, blink::WebBluetoothGetCharacteristicCallbacks* callbacks); - void readValue(const blink::WebString& characteristic_instance_id, + void readValue(int frame_routing_id, + const blink::WebString& characteristic_instance_id, blink::WebBluetoothReadValueCallbacks* callbacks); - void writeValue(const blink::WebString& characteristic_instance_id, + void writeValue(int frame_routing_id, + const blink::WebString& characteristic_instance_id, const blink::WebVector<uint8_t>& value, blink::WebBluetoothWriteValueCallbacks*); - void startNotifications(const blink::WebString& characteristic_instance_id, + void startNotifications(int frame_routing_id, + const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* delegate, blink::WebBluetoothNotificationsCallbacks*); - void stopNotifications(const blink::WebString& characteristic_instance_id, + void stopNotifications(int frame_routing_id, + const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* delegate, blink::WebBluetoothNotificationsCallbacks*); void characteristicObjectRemoved( + int frame_routing_id, const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* delegate); void registerCharacteristicObject( + int frame_routing_id, const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic); @@ -113,6 +123,7 @@ // Creates a notification request and queues it. int QueueNotificationRequest( + int frame_routing_id, const std::string& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic, blink::WebBluetoothNotificationsCallbacks* callbacks, @@ -157,6 +168,7 @@ // receiving notifications. // https://crbug.com/541388 void UnregisterCharacteristicObject( + int frame_routing_id, const blink::WebString& characteristic_instance_id); // IPC Handlers, see definitions in bluetooth_messages.h.
diff --git a/content/renderer/bluetooth/web_bluetooth_impl.cc b/content/renderer/bluetooth/web_bluetooth_impl.cc index 92d035b..3443d2d 100644 --- a/content/renderer/bluetooth/web_bluetooth_impl.cc +++ b/content/renderer/bluetooth/web_bluetooth_impl.cc
@@ -30,65 +30,72 @@ void WebBluetoothImpl::connectGATT( const blink::WebString& device_id, blink::WebBluetoothConnectGATTCallbacks* callbacks) { - GetDispatcher()->connectGATT(device_id, callbacks); + GetDispatcher()->connectGATT(frame_routing_id_, device_id, callbacks); +} + +void WebBluetoothImpl::disconnect(const blink::WebString& device_id) { + GetDispatcher()->disconnect(frame_routing_id_, device_id); } void WebBluetoothImpl::getPrimaryService( const blink::WebString& device_id, const blink::WebString& service_uuid, blink::WebBluetoothGetPrimaryServiceCallbacks* callbacks) { - GetDispatcher()->getPrimaryService(device_id, service_uuid, callbacks); + GetDispatcher()->getPrimaryService(frame_routing_id_, device_id, service_uuid, + callbacks); } void WebBluetoothImpl::getCharacteristic( const blink::WebString& service_instance_id, const blink::WebString& characteristic_uuid, blink::WebBluetoothGetCharacteristicCallbacks* callbacks) { - GetDispatcher()->getCharacteristic(service_instance_id, characteristic_uuid, - callbacks); + GetDispatcher()->getCharacteristic(frame_routing_id_, service_instance_id, + characteristic_uuid, callbacks); } void WebBluetoothImpl::readValue( const blink::WebString& characteristic_instance_id, blink::WebBluetoothReadValueCallbacks* callbacks) { - GetDispatcher()->readValue(characteristic_instance_id, callbacks); + GetDispatcher()->readValue(frame_routing_id_, characteristic_instance_id, + callbacks); } void WebBluetoothImpl::writeValue( const blink::WebString& characteristic_instance_id, const blink::WebVector<uint8_t>& value, blink::WebBluetoothWriteValueCallbacks* callbacks) { - GetDispatcher()->writeValue(characteristic_instance_id, value, callbacks); + GetDispatcher()->writeValue(frame_routing_id_, characteristic_instance_id, + value, callbacks); } void WebBluetoothImpl::startNotifications( const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic, blink::WebBluetoothNotificationsCallbacks* callbacks) { - GetDispatcher()->startNotifications(characteristic_instance_id, - characteristic, callbacks); + GetDispatcher()->startNotifications( + frame_routing_id_, characteristic_instance_id, characteristic, callbacks); } void WebBluetoothImpl::stopNotifications( const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic, blink::WebBluetoothNotificationsCallbacks* callbacks) { - GetDispatcher()->stopNotifications(characteristic_instance_id, characteristic, - callbacks); + GetDispatcher()->stopNotifications( + frame_routing_id_, characteristic_instance_id, characteristic, callbacks); } void WebBluetoothImpl::characteristicObjectRemoved( const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic) { - GetDispatcher()->characteristicObjectRemoved(characteristic_instance_id, - characteristic); + GetDispatcher()->characteristicObjectRemoved( + frame_routing_id_, characteristic_instance_id, characteristic); } void WebBluetoothImpl::registerCharacteristicObject( const blink::WebString& characteristic_instance_id, blink::WebBluetoothGATTCharacteristic* characteristic) { - GetDispatcher()->registerCharacteristicObject(characteristic_instance_id, - characteristic); + GetDispatcher()->registerCharacteristicObject( + frame_routing_id_, characteristic_instance_id, characteristic); } BluetoothDispatcher* WebBluetoothImpl::GetDispatcher() {
diff --git a/content/renderer/bluetooth/web_bluetooth_impl.h b/content/renderer/bluetooth/web_bluetooth_impl.h index b5f85d47..4285e32e 100644 --- a/content/renderer/bluetooth/web_bluetooth_impl.h +++ b/content/renderer/bluetooth/web_bluetooth_impl.h
@@ -39,6 +39,7 @@ blink::WebBluetoothRequestDeviceCallbacks* callbacks) override; void connectGATT(const blink::WebString& device_id, blink::WebBluetoothConnectGATTCallbacks* callbacks) override; + void disconnect(const blink::WebString& device_id) override; void getPrimaryService( const blink::WebString& device_id, const blink::WebString& service_uuid,
diff --git a/content/renderer/media/android/renderer_media_player_manager.cc b/content/renderer/media/android/renderer_media_player_manager.cc index b1b39f2..3c054fca 100644 --- a/content/renderer/media/android/renderer_media_player_manager.cc +++ b/content/renderer/media/android/renderer_media_player_manager.cc
@@ -69,7 +69,7 @@ // Suspend and release resources of all playing video. for (auto& player_it : media_players_) { - WebMediaPlayerAndroid* player = player_it.second; + media::RendererMediaPlayerInterface* player = player_it.second; if (!player || player->paused() || !player->hasVideo()) continue; @@ -145,20 +145,20 @@ int width, int height, bool success) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnMediaMetadataChanged(duration, width, height, success); } void RendererMediaPlayerManager::OnMediaPlaybackCompleted(int player_id) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnPlaybackComplete(); } void RendererMediaPlayerManager::OnMediaBufferingUpdate(int player_id, int percent) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnBufferingUpdate(percent); } @@ -166,7 +166,7 @@ void RendererMediaPlayerManager::OnSeekRequest( int player_id, const base::TimeDelta& time_to_seek) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnSeekRequest(time_to_seek); } @@ -174,13 +174,13 @@ void RendererMediaPlayerManager::OnSeekCompleted( int player_id, const base::TimeDelta& current_time) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnSeekComplete(current_time); } void RendererMediaPlayerManager::OnMediaError(int player_id, int error) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnMediaError(error); } @@ -188,7 +188,7 @@ void RendererMediaPlayerManager::OnVideoSizeChanged(int player_id, int width, int height) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnVideoSizeChanged(width, height); } @@ -197,50 +197,50 @@ int player_id, base::TimeDelta current_timestamp, base::TimeTicks current_time_ticks) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnTimeUpdate(current_timestamp, current_time_ticks); } void RendererMediaPlayerManager::OnWaitingForDecryptionKey(int player_id) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnWaitingForDecryptionKey(); } void RendererMediaPlayerManager::OnMediaPlayerReleased(int player_id) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnPlayerReleased(); } void RendererMediaPlayerManager::OnConnectedToRemoteDevice(int player_id, const std::string& remote_playback_message) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnConnectedToRemoteDevice(remote_playback_message); } void RendererMediaPlayerManager::OnDisconnectedFromRemoteDevice(int player_id) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnDisconnectedFromRemoteDevice(); } void RendererMediaPlayerManager::OnDidExitFullscreen(int player_id) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnDidExitFullscreen(); } void RendererMediaPlayerManager::OnPlayerPlay(int player_id) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnMediaPlayerPlay(); } void RendererMediaPlayerManager::OnPlayerPause(int player_id) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnMediaPlayerPause(); } @@ -248,7 +248,7 @@ void RendererMediaPlayerManager::OnRemoteRouteAvailabilityChanged( int player_id, bool routes_available) { - WebMediaPlayerAndroid* player = GetMediaPlayer(player_id); + media::RendererMediaPlayerInterface* player = GetMediaPlayer(player_id); if (player) player->OnRemoteRouteAvailabilityChanged(routes_available); } @@ -266,7 +266,7 @@ } int RendererMediaPlayerManager::RegisterMediaPlayer( - WebMediaPlayerAndroid* player) { + media::RendererMediaPlayerInterface* player) { media_players_[next_media_player_id_] = player; return next_media_player_id_++; } @@ -275,9 +275,9 @@ media_players_.erase(player_id); } -WebMediaPlayerAndroid* RendererMediaPlayerManager::GetMediaPlayer( +media::RendererMediaPlayerInterface* RendererMediaPlayerManager::GetMediaPlayer( int player_id) { - std::map<int, WebMediaPlayerAndroid*>::iterator iter = + std::map<int, media::RendererMediaPlayerInterface*>::iterator iter = media_players_.find(player_id); if (iter != media_players_.end()) return iter->second; @@ -306,11 +306,11 @@ void RendererMediaPlayerManager::RetrieveGeometryChanges( std::map<int, gfx::RectF>* changes) { DCHECK(changes->empty()); - for (std::map<int, WebMediaPlayerAndroid*>::iterator player_it = + for (std::map<int, media::RendererMediaPlayerInterface*>::iterator player_it = media_players_.begin(); player_it != media_players_.end(); ++player_it) { - WebMediaPlayerAndroid* player = player_it->second; + media::RendererMediaPlayerInterface* player = player_it->second; if (player && player->hasVideo()) { if (player->UpdateBoundaryRectangle())
diff --git a/content/renderer/media/android/renderer_media_player_manager.h b/content/renderer/media/android/renderer_media_player_manager.h index a75f091a..b4eb44be 100644 --- a/content/renderer/media/android/renderer_media_player_manager.h +++ b/content/renderer/media/android/renderer_media_player_manager.h
@@ -10,9 +10,9 @@ #include "base/macros.h" #include "base/time/time.h" -#include "content/common/media/media_player_messages_enums_android.h" #include "content/public/renderer/render_frame_observer.h" #include "media/base/android/media_player_android.h" +#include "media/blink/renderer_media_player_interface.h" #include "url/gurl.h" namespace blink { @@ -30,7 +30,9 @@ // Class for managing all the WebMediaPlayerAndroid objects in the same // RenderFrame. -class RendererMediaPlayerManager : public RenderFrameObserver { +class RendererMediaPlayerManager : + public RenderFrameObserver, + public media::RendererMediaPlayerManagerInterface { public: // Constructs a RendererMediaPlayerManager object for the |render_frame|. explicit RendererMediaPlayerManager(RenderFrame* render_frame); @@ -47,38 +49,38 @@ const GURL& first_party_for_cookies, int demuxer_client_id, const GURL& frame_url, - bool allow_credentials); + bool allow_credentials) override; // Starts the player. - void Start(int player_id); + void Start(int player_id) override; // Pauses the player. // is_media_related_action should be true if this pause is coming from an // an action that explicitly pauses the video (user pressing pause, JS, etc.) // Otherwise it should be false if Pause is being called due to other reasons // (cleanup, freeing resources, etc.) - void Pause(int player_id, bool is_media_related_action); + void Pause(int player_id, bool is_media_related_action) override; // Performs seek on the player. - void Seek(int player_id, const base::TimeDelta& time); + void Seek(int player_id, const base::TimeDelta& time) override; // Sets the player volume. - void SetVolume(int player_id, double volume); + void SetVolume(int player_id, double volume) override; // Sets the poster image. - void SetPoster(int player_id, const GURL& poster); + void SetPoster(int player_id, const GURL& poster) override; // Releases resources for the player after being suspended. - void SuspendAndReleaseResources(int player_id); + void SuspendAndReleaseResources(int player_id) override; // Destroys the player in the browser process - void DestroyPlayer(int player_id); + void DestroyPlayer(int player_id) override; // Requests remote playback if possible - void RequestRemotePlayback(int player_id); + void RequestRemotePlayback(int player_id) override; // Requests control of remote playback - void RequestRemotePlaybackControl(int player_id); + void RequestRemotePlaybackControl(int player_id) override; // Requests the player to enter fullscreen. void EnterFullscreen(int player_id); @@ -101,11 +103,11 @@ #endif // defined(VIDEO_HOLE) // Registers and unregisters a WebMediaPlayerAndroid object. - int RegisterMediaPlayer(WebMediaPlayerAndroid* player); - void UnregisterMediaPlayer(int player_id); + int RegisterMediaPlayer(media::RendererMediaPlayerInterface* player) override; + void UnregisterMediaPlayer(int player_id) override; // Gets the pointer to WebMediaPlayerAndroid given the |player_id|. - WebMediaPlayerAndroid* GetMediaPlayer(int player_id); + media::RendererMediaPlayerInterface* GetMediaPlayer(int player_id); #if defined(VIDEO_HOLE) // Gets the list of media players with video geometry changes. @@ -140,15 +142,9 @@ void OnPlayerPause(int player_id); void OnRemoteRouteAvailabilityChanged(int player_id, bool routes_available); - // Release all video player resources. - // If something is in progress the resource will not be freed. It will - // only be freed once the tab is destroyed or if the user navigates away - // via WebMediaPlayerAndroid::Destroy. - void ReleaseVideoResources(); - // Info for all available WebMediaPlayerAndroid on a page; kept so that // we can enumerate them to send updates about tab focus and visibility. - std::map<int, WebMediaPlayerAndroid*> media_players_; + std::map<int, media::RendererMediaPlayerInterface*> media_players_; int next_media_player_id_;
diff --git a/content/renderer/media/android/webmediaplayer_android.cc b/content/renderer/media/android/webmediaplayer_android.cc index e399cde..d232069 100644 --- a/content/renderer/media/android/webmediaplayer_android.cc +++ b/content/renderer/media/android/webmediaplayer_android.cc
@@ -46,6 +46,7 @@ #include "media/base/timestamp_constants.h" #include "media/base/video_frame.h" #include "media/blink/webcontentdecryptionmodule_impl.h" +#include "media/blink/webmediaplayer_cast_android.h" #include "media/blink/webmediaplayer_delegate.h" #include "media/blink/webmediaplayer_util.h" #include "net/base/mime_util.h" @@ -1161,106 +1162,12 @@ static_cast<int>(video_size_css_px.width() * device_scale_factor), static_cast<int>(video_size_css_px.height() * device_scale_factor)); - SkBitmap bitmap; - bitmap.allocN32Pixels(canvas_size.width(), canvas_size.height()); - - // Create the canvas and draw the "Casting to <Chromecast>" text on it. - SkCanvas canvas(bitmap); - canvas.drawColor(SK_ColorBLACK); - - const SkScalar kTextSize(40); - const SkScalar kMinPadding(40); - - SkPaint paint; - paint.setAntiAlias(true); - paint.setFilterQuality(kHigh_SkFilterQuality); - paint.setColor(SK_ColorWHITE); - paint.setTypeface(SkTypeface::CreateFromName("sans", SkTypeface::kBold)); - paint.setTextSize(kTextSize); - - // Calculate the vertical margin from the top - SkPaint::FontMetrics font_metrics; - paint.getFontMetrics(&font_metrics); - SkScalar sk_vertical_margin = kMinPadding - font_metrics.fAscent; - - // Measure the width of the entire text to display - size_t display_text_width = paint.measureText( - remote_playback_message.c_str(), remote_playback_message.size()); - std::string display_text(remote_playback_message); - - if (display_text_width + (kMinPadding * 2) > canvas_size.width()) { - // The text is too long to fit in one line, truncate it and append ellipsis - // to the end. - - // First, figure out how much of the canvas the '...' will take up. - const std::string kTruncationEllipsis("\xE2\x80\xA6"); - SkScalar sk_ellipse_width = paint.measureText( - kTruncationEllipsis.c_str(), kTruncationEllipsis.size()); - - // Then calculate how much of the text can be drawn with the '...' appended - // to the end of the string. - SkScalar sk_max_original_text_width( - canvas_size.width() - (kMinPadding * 2) - sk_ellipse_width); - size_t sk_max_original_text_length = paint.breakText( - remote_playback_message.c_str(), - remote_playback_message.size(), - sk_max_original_text_width); - - // Remove the part of the string that doesn't fit and append '...'. - display_text.erase(sk_max_original_text_length, - remote_playback_message.size() - sk_max_original_text_length); - display_text.append(kTruncationEllipsis); - display_text_width = paint.measureText( - display_text.c_str(), display_text.size()); - } - - // Center the text horizontally. - SkScalar sk_horizontal_margin = - (canvas_size.width() - display_text_width) / 2.0; - canvas.drawText(display_text.c_str(), - display_text.size(), - sk_horizontal_margin, - sk_vertical_margin, - paint); - - GLES2Interface* gl = stream_texture_factory_->ContextGL(); - GLuint remote_playback_texture_id = 0; - gl->GenTextures(1, &remote_playback_texture_id); - GLuint texture_target = GL_TEXTURE_2D; - gl->BindTexture(texture_target, remote_playback_texture_id); - gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - { - SkAutoLockPixels lock(bitmap); - gl->TexImage2D(texture_target, - 0 /* level */, - GL_RGBA /* internalformat */, - bitmap.width(), - bitmap.height(), - 0 /* border */, - GL_RGBA /* format */, - GL_UNSIGNED_BYTE /* type */, - bitmap.getPixels()); - } - - gpu::Mailbox texture_mailbox; - gl->GenMailboxCHROMIUM(texture_mailbox.name); - gl->ProduceTextureCHROMIUM(texture_target, texture_mailbox.name); - gl->Flush(); - gpu::SyncToken texture_mailbox_sync_token(gl->InsertSyncPointCHROMIUM()); - - scoped_refptr<VideoFrame> new_frame = VideoFrame::WrapNativeTexture( - media::PIXEL_FORMAT_ARGB, - gpu::MailboxHolder(texture_mailbox, texture_mailbox_sync_token, - texture_target), - media::BindToCurrentLoop(base::Bind(&OnReleaseTexture, - stream_texture_factory_, - remote_playback_texture_id)), - canvas_size /* coded_size */, gfx::Rect(canvas_size) /* visible_rect */, - canvas_size /* natural_size */, base::TimeDelta() /* timestamp */); + scoped_refptr<VideoFrame> new_frame(media::MakeTextFrameForCast( + remote_playback_message, + canvas_size, + canvas_size, + base::Bind(&StreamTextureFactory::ContextGL, + stream_texture_factory_))); if (!new_frame) return; SetCurrentFrameInternal(new_frame);
diff --git a/content/renderer/media/android/webmediaplayer_android.h b/content/renderer/media/android/webmediaplayer_android.h index 5e96e838..a97da4c 100644 --- a/content/renderer/media/android/webmediaplayer_android.h +++ b/content/renderer/media/android/webmediaplayer_android.h
@@ -18,10 +18,10 @@ #include "base/time/default_tick_clock.h" #include "base/time/time.h" #include "cc/layers/video_frame_provider.h" -#include "content/common/media/media_player_messages_enums_android.h" #include "content/public/renderer/render_frame_observer.h" #include "content/renderer/media/android/media_info_loader.h" #include "content/renderer/media/android/media_source_delegate.h" +#include "content/renderer/media/android/renderer_media_player_manager.h" #include "content/renderer/media/android/stream_texture_factory.h" #include "gpu/command_buffer/common/mailbox.h" #include "media/base/android/media_player_android.h" @@ -81,7 +81,8 @@ class WebMediaPlayerAndroid : public blink::WebMediaPlayer, public cc::VideoFrameProvider, public RenderFrameObserver, - public StreamTextureFactoryContextObserver { + public StreamTextureFactoryContextObserver, + public media::RendererMediaPlayerInterface { public: // Construct a WebMediaPlayerAndroid object. This class communicates with the // MediaPlayerAndroid object in the browser process through |proxy|. @@ -191,37 +192,38 @@ // Media player callback handlers. void OnMediaMetadataChanged(base::TimeDelta duration, int width, - int height, bool success); - void OnPlaybackComplete(); - void OnBufferingUpdate(int percentage); - void OnSeekRequest(const base::TimeDelta& time_to_seek); - void OnSeekComplete(const base::TimeDelta& current_time); - void OnMediaError(int error_type); - void OnVideoSizeChanged(int width, int height); + int height, bool success) override; + void OnPlaybackComplete() override; + void OnBufferingUpdate(int percentage) override; + void OnSeekRequest(const base::TimeDelta& time_to_seek) override; + void OnSeekComplete(const base::TimeDelta& current_time) override; + void OnMediaError(int error_type) override; + void OnVideoSizeChanged(int width, int height) override; void OnDurationChanged(const base::TimeDelta& duration); // Called to update the current time. void OnTimeUpdate(base::TimeDelta current_timestamp, - base::TimeTicks current_time_ticks); + base::TimeTicks current_time_ticks) override; // Functions called when media player status changes. - void OnConnectedToRemoteDevice(const std::string& remote_playback_message); - void OnDisconnectedFromRemoteDevice(); - void OnDidExitFullscreen(); - void OnMediaPlayerPlay(); - void OnMediaPlayerPause(); - void OnRemoteRouteAvailabilityChanged(bool routes_available); + void OnConnectedToRemoteDevice(const std::string& remote_playback_message) + override; + void OnDisconnectedFromRemoteDevice() override; + void OnDidExitFullscreen() override; + void OnMediaPlayerPlay() override; + void OnMediaPlayerPause() override; + void OnRemoteRouteAvailabilityChanged(bool routes_available) override; // StreamTextureFactoryContextObserver implementation. void ResetStreamTextureProxy() override; // Called when the player is released. - virtual void OnPlayerReleased(); + void OnPlayerReleased() override; // This function is called by the RendererMediaPlayerManager to pause the // video and release the media player and surface texture when we switch tabs. // However, the actual GlTexture is not released to keep the video screenshot. - void SuspendAndReleaseResources(); + void SuspendAndReleaseResources() override; // RenderFrameObserver implementation. void OnDestruct() override; @@ -230,9 +232,9 @@ // Calculate the boundary rectangle of the media player (i.e. location and // size of the video frame). // Returns true if the geometry has been changed since the last call. - bool UpdateBoundaryRectangle(); + bool UpdateBoundaryRectangle() override; - const gfx::RectF GetBoundaryRectangle(); + const gfx::RectF GetBoundaryRectangle() override; #endif // defined(VIDEO_HOLE) MediaKeyException generateKeyRequest(const blink::WebString& key_system, @@ -267,7 +269,7 @@ // Called when a decoder detects that the key needed to decrypt the stream // is not available. - void OnWaitingForDecryptionKey(); + void OnWaitingForDecryptionKey() override; protected: // Helper method to update the playing state.
diff --git a/content/renderer/render_frame_impl.cc b/content/renderer/render_frame_impl.cc index 12fdd07b..9b199d39f 100644 --- a/content/renderer/render_frame_impl.cc +++ b/content/renderer/render_frame_impl.cc
@@ -666,6 +666,40 @@ ssl_status.connection_status); } +#if defined(OS_ANDROID) +// Returns true if WMPI is enabled and is expected to be able to play the URL, +// false if WMPA should be used instead. +// +// Note that HLS and WebM detection are pre-redirect and path-based. It is +// possible to load such a URL and find different content, in which case +// playback may fail. +bool CanUseWebMediaPlayerImpl(const GURL& url) { + // WMPI does not support HLS. + if (media::MediaCodecUtil::IsHLSPath(url)) + return false; + + // If --enable-unified-media-pipeline was passed, always use WMPI. (This + // allows for testing the new path.) + if (base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableUnifiedMediaPipeline)) { + return true; + } + + // Don't use WMPI for blob URLs (MSE in particular) yet. + if (url.SchemeIsBlob()) + return false; + + // WMPI can play VPX even without AVDA. + if (base::EndsWith(url.path(), ".webm", base::CompareCase::INSENSITIVE_ASCII)) + return true; + + // Only use WMPI if AVDA is available. + return (media::MediaCodecUtil::IsMediaCodecAvailable() && + !base::CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisableAcceleratedVideoDecode)); +} +#endif // defined(OS_ANDROID) + } // namespace // static @@ -2375,12 +2409,7 @@ GetMediaPermission(), initial_cdm); #if defined(OS_ANDROID) - // We must use WMPA in when accelerated video decode is disabled becuase WMPI - // is unlikely to have a fallback decoder. - if (base::CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableAcceleratedVideoDecode) || - !media::MediaCodecUtil::IsMediaCodecAvailable() || - media::MediaCodecUtil::IsHLSPath(url)) { + if (!CanUseWebMediaPlayerImpl(url)) { return CreateAndroidWebMediaPlayer(client, encrypted_client, params); } else { // TODO(dalecurtis): This experiment is temporary and should be removed once @@ -2421,9 +2450,16 @@ if (!url_index_.get() || url_index_->frame() != frame) url_index_.reset(new media::UrlIndex(frame)); - return new media::WebMediaPlayerImpl( + media::WebMediaPlayerImpl* media_player = new media::WebMediaPlayerImpl( frame, client, encrypted_client, GetWebMediaPlayerDelegate()->AsWeakPtr(), std::move(media_renderer_factory), GetCdmFactory(), url_index_, params); + +#if defined(OS_ANDROID) // WMPI_CAST + media_player->SetMediaPlayerManager(GetMediaPlayerManager()); + media_player->SetDeviceScaleFactor(render_view_->GetDeviceScaleFactor()); +#endif + + return media_player; } blink::WebMediaSession* RenderFrameImpl::createMediaSession() {
diff --git a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc index 46e7ec57..4e62b29 100644 --- a/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc +++ b/content/shell/browser/layout_test/layout_test_bluetooth_adapter_provider.cc
@@ -116,6 +116,7 @@ // Notifies the adapter's observers that the services have been discovered. void NotifyServicesDiscovered(MockBluetoothAdapter* adapter, MockBluetoothDevice* device) { + device->SetGattServicesDiscoveryComplete(true); FOR_EACH_OBSERVER(BluetoothAdapter::Observer, adapter->GetObservers(), GattServicesDiscovered(adapter, device)); }
diff --git a/content/shell/browser/shell_browser_main_parts.cc b/content/shell/browser/shell_browser_main_parts.cc index 48a87e3..520c918 100644 --- a/content/shell/browser/shell_browser_main_parts.cc +++ b/content/shell/browser/shell_browser_main_parts.cc
@@ -25,6 +25,7 @@ #include "content/shell/browser/shell_devtools_manager_delegate.h" #include "content/shell/browser/shell_net_log.h" #include "content/shell/common/shell_switches.h" +#include "device/bluetooth/bluetooth_adapter_factory.h" #include "net/base/filename_util.h" #include "net/base/net_module.h" #include "net/grit/net_resources.h" @@ -43,6 +44,12 @@ #if !defined(OS_CHROMEOS) && defined(USE_AURA) && defined(OS_LINUX) #include "ui/base/ime/input_method_initializer.h" #endif +#if defined(OS_CHROMEOS) +#include "chromeos/dbus/dbus_thread_manager.h" +#include "device/bluetooth/dbus/bluez_dbus_manager.h" +#elif defined(OS_LINUX) +#include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h" +#endif namespace content { @@ -105,6 +112,16 @@ #if defined(OS_ANDROID) base::MessageLoopForUI::current()->Start(); #endif + +#if defined(OS_CHROMEOS) + chromeos::DBusThreadManager::Initialize(); + bluez::BluezDBusManager::Initialize( + chromeos::DBusThreadManager::Get()->GetSystemBus(), + chromeos::DBusThreadManager::Get()->IsUsingStub( + chromeos::DBusClientBundle::BLUETOOTH)); +#elif defined(OS_LINUX) + bluez::DBusBluezManagerWrapperLinux::Initialize(); +#endif } void ShellBrowserMainParts::PreEarlyInitialization() { @@ -168,4 +185,15 @@ off_the_record_browser_context_.reset(); } +void ShellBrowserMainParts::PostDestroyThreads() { +#if defined(OS_CHROMEOS) + device::BluetoothAdapterFactory::Shutdown(); + bluez::BluezDBusManager::Shutdown(); + chromeos::DBusThreadManager::Shutdown(); +#elif defined(OS_LINUX) + device::BluetoothAdapterFactory::Shutdown(); + bluez::DBusBluezManagerWrapperLinux::Shutdown(); +#endif +} + } // namespace
diff --git a/content/shell/browser/shell_browser_main_parts.h b/content/shell/browser/shell_browser_main_parts.h index c64d030..e506bff 100644 --- a/content/shell/browser/shell_browser_main_parts.h +++ b/content/shell/browser/shell_browser_main_parts.h
@@ -44,6 +44,7 @@ void PreMainMessageLoopRun() override; bool MainMessageLoopRun(int* result_code) override; void PostMainMessageLoopRun() override; + void PostDestroyThreads() override; devtools_http_handler::DevToolsHttpHandler* devtools_http_handler() { return devtools_http_handler_.get();
diff --git a/content/shell/browser/shell_views.cc b/content/shell/browser/shell_views.cc index 72aebc76..2e1e4ff 100644 --- a/content/shell/browser/shell_views.cc +++ b/content/shell/browser/shell_views.cc
@@ -15,7 +15,6 @@ #include "content/public/browser/web_contents.h" #include "content/public/common/context_menu_params.h" #include "content/shell/browser/shell_platform_data_aura.h" -#include "device/bluetooth/bluetooth_adapter_factory.h" #include "ui/aura/client/screen_position_client.h" #include "ui/aura/env.h" #include "ui/aura/window.h" @@ -41,8 +40,6 @@ #include "ui/views/widget/widget_delegate.h" #if defined(OS_CHROMEOS) -#include "chromeos/dbus/dbus_thread_manager.h" -#include "device/bluetooth/dbus/bluez_dbus_manager.h" #include "ui/aura/test/test_screen.h" #include "ui/wm/test/wm_test_helper.h" #else // !defined(OS_CHROMEOS) @@ -416,11 +413,6 @@ _setmode(_fileno(stderr), _O_BINARY); #endif #if defined(OS_CHROMEOS) - chromeos::DBusThreadManager::Initialize(); - bluez::BluezDBusManager::Initialize( - chromeos::DBusThreadManager::Get()->GetSystemBus(), - chromeos::DBusThreadManager::Get()->IsUsingStub( - chromeos::DBusClientBundle::BLUETOOTH)); test_screen_ = aura::TestScreen::Create(gfx::Size()); gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, test_screen_); wm_test_helper_ = new wm::WMTestHelper(default_window_size, @@ -444,11 +436,6 @@ views_delegate_ = NULL; delete platform_; platform_ = NULL; -#if defined(OS_CHROMEOS) - device::BluetoothAdapterFactory::Shutdown(); - bluez::BluezDBusManager::Shutdown(); - chromeos::DBusThreadManager::Shutdown(); -#endif aura::Env::DeleteInstance(); }
diff --git a/content/test/gpu/gpu_tests/memory_test.py b/content/test/gpu/gpu_tests/memory_test.py index d18b0cc0..b6c6870 100644 --- a/content/test/gpu/gpu_tests/memory_test.py +++ b/content/test/gpu/gpu_tests/memory_test.py
@@ -64,7 +64,7 @@ class MemoryValidator(gpu_test_base.ValidatorBase): def ValidateAndMeasurePage(self, page, tab, results): - timeline_data = tab.browser.platform.tracing_controller.Stop() + timeline_data = tab.browser.platform.tracing_controller.StopTracing() timeline_model = model.TimelineModel(timeline_data) for process in timeline_model.GetAllProcesses(): if 'gpu.GpuMemoryUsage' in process.counters: @@ -89,7 +89,7 @@ for c in ['webkit.console', 'blink.console', 'gpu']: config.tracing_category_filter.AddIncludedCategory(c) config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(config, 60) + tab.browser.platform.tracing_controller.StartTracing(config, 60) def _FormatException(self, low_or_high, mb_used): return 'Memory allocation too %s (was %d MB, should be %d MB +/- %d MB)' % (
diff --git a/content/test/gpu/gpu_tests/trace_test.py b/content/test/gpu/gpu_tests/trace_test.py index 421f03b0..19ba60aa 100644 --- a/content/test/gpu/gpu_tests/trace_test.py +++ b/content/test/gpu/gpu_tests/trace_test.py
@@ -44,7 +44,7 @@ raise NotImplementedError("GetCategoryName() Not implemented!") def ValidateAndMeasurePage(self, page, tab, results): - timeline_data = tab.browser.platform.tracing_controller.Stop() + timeline_data = tab.browser.platform.tracing_controller.StopTracing() timeline_model = model_module.TimelineModel(timeline_data) category_name = self.GetCategoryName() @@ -65,7 +65,7 @@ for cat in TOPLEVEL_CATEGORIES: config.tracing_category_filter.AddDisabledByDefault(cat) config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(config, 60) + tab.browser.platform.tracing_controller.StartTracing(config, 60) def _FormatException(self, category): return 'Trace markers for GPU category was not found: %s' % category
diff --git a/device/bluetooth/BUILD.gn b/device/bluetooth/BUILD.gn index 0abb9d4..d964a6a 100644 --- a/device/bluetooth/BUILD.gn +++ b/device/bluetooth/BUILD.gn
@@ -211,8 +211,6 @@ "dbus/bluez_dbus_client.h", "dbus/bluez_dbus_manager.cc", "dbus/bluez_dbus_manager.h", - "dbus/dbus_thread_manager_linux.cc", - "dbus/dbus_thread_manager_linux.h", "dbus/fake_bluetooth_adapter_client.cc", "dbus/fake_bluetooth_adapter_client.h", "dbus/fake_bluetooth_agent_manager_client.cc", @@ -252,10 +250,23 @@ "dbus/fake_bluetooth_profile_service_provider.cc", "dbus/fake_bluetooth_profile_service_provider.h", ] - + if (is_linux) { + sources += [ + "dbus/dbus_bluez_manager_wrapper_linux.cc", + "dbus/dbus_bluez_manager_wrapper_linux.h", + "dbus/dbus_thread_manager_linux.cc", + "dbus/dbus_thread_manager_linux.h", + ] + } deps += [ "//dbus" ] } else { # !use_dbus sources += [ "bluetooth_adapter_stub.cc" ] + if (is_linux) { + sources += [ + "dbus/dbus_bluez_manager_wrapper_linux.h", + "dbus/dbus_bluez_manager_wrapper_stub_linux.cc", + ] + } } } }
diff --git a/device/bluetooth/bluetooth.gyp b/device/bluetooth/bluetooth.gyp index b7fec2c..1cbf220 100644 --- a/device/bluetooth/bluetooth.gyp +++ b/device/bluetooth/bluetooth.gyp
@@ -187,8 +187,6 @@ 'dbus/bluez_dbus_client.h', 'dbus/bluez_dbus_manager.cc', 'dbus/bluez_dbus_manager.h', - 'dbus/dbus_thread_manager_linux.cc', - 'dbus/dbus_thread_manager_linux.h', 'dbus/fake_bluetooth_adapter_client.cc', 'dbus/fake_bluetooth_adapter_client.h', 'dbus/fake_bluetooth_le_advertising_manager_client.cc', @@ -228,6 +226,16 @@ 'dbus/fake_bluetooth_profile_service_provider.cc', 'dbus/fake_bluetooth_profile_service_provider.h', ], + 'conditions': [ + ['OS=="linux"', { + 'sources': [ + 'dbus/dbus_bluez_manager_wrapper_linux.cc', + 'dbus/dbus_bluez_manager_wrapper_linux.h', + 'dbus/dbus_thread_manager_linux.cc', + 'dbus/dbus_thread_manager_linux.h', + ] + }] + ], 'dependencies': [ '../../build/linux/system.gyp:dbus', '../../dbus/dbus.gyp:dbus', @@ -236,7 +244,15 @@ '../../build/linux/system.gyp:dbus' ] }, { # !use_dbus - 'sources': [ 'bluetooth_adapter_stub.cc' ] + 'sources': [ 'bluetooth_adapter_stub.cc' ], + 'conditions': [ + ['OS=="linux"', { + 'sources': [ + 'dbus/dbus_bluez_manager_wrapper_linux.h', + 'dbus/dbus_bluez_manager_wrapper_stub_linux.cc', + ] + }], + ] }], ], }],
diff --git a/device/bluetooth/bluetooth_adapter_bluez.cc b/device/bluetooth/bluetooth_adapter_bluez.cc index 0997dd9..4b50cd72 100644 --- a/device/bluetooth/bluetooth_adapter_bluez.cc +++ b/device/bluetooth/bluetooth_adapter_bluez.cc
@@ -938,6 +938,7 @@ BluetoothDeviceBlueZ* device) { DCHECK(device->adapter_ == this); + device->SetGattServicesDiscoveryComplete(true); FOR_EACH_OBSERVER(BluetoothAdapter::Observer, observers_, GattServicesDiscovered(this, device)); }
diff --git a/device/bluetooth/bluetooth_adapter_factory.cc b/device/bluetooth/bluetooth_adapter_factory.cc index fc2af86f..2bcfbe90 100644 --- a/device/bluetooth/bluetooth_adapter_factory.cc +++ b/device/bluetooth/bluetooth_adapter_factory.cc
@@ -59,9 +59,8 @@ // instance even on platforms that would otherwise not support it. if (default_adapter.Get()) return true; -// Even though the adapter is available on Linux, we only want to use it for -// the Chrome API, which is why defines(OS_LINUX) is missing from here. -#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN) +#if defined(OS_ANDROID) || defined(OS_CHROMEOS) || defined(OS_WIN) || \ + defined(OS_LINUX) return true; #elif defined(OS_MACOSX) return base::mac::IsOSLionOrLater(); @@ -72,12 +71,7 @@ // static void BluetoothAdapterFactory::GetAdapter(const AdapterCallback& callback) { -// TODO(rkc): This is a very slight hack to allow us to be able to create -// an adapter on Linux, 'without' exposing the adapter to all Bluetooth -// services within the browser. -#if !defined(OS_LINUX) DCHECK(IsBluetoothAdapterAvailable()); -#endif #if defined(OS_WIN) if (!default_adapter.Get()) {
diff --git a/device/bluetooth/bluetooth_advertisement_bluez_unittest.cc b/device/bluetooth/bluetooth_advertisement_bluez_unittest.cc index ea933fc..27b2c8f 100644 --- a/device/bluetooth/bluetooth_advertisement_bluez_unittest.cc +++ b/device/bluetooth/bluetooth_advertisement_bluez_unittest.cc
@@ -53,7 +53,8 @@ class BluetoothAdvertisementBlueZTest : public testing::Test { public: void SetUp() override { - bluez::BluezDBusManager::Initialize(NULL, true); + bluez::BluezDBusManager::Initialize(nullptr /* bus */, + true /* use_dbus_stub */); callback_count_ = 0; error_callback_count_ = 0;
diff --git a/device/bluetooth/bluetooth_audio_sink_bluez_unittest.cc b/device/bluetooth/bluetooth_audio_sink_bluez_unittest.cc index 6b6e3aa..25b53d5 100644 --- a/device/bluetooth/bluetooth_audio_sink_bluez_unittest.cc +++ b/device/bluetooth/bluetooth_audio_sink_bluez_unittest.cc
@@ -85,7 +85,8 @@ class BluetoothAudioSinkBlueZTest : public testing::Test { public: void SetUp() override { - bluez::BluezDBusManager::Initialize(NULL, true); + bluez::BluezDBusManager::Initialize(nullptr /* bus */, + true /* use_dbus_stub */); callback_count_ = 0; error_callback_count_ = 0;
diff --git a/device/bluetooth/bluetooth_device.cc b/device/bluetooth/bluetooth_device.cc index e666aa5..05532cc 100644 --- a/device/bluetooth/bluetooth_device.cc +++ b/device/bluetooth/bluetooth_device.cc
@@ -19,7 +19,9 @@ namespace device { BluetoothDevice::BluetoothDevice(BluetoothAdapter* adapter) - : adapter_(adapter), services_data_(new base::DictionaryValue()) {} + : adapter_(adapter), + gatt_services_discovery_complete_(false), + services_data_(new base::DictionaryValue()) {} BluetoothDevice::~BluetoothDevice() { DidDisconnectGatt(); @@ -214,6 +216,14 @@ CreateGattConnectionImpl(); } +void BluetoothDevice::SetGattServicesDiscoveryComplete(bool complete) { + gatt_services_discovery_complete_ = complete; +} + +bool BluetoothDevice::IsGattServicesDiscoveryComplete() const { + return gatt_services_discovery_complete_; +} + std::vector<BluetoothGattService*> BluetoothDevice::GetGattServices() const { std::vector<BluetoothGattService*> services;
diff --git a/device/bluetooth/bluetooth_device.h b/device/bluetooth/bluetooth_device.h index 845c89a..17c5fdab 100644 --- a/device/bluetooth/bluetooth_device.h +++ b/device/bluetooth/bluetooth_device.h
@@ -432,6 +432,12 @@ virtual void CreateGattConnection(const GattConnectionCallback& callback, const ConnectErrorCallback& error_callback); + // Set the gatt services discovery complete flag for this device. + void SetGattServicesDiscoveryComplete(bool complete); + + // Indicates whether service discovery is complete for this device. + bool IsGattServicesDiscoveryComplete() const; + // Returns the list of discovered GATT services. virtual std::vector<BluetoothGattService*> GetGattServices() const; @@ -462,6 +468,8 @@ BluetoothGattConnection_DisconnectGatt_SimulateDisconnect); FRIEND_TEST_ALL_PREFIXES(BluetoothTest, BluetoothGattConnection_ErrorAfterConnection); + FRIEND_TEST_ALL_PREFIXES(BluetoothTest, + BluetoothGattConnection_DisconnectGatt_Cleanup); BluetoothDevice(BluetoothAdapter* adapter); @@ -519,6 +527,7 @@ typedef base::ScopedPtrHashMap<std::string, scoped_ptr<BluetoothGattService>> GattServiceMap; GattServiceMap gatt_services_; + bool gatt_services_discovery_complete_; // Mapping from service UUID represented as a std::string of a bluetooth // service to
diff --git a/device/bluetooth/bluetooth_device_android.cc b/device/bluetooth/bluetooth_device_android.cc index 71e4d057..71ceb666 100644 --- a/device/bluetooth/bluetooth_device_android.cc +++ b/device/bluetooth/bluetooth_device_android.cc
@@ -210,6 +210,9 @@ if (gatt_connected_) { DidConnectGatt(); } else { + gatt_services_.clear(); + SetGattServicesDiscoveryComplete(false); + switch (status) { // Constants are from android.bluetooth.BluetoothGatt. case 0x0000008f: // GATT_CONNECTION_CONGESTED return DidFailToConnectGatt(ERROR_CONNECTION_CONGESTED); @@ -241,6 +244,7 @@ void BluetoothDeviceAndroid::OnGattServicesDiscovered( JNIEnv* env, const JavaParamRef<jobject>& jcaller) { + SetGattServicesDiscoveryComplete(true); FOR_EACH_OBSERVER(BluetoothAdapter::Observer, GetAdapter()->GetObservers(), GattServicesDiscovered(GetAdapter(), this)); }
diff --git a/device/bluetooth/bluetooth_device_unittest.cc b/device/bluetooth/bluetooth_device_unittest.cc index f395764..69410b5 100644 --- a/device/bluetooth/bluetooth_device_unittest.cc +++ b/device/bluetooth/bluetooth_device_unittest.cc
@@ -395,6 +395,55 @@ #endif // defined(OS_ANDROID) #if defined(OS_ANDROID) +// Calls CreateGattConnection & DisconnectGatt, then checks that gatt services +// have been cleaned up. +TEST_F(BluetoothTest, BluetoothGattConnection_DisconnectGatt_Cleanup) { + InitWithFakeAdapter(); + StartLowEnergyDiscoverySession(); + BluetoothDevice* device = DiscoverLowEnergyDevice(3); + EXPECT_FALSE(device->IsConnected()); + + // Connect to the device + ResetEventCounts(); + device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED), + GetConnectErrorCallback(Call::NOT_EXPECTED)); + TestBluetoothAdapterObserver observer(adapter_); + SimulateGattConnection(device); + EXPECT_TRUE(device->IsConnected()); + + // Discover services + std::vector<std::string> services; + services.push_back("00000000-0000-1000-8000-00805f9b34fb"); + services.push_back("00000001-0000-1000-8000-00805f9b34fb"); + SimulateGattServicesDiscovered(device, services); + EXPECT_TRUE(device->IsGattServicesDiscoveryComplete()); + EXPECT_EQ(2u, device->GetGattServices().size()); + EXPECT_EQ(1, observer.gatt_services_discovered_count()); + + // Disconnect from the device + device->DisconnectGatt(); + SimulateGattDisconnection(device); + EXPECT_FALSE(device->IsConnected()); + EXPECT_FALSE(device->IsGattServicesDiscoveryComplete()); + EXPECT_EQ(0u, device->GetGattServices().size()); + + // Verify that the device can be connected to again + device->CreateGattConnection(GetGattConnectionCallback(Call::EXPECTED), + GetConnectErrorCallback(Call::NOT_EXPECTED)); + SimulateGattConnection(device); + EXPECT_TRUE(device->IsConnected()); + + // Verify that service discovery can be done again + std::vector<std::string> services2; + services2.push_back("00000002-0000-1000-8000-00805f9b34fb"); + SimulateGattServicesDiscovered(device, services2); + EXPECT_TRUE(device->IsGattServicesDiscoveryComplete()); + EXPECT_EQ(1u, device->GetGattServices().size()); + EXPECT_EQ(2, observer.gatt_services_discovered_count()); +} +#endif // defined(OS_ANDROID) + +#if defined(OS_ANDROID) // Calls CreateGattConnection, but simulate errors connecting. Also, verifies // multiple errors should only invoke callbacks once. TEST_F(BluetoothTest, BluetoothGattConnection_ErrorAfterConnection) {
diff --git a/device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.cc b/device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.cc new file mode 100644 index 0000000..5b8b573 --- /dev/null +++ b/device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.cc
@@ -0,0 +1,26 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h" + +#include "device/bluetooth/dbus/bluez_dbus_manager.h" +#include "device/bluetooth/dbus/dbus_thread_manager_linux.h" + +namespace bluez { + +// static +void DBusBluezManagerWrapperLinux::Initialize() { + DBusThreadManagerLinux::Initialize(); + BluezDBusManager::Initialize( + bluez::DBusThreadManagerLinux::Get()->GetSystemBus(), + false /* use_dbus_stub */); +} + +// static +void DBusBluezManagerWrapperLinux::Shutdown() { + bluez::BluezDBusManager::Shutdown(); + bluez::DBusThreadManagerLinux::Shutdown(); +} + +} // namespace bluez
diff --git a/device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h b/device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h new file mode 100644 index 0000000..ccd96232 --- /dev/null +++ b/device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h
@@ -0,0 +1,27 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef DEVICE_BLUETOOTH_DBUS_DBUS_BLUEZ_MANAGER_WRAPPER_LINUX_H_ +#define DEVICE_BLUETOOTH_DBUS_DBUS_BLUEZ_MANAGER_WRAPPER_LINUX_H_ + +#include "base/macros.h" +#include "device/bluetooth/bluetooth_export.h" + +namespace bluez { + +// This class abstracts the initialization of DBusThreadManagerLinux and +// BluezDBusManager. Targets that don't use DBus can provide stub +// implementations. +class DEVICE_BLUETOOTH_EXPORT DBusBluezManagerWrapperLinux { + public: + static void Initialize(); + static void Shutdown(); + + private: + DISALLOW_IMPLICIT_CONSTRUCTORS(DBusBluezManagerWrapperLinux); +}; + +} // namespace bluez + +#endif // DEVICE_BLUETOOTH_DBUS_DBUS_BLUEZ_MANAGER_WRAPPER_LINUX_H_
diff --git a/device/bluetooth/dbus/dbus_bluez_manager_wrapper_stub_linux.cc b/device/bluetooth/dbus/dbus_bluez_manager_wrapper_stub_linux.cc new file mode 100644 index 0000000..18c2bfe --- /dev/null +++ b/device/bluetooth/dbus/dbus_bluez_manager_wrapper_stub_linux.cc
@@ -0,0 +1,17 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h" + +namespace bluez { + +// Stub implementation for targets that don't use DBus. +// static +void DBusBluezManagerWrapperLinux::Initialize() {} + +// Stub implementation for targets that don't use DBus. +// static +void DBusBluezManagerWrapperLinux::Shutdown() {} + +} // namespace bluez
diff --git a/docs/clang_tool_refactoring.md b/docs/clang_tool_refactoring.md index 6d0409b..3d9c9ed 100644 --- a/docs/clang_tool_refactoring.md +++ b/docs/clang_tool_refactoring.md
@@ -39,16 +39,15 @@ Chromium clang tools generally follow this pattern: -1. Instantiate a [`clang::ast_matchers::MatchFinder`]( - http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder.html). -2. Call `addMatcher()` to register [`clang::ast_matchers::MatchFinder::MatchCallback`]( - http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder_1_1MatchCallback.html) actions to execute when [matching](http://clang.llvm.org/docs/LibASTMatchersReference.html) the AST. +1. Instantiate a [`clang::ast_matchers::MatchFinder`](http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder.html). +2. Call `addMatcher()` to register [`clang::ast_matchers::MatchFinder::MatchCallback`](http://clang.llvm.org/doxygen/classclang_1_1ast__matchers_1_1MatchFinder_1_1MatchCallback.html) + actions to execute when [matching](http://clang.llvm.org/docs/LibASTMatchersReference.html) + the AST. 3. Create a new `clang::tooling::FrontendActionFactory` from the `MatchFinder`. 4. Run the action across the specified files with [`clang::tooling::ClangTool::run`](http://clang.llvm.org/doxygen/classclang_1_1tooling_1_1ClangTool.html#acec91f63b45ac7ee2d6c94cb9c10dab3). -5. Serialize generated [`clang::tooling::Replacement`]( - http://clang.llvm.org/doxygen/classclang_1_1tooling_1_1Replacement.html)s to - `stdout`. +5. Serialize generated [`clang::tooling::Replacement`](http://clang.llvm.org/doxygen/classclang_1_1tooling_1_1Replacement.html)s + to `stdout`. Other useful references when writing the tool: @@ -85,10 +84,9 @@ expansion loc, etc. ### Why not RefactoringTool? -While clang has a [`clang::tooling::RefactoringTool`]( -http://clang.llvm.org/doxygen/classclang_1_1tooling_1_1RefactoringTool.html) to -automatically apply the generated replacements and save the results, it doesn't -work well for Chromium: +While clang has a [`clang::tooling::RefactoringTool`](http://clang.llvm.org/doxygen/classclang_1_1tooling_1_1RefactoringTool.html) +to automatically apply the generated replacements and save the results, it +doesn't work well for Chromium: * Clang tools run actions serially, so runtime scales poorly to tens of thousands of files. @@ -97,10 +95,12 @@ ## Building Synopsis: + ```shell tools/clang/scripts/update.py --force-local-build --without-android \ --tools blink_gc_plugin plugins rewrite_to_chrome_style ``` + Running this command builds the [Oilpan plugin](https://chromium.googlesource.com/chromium/src/+/master/tools/clang/blink_gc_plugin/), the [Chrome style plugin](https://chromium.googlesource.com/chromium/src/+/master/tools/clang/plugins/), @@ -112,12 +112,14 @@ ## Running First, build all chromium targets to avoid failures due to missing dependecies that are generated as part of the build: + ```shell ninja -C out/Debug ``` Then run the actual tool: -``` + +```shell tools/clang/scripts/run_tool.py <toolname> \ --generate-compdb out/Debug <path 1> <path 2> ... @@ -139,28 +141,33 @@ ## Debugging Dumping the AST for a file: + ```shell clang++ -cc1 -ast-dump foo.cc ``` Using `clang-query` to dynamically test matchers (requires checking out and building [clang-tools-extras](https://github.com/llvm-mirror/clang-tools-extra)): + ```shell clang-query -p path/to/compdb base/memory/ref_counted.cc ``` `printf` debugging: + ```c++ clang::Decl* decl = result.Nodes.getNodeAs<clang::Decl>("decl"); decl->dumpColor(); clang::Stmt* stmt = result.Nodes.getNodeAs<clang::Stmt>("stmt"); stmt->dumpColor(); ``` + By default, the script hides the output of the tool. The easiest way to change that is to `return 1` from the `main()` function of the clang tool. ## Testing Synposis: + ```shell test_tool.py <tool name> ```
diff --git a/extensions/browser/api/bluetooth/bluetooth_event_router.cc b/extensions/browser/api/bluetooth/bluetooth_event_router.cc index 32606fab..d11d17e 100644 --- a/extensions/browser/api/bluetooth/bluetooth_event_router.cc +++ b/extensions/browser/api/bluetooth/bluetooth_event_router.cc
@@ -73,9 +73,6 @@ } bool BluetoothEventRouter::IsBluetoothSupported() const { -#if defined(OS_LINUX) - return true; -#endif return adapter_.get() || device::BluetoothAdapterFactory::IsBluetoothAdapterAvailable(); }
diff --git a/extensions/browser/extension_prefs.cc b/extensions/browser/extension_prefs.cc index 6f584d0..839f6ff 100644 --- a/extensions/browser/extension_prefs.cc +++ b/extensions/browser/extension_prefs.cc
@@ -81,10 +81,6 @@ // run of this profile. const char kPrefExternalInstallFirstRun[] = "external_first_run"; -// DO NOT USE, use kPrefDisableReasons instead. -// Indicates whether the extension was updated while it was disabled. -const char kDeprecatedPrefDisableReason[] = "disable_reason"; - // A bitmask of all the reasons an extension is disabled. const char kPrefDisableReasons[] = "disable_reasons"; @@ -998,33 +994,6 @@ } } -void ExtensionPrefs::MigrateDisableReasons( - const ExtensionIdList& extension_ids) { - for (ExtensionIdList::const_iterator ext_id = - extension_ids.begin(); ext_id != extension_ids.end(); ++ext_id) { - int value = -1; - if (ReadPrefAsInteger(*ext_id, kDeprecatedPrefDisableReason, &value)) { - int new_value = Extension::DISABLE_NONE; - switch (value) { - case Extension::DEPRECATED_DISABLE_USER_ACTION: - new_value = Extension::DISABLE_USER_ACTION; - break; - case Extension::DEPRECATED_DISABLE_PERMISSIONS_INCREASE: - new_value = Extension::DISABLE_PERMISSIONS_INCREASE; - break; - case Extension::DEPRECATED_DISABLE_RELOAD: - new_value = Extension::DISABLE_RELOAD; - break; - } - - UpdateExtensionPref(*ext_id, kPrefDisableReasons, - new base::FundamentalValue(new_value)); - // Remove the old disable reason. - UpdateExtensionPref(*ext_id, kDeprecatedPrefDisableReason, NULL); - } - } -} - scoped_ptr<const PermissionSet> ExtensionPrefs::GetGrantedPermissions( const std::string& extension_id) const { CHECK(crx_file::id_util::IdIsValid(extension_id)); @@ -1739,7 +1708,6 @@ FixMissingPrefs(extension_ids); MigratePermissions(extension_ids); - MigrateDisableReasons(extension_ids); InitExtensionControlledPrefs(extension_pref_value_map_);
diff --git a/extensions/browser/extension_prefs.h b/extensions/browser/extension_prefs.h index f86b02e..13bff1e 100644 --- a/extensions/browser/extension_prefs.h +++ b/extensions/browser/extension_prefs.h
@@ -633,9 +633,6 @@ // Migrates the permissions data in the pref store. void MigratePermissions(const ExtensionIdList& extension_ids); - // Migrates the disable reasons from a single enum to a bit mask. - void MigrateDisableReasons(const ExtensionIdList& extension_ids); - // Checks whether there is a state pref for the extension and if so, whether // it matches |check_state|. bool DoesExtensionHaveState(const std::string& id,
diff --git a/extensions/common/extension.h b/extensions/common/extension.h index ec71517d..25035ee 100644 --- a/extensions/common/extension.h +++ b/extensions/common/extension.h
@@ -73,15 +73,6 @@ NUM_STATES }; - // Used to record the reason an extension was disabled. - enum DeprecatedDisableReason { - DEPRECATED_DISABLE_UNKNOWN, - DEPRECATED_DISABLE_USER_ACTION, - DEPRECATED_DISABLE_PERMISSIONS_INCREASE, - DEPRECATED_DISABLE_RELOAD, - DEPRECATED_DISABLE_LAST, // Not used. - }; - // Reasons an extension may be disabled. These are used in histograms, so do // not remove/reorder entries - only add at the end just before // DISABLE_REASON_LAST (and update the shift value for it). Also remember to
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder.cc b/gpu/command_buffer/service/gles2_cmd_decoder.cc index 9538614..5bf0492 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder.cc
@@ -1983,6 +1983,8 @@ // Backbuffer attachments that are currently undefined. uint32_t backbuffer_needs_clear_bits_; + uint64_t swaps_since_resize_; + // The current decoder error communicates the decoder error through command // processing functions that do not return the error value. Should be set only // if not returning an error. @@ -2533,6 +2535,7 @@ back_buffer_draw_buffer_(GL_BACK), surfaceless_(false), backbuffer_needs_clear_bits_(0), + swaps_since_resize_(0), current_decoder_error_(error::kNoError), validators_(group_->feature_info()->validators()), feature_info_(group_->feature_info()), @@ -3655,8 +3658,7 @@ if (surfaceless_) return false; if (backbuffer_needs_clear_bits_) { - glClearColor(0, 0, 0, (GLES2Util::GetChannelsForFormat( - offscreen_target_color_format_) & 0x0008) != 0 ? 0 : 1.f); + glClearColor(0, 0, 0, BackBufferHasAlpha() ? 0 : 1.f); state_.SetDeviceColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glClearStencil(0); state_.SetDeviceStencilMaskSeparate(GL_FRONT, kDefaultStencilMask); @@ -4351,8 +4353,13 @@ << "current after resize callback."; return error::kLostContext; } + if (surface_->BuffersFlipped()) { + backbuffer_needs_clear_bits_ |= GL_COLOR_BUFFER_BIT; + } } + swaps_since_resize_ = 0; + return error::kNoError; } @@ -12231,6 +12238,12 @@ group_->LoseContexts(error::kUnknown); } } + ++swaps_since_resize_; + if (swaps_since_resize_ == 1 && surface_->BuffersFlipped()) { + // The second buffer after a resize is new and needs to be cleared to + // known values. + backbuffer_needs_clear_bits_ |= GL_COLOR_BUFFER_BIT; + } } void GLES2DecoderImpl::DoCommitOverlayPlanes() {
diff --git a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc index ec0234df..634cd2d 100644 --- a/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc +++ b/gpu/command_buffer/service/gles2_cmd_decoder_unittest_framebuffers.cc
@@ -35,6 +35,7 @@ using ::gfx::MockGLInterface; using ::testing::_; +using ::testing::AnyNumber; using ::testing::DoAll; using ::testing::InSequence; using ::testing::Invoke; @@ -2927,6 +2928,41 @@ gfx::MockGLInterface::GetGLProcAddress("glDiscardFramebufferEXT")); } +TEST_P(GLES2DecoderTest, ClearBackbufferBitsOnFlipSwap) { + surface_->set_buffers_flipped(true); + + EXPECT_EQ(0u, GetAndClearBackbufferClearBitsForTest()); + + SwapBuffers& cmd = *GetImmediateAs<SwapBuffers>(); + cmd.Init(); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(static_cast<uint32_t>(GL_COLOR_BUFFER_BIT), + GetAndClearBackbufferClearBitsForTest()); + + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(0u, GetAndClearBackbufferClearBitsForTest()); + + EXPECT_CALL(*gl_, Finish()).Times(AnyNumber()); + ResizeCHROMIUM& resize_cmd = *GetImmediateAs<ResizeCHROMIUM>(); + resize_cmd.Init(1, 1, 1.0f, GL_TRUE); + EXPECT_EQ(error::kNoError, ExecuteCmd(resize_cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(static_cast<uint32_t>(GL_COLOR_BUFFER_BIT), + GetAndClearBackbufferClearBitsForTest()); + + cmd.Init(); + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(static_cast<uint32_t>(GL_COLOR_BUFFER_BIT), + GetAndClearBackbufferClearBitsForTest()); + + EXPECT_EQ(error::kNoError, ExecuteCmd(cmd)); + EXPECT_EQ(GL_NO_ERROR, GetGLError()); + EXPECT_EQ(0u, GetAndClearBackbufferClearBitsForTest()); +} + TEST_P(GLES2DecoderManualInitTest, DiscardFramebufferEXT) { InitState init; init.extensions = "GL_EXT_discard_framebuffer";
diff --git a/ios/web/public/web_state/ui/crw_web_delegate.h b/ios/web/public/web_state/ui/crw_web_delegate.h index a5821b3..5bf73c79 100644 --- a/ios/web/public/web_state/ui/crw_web_delegate.h +++ b/ios/web/public/web_state/ui/crw_web_delegate.h
@@ -71,9 +71,7 @@ // Called when the page wants to open a new window by DOM. // CRWSessionController's openedByDOM property of the returned CRWWebController // must be YES. -- (CRWWebController*)webPageOrderedOpenBlankWithReferrer: - (const web::Referrer&)referrer - inBackground:(BOOL)inBackground; +- (CRWWebController*)webPageOrderedOpen; // Called when the page calls window.close() on itself. Begin the shut-down // sequence for this controller.
diff --git a/ios/web/shell/view_controller.mm b/ios/web/shell/view_controller.mm index f7bc351..c01c23f 100644 --- a/ios/web/shell/view_controller.mm +++ b/ios/web/shell/view_controller.mm
@@ -286,9 +286,7 @@ return nil; } -- (CRWWebController*)webPageOrderedOpenBlankWithReferrer: - (const web::Referrer&)referrer - inBackground:(BOOL)inBackground { +- (CRWWebController*)webPageOrderedOpen { return nil; }
diff --git a/ios/web/web_state/ui/crw_web_controller+protected.h b/ios/web/web_state/ui/crw_web_controller+protected.h index 7261210e4..bc773355c 100644 --- a/ios/web/web_state/ui/crw_web_controller+protected.h +++ b/ios/web/web_state/ui/crw_web_controller+protected.h
@@ -342,8 +342,7 @@ // Creates a new opened by DOM window and returns its autoreleased web // controller. -- (CRWWebController*)createChildWebControllerWithReferrerURL: - (const GURL&)referrerURL; +- (CRWWebController*)createChildWebController; // Called following navigation completion to generate final navigation lifecycle // events. Navigation is considered complete when the document has finished
diff --git a/ios/web/web_state/ui/crw_web_controller.mm b/ios/web/web_state/ui/crw_web_controller.mm index 18aaf16..2a4fb13 100644 --- a/ios/web/web_state/ui/crw_web_controller.mm +++ b/ios/web/web_state/ui/crw_web_controller.mm
@@ -1194,12 +1194,8 @@ [self.containerView displayWebViewContentView:webViewContentView]; } -- (CRWWebController*)createChildWebControllerWithReferrerURL: - (const GURL&)referrerURL { - web::Referrer referrer(referrerURL, web::ReferrerPolicyDefault); - CRWWebController* result = - [self.delegate webPageOrderedOpenBlankWithReferrer:referrer - inBackground:NO]; +- (CRWWebController*)createChildWebController { + CRWWebController* result = [self.delegate webPageOrderedOpen]; DCHECK(!result || result.sessionController.openedByDOM); return result; } @@ -2815,9 +2811,9 @@ return NO; } - // Abort load if navigation is believed to be happening on the main frame. + // Stop load if navigation is believed to be happening on the main frame. if ([self isPutativeMainFrameRequest:request targetFrame:targetFrame]) - [self abortLoad]; + [self stopLoading]; if ([_delegate openExternalURL:requestURL]) { // Record the URL so that errors reported following the 'NO' reply can be
diff --git a/ios/web/web_state/ui/crw_web_controller_unittest.mm b/ios/web/web_state/ui/crw_web_controller_unittest.mm index c97ebe1..ab1d48b 100644 --- a/ios/web/web_state/ui/crw_web_controller_unittest.mm +++ b/ios/web/web_state/ui/crw_web_controller_unittest.mm
@@ -119,7 +119,7 @@ @synthesize recoverable = _recoverable; @synthesize shouldContinueCallback = _shouldContinueCallback; -typedef void (^webPageOrderedOpenBlankBlockType)(const web::Referrer&, BOOL); +typedef void (^webPageOrderedOpenBlankBlockType)(); typedef void (^webPageOrderedOpenBlockType)(const GURL&, const web::Referrer&, NSString*, @@ -133,11 +133,8 @@ return self; } -- (CRWWebController*)webPageOrderedOpenBlankWithReferrer: - (const web::Referrer&)referrer - inBackground:(BOOL)inBackground { - static_cast<webPageOrderedOpenBlankBlockType>([self blockForSelector:_cmd])( - referrer, inBackground); +- (CRWWebController*)webPageOrderedOpen { + static_cast<webPageOrderedOpenBlankBlockType>([self blockForSelector:_cmd])(); return _childWebController; } @@ -1436,12 +1433,9 @@ TEST_F(CRWWKWebControllerWindowOpenTest, OpenWithUserGesture) { CR_TEST_REQUIRES_WK_WEB_VIEW(); - SEL selector = @selector(webPageOrderedOpenBlankWithReferrer:inBackground:); + SEL selector = @selector(webPageOrderedOpen); [delegate_ onSelector:selector - callBlockExpectation:^(const web::Referrer& referrer, - BOOL in_background) { - EXPECT_EQ("", referrer.url.spec()); - EXPECT_FALSE(in_background); + callBlockExpectation:^(){ }]; [webController_ touched:YES]; @@ -1485,12 +1479,9 @@ CR_TEST_REQUIRES_WK_WEB_VIEW(); [delegate_ setBlockPopups:NO]; - SEL selector = @selector(webPageOrderedOpenBlankWithReferrer:inBackground:); + SEL selector = @selector(webPageOrderedOpen); [delegate_ onSelector:selector - callBlockExpectation:^(const web::Referrer& referrer, - BOOL in_background) { - EXPECT_EQ("", referrer.url.spec()); - EXPECT_FALSE(in_background); + callBlockExpectation:^(){ }]; EXPECT_NSEQ(@"[object Window]", OpenWindowByDOM());
diff --git a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm index 5cedc12..5cebd46b 100644 --- a/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm +++ b/ios/web/web_state/ui/crw_wk_web_view_web_controller.mm
@@ -470,6 +470,7 @@ - (void)stopLoading { _stoppedWKNavigation.reset(_latestWKNavigation); + [super stopLoading]; } #pragma mark - @@ -1971,19 +1972,20 @@ forNavigationAction:(WKNavigationAction*)navigationAction windowFeatures:(WKWindowFeatures*)windowFeatures { GURL requestURL = net::GURLWithNSURL(navigationAction.request.URL); - NSString* referer = GetRefererFromNavigationAction(navigationAction); - GURL referrerURL = referer ? GURL(base::SysNSStringToUTF8(referer)) : - [self currentURL]; - if (![self userIsInteracting] && - [self shouldBlockPopupWithURL:requestURL sourceURL:referrerURL]) { - [self didBlockPopupWithURL:requestURL sourceURL:referrerURL]; - // Desktop Chrome does not return a window for the blocked popups; - // follow the same approach by returning nil; - return nil; + if (![self userIsInteracting]) { + NSString* referer = GetRefererFromNavigationAction(navigationAction); + GURL referrerURL = + referer ? GURL(base::SysNSStringToUTF8(referer)) : [self currentURL]; + if ([self shouldBlockPopupWithURL:requestURL sourceURL:referrerURL]) { + [self didBlockPopupWithURL:requestURL sourceURL:referrerURL]; + // Desktop Chrome does not return a window for the blocked popups; + // follow the same approach by returning nil; + return nil; + } } - id child = [self createChildWebControllerWithReferrerURL:referrerURL]; + id child = [self createChildWebController]; // WKWebView requires WKUIDelegate to return a child view created with // exactly the same |configuration| object (exception is raised if config is // different). |configuration| param and config returned by
diff --git a/ipc/unix_domain_socket_util.cc b/ipc/unix_domain_socket_util.cc index fb64cb2..a21df2f 100644 --- a/ipc/unix_domain_socket_util.cc +++ b/ipc/unix_domain_socket_util.cc
@@ -5,7 +5,6 @@ #include "ipc/unix_domain_socket_util.h" #include <errno.h> -#include <fcntl.h> #include <stddef.h> #include <sys/socket.h> #include <sys/stat.h> @@ -55,8 +54,8 @@ } // Make socket non-blocking - if (HANDLE_EINTR(fcntl(fd.get(), F_SETFL, O_NONBLOCK)) < 0) { - PLOG(ERROR) << "fcntl(O_NONBLOCK)"; + if (!base::SetNonBlocking(fd.get())) { + PLOG(ERROR) << "base::SetNonBlocking() failed " << fd.get(); return -1; } @@ -189,8 +188,8 @@ base::ScopedFD accept_fd(HANDLE_EINTR(accept(server_listen_fd, NULL, 0))); if (!accept_fd.is_valid()) return IsRecoverableError(errno); - if (HANDLE_EINTR(fcntl(accept_fd.get(), F_SETFL, O_NONBLOCK)) < 0) { - PLOG(ERROR) << "fcntl(O_NONBLOCK) " << accept_fd.get(); + if (!base::SetNonBlocking(accept_fd.get())) { + PLOG(ERROR) << "base::SetNonBlocking() failed " << accept_fd.get(); // It's safe to keep listening on |server_listen_fd| even if the attempt to // set O_NONBLOCK failed on the client fd. return true;
diff --git a/media/base/video_frame.cc b/media/base/video_frame.cc index aad4969..0ad4ac0f 100644 --- a/media/base/video_frame.cc +++ b/media/base/video_frame.cc
@@ -47,6 +47,35 @@ visible_rect.ToString().c_str(), natural_size.ToString().c_str()); } +static std::string StorageTypeToString( + const VideoFrame::StorageType storage_type) { + switch (storage_type) { + case VideoFrame::STORAGE_UNKNOWN: + return "UNKNOWN"; + case VideoFrame::STORAGE_OPAQUE: + return "OPAQUE"; + case VideoFrame::STORAGE_UNOWNED_MEMORY: + return "UNOWNED_MEMORY"; + case VideoFrame::STORAGE_OWNED_MEMORY: + return "OWNED_MEMORY"; + case VideoFrame::STORAGE_SHMEM: + return "SHMEM"; +#if defined(OS_LINUX) + case VideoFrame::STORAGE_DMABUFS: + return "DMABUFS"; +#endif +#if defined(VIDEO_HOLE) + case VideoFrame::STORAGE_HOLE: + return "HOLE"; +#endif + case VideoFrame::STORAGE_GPU_MEMORY_BUFFERS: + return "GPU_MEMORY_BUFFERS"; + } + + NOTREACHED() << "Invalid StorageType provided: " << storage_type; + return "INVALID"; +} + // Returns true if |plane| is a valid plane index for the given |format|. static bool IsValidPlane(size_t plane, VideoPixelFormat format) { DCHECK_LE(VideoFrame::NumPlanes(format), @@ -826,6 +855,20 @@ client->GenerateSyncToken(&release_sync_token_); } +std::string VideoFrame::AsHumanReadableString() { + if (metadata()->IsTrue(media::VideoFrameMetadata::END_OF_STREAM)) + return "end of stream"; + + std::ostringstream s; + s << "format: " << VideoPixelFormatToString(format_) + << " storage_type: " << StorageTypeToString(storage_type_) + << " coded_size: " << coded_size_.ToString() + << " visible_rect: " << visible_rect_.ToString() + << " natural_size: " << natural_size_.ToString() + << " timestamp: " << timestamp_.InMicroseconds(); + return s.str(); +} + // static scoped_refptr<VideoFrame> VideoFrame::WrapExternalStorage( VideoPixelFormat format,
diff --git a/media/base/video_frame.h b/media/base/video_frame.h index edd9dd55..ad7f4c0 100644 --- a/media/base/video_frame.h +++ b/media/base/video_frame.h
@@ -8,6 +8,7 @@ #include <stddef.h> #include <stdint.h> +#include <string> #include <vector> #include "base/callback.h" @@ -409,6 +410,9 @@ // This method is thread safe. Both blink and compositor threads can call it. void UpdateReleaseSyncToken(SyncTokenClient* client); + // Returns a human-readable string describing |*this|. + std::string AsHumanReadableString(); + private: friend class base::RefCountedThreadSafe<VideoFrame>;
diff --git a/media/blink/BUILD.gn b/media/blink/BUILD.gn index 75c368a..31140ce 100644 --- a/media/blink/BUILD.gn +++ b/media/blink/BUILD.gn
@@ -12,6 +12,7 @@ "//base", "//cc", "//cc/blink", + "//gpu", "//gpu/blink", "//media", "//media:shared_memory_support", @@ -92,6 +93,12 @@ "webmediaplayer_impl.cc", "webmediaplayer_impl.h", ] + if (is_android) { + sources += [ + "webmediaplayer_cast_android.cc", + "webmediaplayer_cast_android.h", + ] + } } }
diff --git a/media/blink/media_blink.gyp b/media/blink/media_blink.gyp index 9bac71e..72eec89 100644 --- a/media/blink/media_blink.gyp +++ b/media/blink/media_blink.gyp
@@ -16,6 +16,7 @@ '../../cc/cc.gyp:cc', '../../cc/blink/cc_blink.gyp:cc_blink', '../../gpu/blink/gpu_blink.gyp:gpu_blink', + '../../gpu/gpu.gyp:gpu', '../../ui/gfx/gfx.gyp:gfx_geometry', '../../net/net.gyp:net', '../../skia/skia.gyp:skia', @@ -92,6 +93,12 @@ 'websourcebuffer_impl.h', ], 'conditions': [ + ['OS=="android" and media_use_ffmpeg==1', { + 'sources': [ + 'webmediaplayer_cast_android.cc', + 'webmediaplayer_cast_android.h', + ], + }], ['OS=="android" and media_use_ffmpeg==0', { 'sources!': [ 'encrypted_media_player_support.cc',
diff --git a/media/blink/renderer_media_player_interface.h b/media/blink/renderer_media_player_interface.h new file mode 100644 index 0000000..db50f8f3 --- /dev/null +++ b/media/blink/renderer_media_player_interface.h
@@ -0,0 +1,128 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef MEDIA_BLINK_RENDERER_MEDIA_PLAYER_INTERFACE_H_ +#define MEDIA_BLINK_RENDERER_MEDIA_PLAYER_INTERFACE_H_ + +// This file contains interfaces modeled after classes in +// content/renderer/media/android for the purposes of letting clases in +// this directory implement and/or interact with those classes. +// It's a stop-gap used to support cast on android until a better solution +// is implemented: crbug/575276 + +#include <string> +#include "base/time/time.h" +#include "ui/gfx/geometry/rect_f.h" +#include "url/gurl.h" + +// Dictates which type of media playback is being initialized. +enum MediaPlayerHostMsg_Initialize_Type { + MEDIA_PLAYER_TYPE_URL, + MEDIA_PLAYER_TYPE_MEDIA_SOURCE, + MEDIA_PLAYER_TYPE_REMOTE_ONLY, + MEDIA_PLAYER_TYPE_LAST = MEDIA_PLAYER_TYPE_REMOTE_ONLY +}; + +namespace media { + +class RendererMediaPlayerInterface { + public: + virtual void OnMediaMetadataChanged(base::TimeDelta duration, + int width, + int height, + bool success) = 0; + virtual void OnPlaybackComplete() = 0; + virtual void OnBufferingUpdate(int percentage) = 0; + virtual void OnSeekRequest(const base::TimeDelta& time_to_seek) = 0; + virtual void OnSeekComplete(const base::TimeDelta& current_time) = 0; + virtual void OnMediaError(int error_type) = 0; + virtual void OnVideoSizeChanged(int width, int height) = 0; + + // Called to update the current time. + virtual void OnTimeUpdate(base::TimeDelta current_timestamp, + base::TimeTicks current_time_ticks) = 0; + + virtual void OnWaitingForDecryptionKey() = 0; + virtual void OnPlayerReleased() = 0; + + // Functions called when media player status changes. + virtual void OnConnectedToRemoteDevice( + const std::string& remote_playback_message) = 0; + virtual void OnDisconnectedFromRemoteDevice() = 0; + virtual void OnDidExitFullscreen() = 0; + virtual void OnMediaPlayerPlay() = 0; + virtual void OnMediaPlayerPause() = 0; + virtual void OnRemoteRouteAvailabilityChanged(bool routes_available) = 0; + + // Getters of playback state. + virtual bool paused() const = 0; + + // True if the loaded media has a playable video track. + virtual bool hasVideo() const = 0; + + // This function is called by the RendererMediaPlayerManager to pause the + // video and release the media player and surface texture when we switch tabs. + // However, the actual GlTexture is not released to keep the video screenshot. + virtual void SuspendAndReleaseResources() = 0; + +#if defined(VIDEO_HOLE) + // Calculate the boundary rectangle of the media player (i.e. location and + // size of the video frame). + // Returns true if the geometry has been changed since the last call. + virtual bool UpdateBoundaryRectangle() = 0; + + virtual const gfx::RectF GetBoundaryRectangle() = 0; +#endif +}; + +class RendererMediaPlayerManagerInterface { + public: + // Initializes a MediaPlayerAndroid object in browser process. + virtual void Initialize(MediaPlayerHostMsg_Initialize_Type type, + int player_id, + const GURL& url, + const GURL& first_party_for_cookies, + int demuxer_client_id, + const GURL& frame_url, + bool allow_credentials) = 0; + + // Starts the player. + virtual void Start(int player_id) = 0; + + // Pauses the player. + // is_media_related_action should be true if this pause is coming from an + // an action that explicitly pauses the video (user pressing pause, JS, etc.) + // Otherwise it should be false if Pause is being called due to other reasons + // (cleanup, freeing resources, etc.) + virtual void Pause(int player_id, bool is_media_related_action) = 0; + + // Performs seek on the player. + virtual void Seek(int player_id, const base::TimeDelta& time) = 0; + + // Sets the player volume. + virtual void SetVolume(int player_id, double volume) = 0; + + // Sets the poster image. + virtual void SetPoster(int player_id, const GURL& poster) = 0; + + // Releases resources for the player after being suspended. + virtual void SuspendAndReleaseResources(int player_id) = 0; + + // Destroys the player in the browser process + virtual void DestroyPlayer(int player_id) = 0; + + // Requests remote playback if possible + virtual void RequestRemotePlayback(int player_id) = 0; + + // Requests control of remote playback + virtual void RequestRemotePlaybackControl(int player_id) = 0; + + // Registers and unregisters a RendererMediaPlayerInterface object. + virtual int RegisterMediaPlayer(RendererMediaPlayerInterface* player) = 0; + virtual void UnregisterMediaPlayer(int player_id) = 0; +}; + +} // namespace media + +#endif // MEDIA_BLINK_RENDERER_MEDIA_PLAYER_INTERFACE_H_
diff --git a/media/blink/webmediaplayer_cast_android.cc b/media/blink/webmediaplayer_cast_android.cc new file mode 100644 index 0000000..608ed2c --- /dev/null +++ b/media/blink/webmediaplayer_cast_android.cc
@@ -0,0 +1,391 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "media/blink/webmediaplayer_cast_android.h" + +#include "gpu/GLES2/gl2extchromium.h" +#include "gpu/blink/webgraphicscontext3d_impl.h" +#include "gpu/command_buffer/client/gles2_interface.h" +#include "gpu/command_buffer/common/sync_token.h" +#include "media/base/android/media_common_android.h" +#include "media/base/bind_to_current_loop.h" +#include "media/blink/webmediaplayer_impl.h" +#include "media/blink/webmediaplayer_params.h" +#include "third_party/WebKit/public/platform/WebMediaPlayerClient.h" +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" +#include "third_party/skia/include/core/SkCanvas.h" +#include "third_party/skia/include/core/SkPaint.h" +#include "third_party/skia/include/core/SkTypeface.h" +#include "third_party/skia/include/gpu/GrContext.h" +#include "third_party/skia/include/gpu/SkGrPixelRef.h" + +using gpu::gles2::GLES2Interface; + +namespace media { + +namespace { +// File-static function is to allow it to run even after WMPI is deleted. +void OnReleaseTexture( + const base::Callback<gpu::gles2::GLES2Interface*()>& context_3d_cb, + GLuint texture_id, + const gpu::SyncToken& sync_token) { + GLES2Interface* gl = context_3d_cb.Run(); + if (!gl) + return; + + gl->WaitSyncTokenCHROMIUM(sync_token.GetConstData()); + gl->DeleteTextures(1, &texture_id); + // Flush to ensure that the texture gets deleted in a timely fashion. + gl->ShallowFlushCHROMIUM(); +} + +GLES2Interface* GLCBShim( + const WebMediaPlayerParams::Context3DCB& context_3d_cb) { + return context_3d_cb.Run().gl; +} + +} // namespace + +scoped_refptr<VideoFrame> MakeTextFrameForCast( + const std::string& remote_playback_message, + gfx::Size canvas_size, + gfx::Size natural_size, + const base::Callback<gpu::gles2::GLES2Interface*()>& context_3d_cb) { + SkBitmap bitmap; + bitmap.allocN32Pixels(canvas_size.width(), canvas_size.height()); + + // Create the canvas and draw the "Casting to <Chromecast>" text on it. + SkCanvas canvas(bitmap); + canvas.drawColor(SK_ColorBLACK); + + const SkScalar kTextSize(40); + const SkScalar kMinPadding(40); + + SkPaint paint; + paint.setAntiAlias(true); + paint.setFilterQuality(kHigh_SkFilterQuality); + paint.setColor(SK_ColorWHITE); + paint.setTypeface(SkTypeface::CreateFromName("sans", SkTypeface::kBold)); + paint.setTextSize(kTextSize); + + // Calculate the vertical margin from the top + SkPaint::FontMetrics font_metrics; + paint.getFontMetrics(&font_metrics); + SkScalar sk_vertical_margin = kMinPadding - font_metrics.fAscent; + + // Measure the width of the entire text to display + size_t display_text_width = paint.measureText(remote_playback_message.c_str(), + remote_playback_message.size()); + std::string display_text(remote_playback_message); + + if (display_text_width + (kMinPadding * 2) > canvas_size.width()) { + // The text is too long to fit in one line, truncate it and append ellipsis + // to the end. + + // First, figure out how much of the canvas the '...' will take up. + const std::string kTruncationEllipsis("\xE2\x80\xA6"); + SkScalar sk_ellipse_width = paint.measureText(kTruncationEllipsis.c_str(), + kTruncationEllipsis.size()); + + // Then calculate how much of the text can be drawn with the '...' appended + // to the end of the string. + SkScalar sk_max_original_text_width(canvas_size.width() - + (kMinPadding * 2) - sk_ellipse_width); + size_t sk_max_original_text_length = paint.breakText( + remote_playback_message.c_str(), remote_playback_message.size(), + sk_max_original_text_width); + + // Remove the part of the string that doesn't fit and append '...'. + display_text.erase( + sk_max_original_text_length, + remote_playback_message.size() - sk_max_original_text_length); + display_text.append(kTruncationEllipsis); + display_text_width = + paint.measureText(display_text.c_str(), display_text.size()); + } + + // Center the text horizontally. + SkScalar sk_horizontal_margin = + (canvas_size.width() - display_text_width) / 2.0; + canvas.drawText(display_text.c_str(), display_text.size(), + sk_horizontal_margin, sk_vertical_margin, paint); + + GLES2Interface* gl = context_3d_cb.Run(); + + // GPU Process crashed. + if (!gl) + return nullptr; + GLuint remote_playback_texture_id = 0; + gl->GenTextures(1, &remote_playback_texture_id); + GLuint texture_target = GL_TEXTURE_2D; + gl->BindTexture(texture_target, remote_playback_texture_id); + gl->TexParameteri(texture_target, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->TexParameteri(texture_target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(texture_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + { + SkAutoLockPixels lock(bitmap); + gl->TexImage2D(texture_target, 0 /* level */, GL_RGBA /* internalformat */, + bitmap.width(), bitmap.height(), 0 /* border */, + GL_RGBA /* format */, GL_UNSIGNED_BYTE /* type */, + bitmap.getPixels()); + } + + gpu::Mailbox texture_mailbox; + gl->GenMailboxCHROMIUM(texture_mailbox.name); + gl->ProduceTextureCHROMIUM(texture_target, texture_mailbox.name); + gl->Flush(); + gpu::SyncToken texture_mailbox_sync_token(gl->InsertSyncPointCHROMIUM()); + + return VideoFrame::WrapNativeTexture( + media::PIXEL_FORMAT_ARGB, + gpu::MailboxHolder(texture_mailbox, texture_mailbox_sync_token, + texture_target), + media::BindToCurrentLoop(base::Bind(&OnReleaseTexture, context_3d_cb, + remote_playback_texture_id)), + canvas_size /* coded_size */, gfx::Rect(canvas_size) /* visible_rect */, + natural_size /* natural_size */, base::TimeDelta() /* timestamp */); +} + +WebMediaPlayerCast::WebMediaPlayerCast( + WebMediaPlayerImpl* impl, + blink::WebMediaPlayerClient* client, + const WebMediaPlayerParams::Context3DCB& context_3d_cb, + base::WeakPtr<WebMediaPlayerDelegate> delegate) + : webmediaplayer_(impl), + client_(client), + context_3d_cb_(context_3d_cb), + delegate_(delegate) {} + +WebMediaPlayerCast::~WebMediaPlayerCast() { + if (player_manager_) { + if (is_player_initialized_) + player_manager_->DestroyPlayer(player_id_); + + player_manager_->UnregisterMediaPlayer(player_id_); + } +} + +void WebMediaPlayerCast::Initialize(const GURL& url, + blink::WebLocalFrame* frame) { + player_manager_->Initialize(MEDIA_PLAYER_TYPE_REMOTE_ONLY, player_id_, url, + frame->document().firstPartyForCookies(), 0, + frame->document().url(), true); + is_player_initialized_ = true; +} + +void WebMediaPlayerCast::SetMediaPlayerManager( + RendererMediaPlayerManagerInterface* media_player_manager) { + player_manager_ = media_player_manager; + player_id_ = player_manager_->RegisterMediaPlayer(this); +} + +void WebMediaPlayerCast::requestRemotePlayback() { + player_manager_->Seek(player_id_, base::TimeDelta::FromSecondsD( + webmediaplayer_->currentTime())); + player_manager_->RequestRemotePlayback(player_id_); +} + +void WebMediaPlayerCast::requestRemotePlaybackControl() { + player_manager_->RequestRemotePlaybackControl(player_id_); +} + +void WebMediaPlayerCast::OnMediaMetadataChanged(base::TimeDelta duration, + int width, + int height, + bool success) {} + +void WebMediaPlayerCast::OnPlaybackComplete() { + DVLOG(1) << __FUNCTION__; + webmediaplayer_->OnRemotePlaybackEnded(); +} + +void WebMediaPlayerCast::OnBufferingUpdate(int percentage) { + DVLOG(1) << __FUNCTION__; +} + +void WebMediaPlayerCast::OnSeekRequest(const base::TimeDelta& time_to_seek) { + DVLOG(1) << __FUNCTION__; + client_->requestSeek(time_to_seek.InSecondsF()); +} + +void WebMediaPlayerCast::OnSeekComplete(const base::TimeDelta& current_time) { + DVLOG(1) << __FUNCTION__; + remote_time_at_ = base::TimeTicks::Now(); + remote_time_ = current_time; + webmediaplayer_->OnPipelineSeeked(true, PIPELINE_OK); +} + +void WebMediaPlayerCast::OnMediaError(int error_type) { + DVLOG(1) << __FUNCTION__; +} + +void WebMediaPlayerCast::OnVideoSizeChanged(int width, int height) { + DVLOG(1) << __FUNCTION__; +} + +void WebMediaPlayerCast::OnTimeUpdate(base::TimeDelta current_timestamp, + base::TimeTicks current_time_ticks) { + DVLOG(1) << __FUNCTION__ << " " << current_timestamp.InSecondsF(); + remote_time_at_ = current_time_ticks; + remote_time_ = current_timestamp; +} + +void WebMediaPlayerCast::OnPlayerReleased() { + DVLOG(1) << __FUNCTION__; +} + +void WebMediaPlayerCast::OnConnectedToRemoteDevice( + const std::string& remote_playback_message) { + DVLOG(1) << __FUNCTION__; + remote_time_ = base::TimeDelta::FromSecondsD(webmediaplayer_->currentTime()); + is_remote_ = true; + initializing_ = true; + paused_ = false; + if (delegate_ && is_remote_) + delegate_->DidPlay(webmediaplayer_); + client_->playbackStateChanged(); + + remote_playback_message_ = remote_playback_message; + webmediaplayer_->SuspendForRemote(); + client_->connectedToRemoteDevice(); +} + +double WebMediaPlayerCast::currentTime() const { + base::TimeDelta ret = remote_time_; + if (!paused_ && !initializing_) { + ret += base::TimeTicks::Now() - remote_time_at_; + } + return ret.InSecondsF(); +} + +void WebMediaPlayerCast::play() { + if (!paused_) + return; + + player_manager_->Start(player_id_); + remote_time_at_ = base::TimeTicks::Now(); + paused_ = false; + if (delegate_ && is_remote_) + delegate_->DidPlay(webmediaplayer_); +} + +void WebMediaPlayerCast::pause() { + if (paused_) + return; + player_manager_->Pause(player_id_, true); +} + +void WebMediaPlayerCast::seek(base::TimeDelta t) { + should_notify_time_changed_ = true; + player_manager_->Seek(player_id_, t); +} + +void WebMediaPlayerCast::OnDisconnectedFromRemoteDevice() { + DVLOG(1) << __FUNCTION__; + if (!paused_) { + paused_ = true; + if (delegate_ && is_remote_) + delegate_->DidPause(webmediaplayer_); + } + is_remote_ = false; + double t = currentTime(); + if (t + media::kTimeUpdateInterval * 2 / 1000 > webmediaplayer_->duration()) { + t = webmediaplayer_->duration(); + } + webmediaplayer_->OnDisconnectedFromRemoteDevice(t); +} + +void WebMediaPlayerCast::OnDidExitFullscreen() { + DVLOG(1) << __FUNCTION__; +} + +void WebMediaPlayerCast::OnMediaPlayerPlay() { + DVLOG(1) << __FUNCTION__ << " is_remote_ = " << is_remote_; + initializing_ = false; + if (paused_) { + paused_ = false; + if (delegate_ && paused_ && is_remote_) + delegate_->DidPlay(webmediaplayer_); + if (!is_remote_) + webmediaplayer_->play(); + + remote_time_at_ = base::TimeTicks::Now(); + client_->playbackStateChanged(); + } + // Blink expects a timeChanged() in response to a seek(). + if (should_notify_time_changed_) + client_->timeChanged(); +} + +void WebMediaPlayerCast::OnMediaPlayerPause() { + DVLOG(1) << __FUNCTION__ << " is_remote_ = " << is_remote_; + if (!paused_) { + paused_ = true; + if (delegate_ && is_remote_) + delegate_->DidPause(webmediaplayer_); + if (!is_remote_) + webmediaplayer_->pause(); + client_->playbackStateChanged(); + } +} + +void WebMediaPlayerCast::OnRemoteRouteAvailabilityChanged( + bool routes_available) { + DVLOG(1) << __FUNCTION__; + client_->remoteRouteAvailabilityChanged(routes_available); +} + +void WebMediaPlayerCast::SuspendAndReleaseResources() {} +void WebMediaPlayerCast::OnWaitingForDecryptionKey() {} + +bool WebMediaPlayerCast::hasVideo() const { + return true; +} + +bool WebMediaPlayerCast::paused() const { + return paused_; +} + +#if defined(VIDEO_HOLE) +bool WebMediaPlayerCast::UpdateBoundaryRectangle() { + return false; +} + +const gfx::RectF WebMediaPlayerCast::GetBoundaryRectangle() { + return gfx::RectF(); +} +#endif // defined(VIDEO_HOLE) + +void WebMediaPlayerCast::SetDeviceScaleFactor(float scale_factor) { + device_scale_factor_ = scale_factor; +} + +scoped_refptr<VideoFrame> WebMediaPlayerCast::GetCastingBanner() { + DVLOG(1) << __FUNCTION__; + + // TODO(johnme): Should redraw this frame if the layer bounds change; but + // there seems no easy way to listen for the layer resizing (as opposed to + // OnVideoSizeChanged, which is when the frame sizes of the video file + // change). Perhaps have to poll (on main thread of course)? + gfx::Size video_size_css_px = webmediaplayer_->GetCanvasSize(); + if (!video_size_css_px.width()) + return nullptr; + + // canvas_size will be the size in device pixels when pageScaleFactor == 1 + gfx::Size canvas_size( + static_cast<int>(video_size_css_px.width() * device_scale_factor_), + static_cast<int>(video_size_css_px.height() * device_scale_factor_)); + + if (!canvas_size.width()) + return nullptr; + + return MakeTextFrameForCast(remote_playback_message_, canvas_size, + webmediaplayer_->naturalSize(), + base::Bind(&GLCBShim, context_3d_cb_)); +} + +} // namespace media
diff --git a/media/blink/webmediaplayer_cast_android.h b/media/blink/webmediaplayer_cast_android.h new file mode 100644 index 0000000..2707e885 --- /dev/null +++ b/media/blink/webmediaplayer_cast_android.h
@@ -0,0 +1,151 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Delete this file when WMPI_CAST is no longer needed. + +#ifndef MEDIA_BLINK_WEBMEDIAPLAYER_CAST_H_ +#define MEDIA_BLINK_WEBMEDIAPLAYER_CAST_H_ + +#include "base/memory/weak_ptr.h" +#include "media/blink/media_blink_export.h" +#include "media/blink/renderer_media_player_interface.h" +#include "media/blink/webmediaplayer_params.h" +#include "url/gurl.h" + +namespace blink { +class WebLocalFrame; +class WebMediaPlayerClient; +} + +namespace media { + +class VideoFrame; +class WebMediaPlayerDelegate; +class WebMediaPlayerImpl; + +// This shim allows WebMediaPlayer to act sufficiently similar to +// WebMediaPlayerAndroid (by extending RendererMediaPlayerInterface) +// to implement cast functionality. +class WebMediaPlayerCast : public RendererMediaPlayerInterface { + public: + WebMediaPlayerCast(WebMediaPlayerImpl* impl, + blink::WebMediaPlayerClient* client, + const WebMediaPlayerParams::Context3DCB& context_3d_cb, + base::WeakPtr<WebMediaPlayerDelegate> delegate); + ~WebMediaPlayerCast(); + + void Initialize(const GURL& url, blink::WebLocalFrame* frame); + + void requestRemotePlayback(); + void requestRemotePlaybackControl(); + + void SetMediaPlayerManager( + RendererMediaPlayerManagerInterface* media_player_manager); + bool isRemote() const { return is_remote_; } + + double currentTime() const; + void play(); + void pause(); + void seek(base::TimeDelta t); + + // RendererMediaPlayerInterface implementation + void OnMediaMetadataChanged(base::TimeDelta duration, + int width, + int height, + bool success) override; + void OnPlaybackComplete() override; + void OnBufferingUpdate(int percentage) override; + void OnSeekRequest(const base::TimeDelta& time_to_seek) override; + void OnSeekComplete(const base::TimeDelta& current_time) override; + void OnMediaError(int error_type) override; + void OnVideoSizeChanged(int width, int height) override; + + // Called to update the current time. + void OnTimeUpdate(base::TimeDelta current_timestamp, + base::TimeTicks current_time_ticks) override; + + // void OnWaitingForDecryptionKey() override; + void OnPlayerReleased() override; + + // Functions called when media player status changes. + void OnConnectedToRemoteDevice( + const std::string& remote_playback_message) override; + void OnDisconnectedFromRemoteDevice() override; + void OnDidExitFullscreen() override; + void OnMediaPlayerPlay() override; + void OnMediaPlayerPause() override; + void OnRemoteRouteAvailabilityChanged(bool routes_available) override; + + // Getters of playback state. + // bool paused() const override; + + // True if the loaded media has a playable video track. + // bool hasVideo() const override; + + // This function is called by the RendererMediaPlayerManager to pause the + // video and release the media player and surface texture when we switch tabs. + // However, the actual GlTexture is not released to keep the video screenshot. + void SuspendAndReleaseResources() override; + +#if defined(VIDEO_HOLE) + // Calculate the boundary rectangle of the media player (i.e. location and + // size of the video frame). + // Returns true if the geometry has been changed since the last call. + bool UpdateBoundaryRectangle() override; + + const gfx::RectF GetBoundaryRectangle() override; +#endif + + void OnWaitingForDecryptionKey() override; + + bool paused() const override; + bool hasVideo() const override; + + void SetDeviceScaleFactor(float scale_factor); + scoped_refptr<VideoFrame> GetCastingBanner(); + + private: + WebMediaPlayerImpl* webmediaplayer_; + blink::WebMediaPlayerClient* client_; + WebMediaPlayerParams::Context3DCB context_3d_cb_; + base::WeakPtr<WebMediaPlayerDelegate> delegate_; + + // Manages this object and delegates player calls to the browser process. + // Owned by RenderFrameImpl. + RendererMediaPlayerManagerInterface* player_manager_ = nullptr; + + // Player ID assigned by the |player_manager_|. + int player_id_; + + // Whether the browser is currently connected to a remote media player. + bool is_remote_ = false; + + bool paused_ = true; + bool initializing_ = false; + bool should_notify_time_changed_ = false; + + // Last reported playout time. + base::TimeDelta remote_time_; + base::TimeTicks remote_time_at_; + + // Whether the media player has been initialized. + bool is_player_initialized_ = false; + + std::string remote_playback_message_; + + float device_scale_factor_ = 1.0; + + DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerCast); +}; + +// Make a texture-backed video of the given size containing the given message. +MEDIA_BLINK_EXPORT scoped_refptr<VideoFrame> MakeTextFrameForCast( + const std::string& remote_playback_message, + gfx::Size canvas_size, + gfx::Size natural_size, + const base::Callback<gpu::gles2::GLES2Interface*()>& context_3d_cb); + +} // namespace media + +#endif // MEDIA_BLINK_WEBMEDIAPLAYER_CAST_H_
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index dc17467..584a0d9 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -64,6 +64,9 @@ using blink::WebRect; using blink::WebSize; using blink::WebString; +using gpu::gles2::GLES2Interface; + +namespace media { namespace { @@ -86,23 +89,20 @@ const double kMinRate = 0.0625; const double kMaxRate = 16.0; -void SetSinkIdOnMediaThread( - scoped_refptr<media::WebAudioSourceProviderImpl> sink, - const std::string& device_id, - const url::Origin& security_origin, - const media::SwitchOutputDeviceCB& callback) { +void SetSinkIdOnMediaThread(scoped_refptr<WebAudioSourceProviderImpl> sink, + const std::string& device_id, + const url::Origin& security_origin, + const SwitchOutputDeviceCB& callback) { if (sink->GetOutputDevice()) { sink->GetOutputDevice()->SwitchOutputDevice(device_id, security_origin, callback); } else { - callback.Run(media::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); + callback.Run(OUTPUT_DEVICE_STATUS_ERROR_INTERNAL); } } } // namespace -namespace media { - class BufferedDataSourceHostImpl; #define STATIC_ASSERT_MATCHING_ENUM(name, name2) \ @@ -182,6 +182,9 @@ AsWeakPtr(), base::Bind(&IgnoreCdmAttached))), is_cdm_attached_(false), +#if defined(OS_ANDROID) // WMPI_CAST + cast_impl_(this, client_, params.context_3d_cb(), delegate), +#endif renderer_factory_(std::move(renderer_factory)) { DCHECK(!adjust_allocated_memory_cb_.is_null()); DCHECK(renderer_factory_); @@ -302,13 +305,25 @@ data_source_->SetBufferingStrategy(buffering_strategy_); data_source_->Initialize( base::Bind(&WebMediaPlayerImpl::DataSourceInitialized, AsWeakPtr())); + +#if defined(OS_ANDROID) // WMPI_CAST + cast_impl_.Initialize(url, frame_); +#endif } void WebMediaPlayerImpl::play() { DVLOG(1) << __FUNCTION__; DCHECK(main_task_runner_->BelongsToCurrentThread()); +#if defined(OS_ANDROID) // WMPI_CAST + cast_impl_.play(); + if (isRemote()) { + return; + } +#endif + paused_ = false; + pipeline_.SetPlaybackRate(playback_rate_); if (data_source_) data_source_->MediaIsPlaying(); @@ -325,6 +340,14 @@ const bool was_already_paused = paused_ || playback_rate_ == 0; paused_ = true; + +#if defined(OS_ANDROID) // WMPI_CAST + cast_impl_.pause(); + if (isRemote()) { + return; + } +#endif + pipeline_.SetPlaybackRate(0.0); UpdatePausedTime(); @@ -345,12 +368,19 @@ ended_ = false; + base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds); + +#if defined(OS_ANDROID) // WMPI_CAST + if (isRemote()) { + cast_impl_.seek(new_seek_time); + return; + } +#endif + ReadyState old_state = ready_state_; if (ready_state_ > WebMediaPlayer::ReadyStateHaveMetadata) SetReadyState(WebMediaPlayer::ReadyStateHaveMetadata); - base::TimeDelta new_seek_time = base::TimeDelta::FromSecondsD(seconds); - if (seeking_ || suspended_) { // Once resuming, it's too late to change the resume time and so the // implementation is a little different. @@ -424,7 +454,6 @@ if (chunk_demuxer_) chunk_demuxer_->StartWaitingForSeek(seek_time_); - // Kick off the asynchronous seek! pipeline_.Seek(seek_time_, BIND_TO_RENDER_LOOP1( &WebMediaPlayerImpl::OnPipelineSeeked, true)); } @@ -541,6 +570,10 @@ bool WebMediaPlayerImpl::paused() const { DCHECK(main_task_runner_->BelongsToCurrentThread()); +#if defined(OS_ANDROID) // WMPI_CAST + if (isRemote()) + return cast_impl_.paused(); +#endif return pipeline_.GetPlaybackRate() == 0.0f; } @@ -588,7 +621,17 @@ : seek_time_.InSecondsF(); } - return (paused_ ? paused_time_ : pipeline_.GetMediaTime()).InSecondsF(); +#if defined(OS_ANDROID) // WMPI_CAST + if (isRemote()) { + return cast_impl_.currentTime(); + } +#endif + + if (paused_) { + return paused_time_.InSecondsF(); + } + + return pipeline_.GetMediaTime().InSecondsF(); } WebMediaPlayer::NetworkState WebMediaPlayerImpl::networkState() const { @@ -915,6 +958,15 @@ suspending_ = false; +#if defined(OS_ANDROID) + if (isRemote()) { + scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); + if (frame) { + compositor_->PaintFrameUsingOldRenderingPath(frame); + } + } +#endif + if (pending_resume_) { pending_resume_ = false; Resume(); @@ -1055,6 +1107,16 @@ return; } +#if defined(OS_ANDROID) + // If we're remote, the pipeline should already be suspended. + if (isRemote()) + return; +#endif + + ScheduleSuspend(); +} + +void WebMediaPlayerImpl::ScheduleSuspend() { if (!pipeline_.IsRunning() || !hasVideo()) return; @@ -1096,6 +1158,16 @@ return; } +#if defined(OS_ANDROID) + // If we're remote, the pipeline should stay suspended. + if (isRemote()) + return; +#endif + + ScheduleResume(); +} + +void WebMediaPlayerImpl::ScheduleResume() { if (!pipeline_.IsRunning()) return; @@ -1109,12 +1181,9 @@ return; } - // We may not be suspended if we were not yet subscribed or the pipeline was - // not yet started when OnHidden() fired. - if (!suspended_) - return; - - Resume(); + // Might already be resuming iff we came back from remote playback recently. + if (suspended_ && !resuming_) + Resume(); } void WebMediaPlayerImpl::Resume() { @@ -1150,6 +1219,70 @@ time_changed)); } +#if defined(OS_ANDROID) // WMPI_CAST + +bool WebMediaPlayerImpl::isRemote() const { + return cast_impl_.isRemote(); +} + +void WebMediaPlayerImpl::SetMediaPlayerManager( + RendererMediaPlayerManagerInterface* media_player_manager) { + cast_impl_.SetMediaPlayerManager(media_player_manager); +} + +void WebMediaPlayerImpl::requestRemotePlayback() { + cast_impl_.requestRemotePlayback(); +} + +void WebMediaPlayerImpl::requestRemotePlaybackControl() { + cast_impl_.requestRemotePlaybackControl(); +} + +void WebMediaPlayerImpl::OnRemotePlaybackEnded() { + DVLOG(1) << __FUNCTION__; + DCHECK(main_task_runner_->BelongsToCurrentThread()); + + ended_ = true; + client_->timeChanged(); +} + +void WebMediaPlayerImpl::OnDisconnectedFromRemoteDevice(double t) { + paused_time_ = base::TimeDelta::FromSecondsD(t); + pending_seek_ = true; + pending_seek_time_ = paused_time_; + + ScheduleResume(); + + if (paused_time_ == pipeline_.GetMediaDuration()) { + ended_ = true; + } + // We already told the delegate we're paused when remoting started. + client_->playbackStateChanged(); + client_->disconnectedFromRemoteDevice(); +} + +void WebMediaPlayerImpl::SuspendForRemote() { + if (suspended_ && !suspending_) { + scoped_refptr<VideoFrame> frame = cast_impl_.GetCastingBanner(); + if (frame) { + compositor_->PaintFrameUsingOldRenderingPath(frame); + } + } + ScheduleSuspend(); +} + +gfx::Size WebMediaPlayerImpl::GetCanvasSize() const { + if (!video_weblayer_) + return pipeline_metadata_.natural_size; + + return video_weblayer_->bounds(); +} + +void WebMediaPlayerImpl::SetDeviceScaleFactor(float scale_factor) { + cast_impl_.SetDeviceScaleFactor(scale_factor); +} +#endif // defined(OS_ANDROID) // WMPI_CAST + void WebMediaPlayerImpl::DataSourceInitialized(bool success) { DVLOG(1) << __FUNCTION__; DCHECK(main_task_runner_->BelongsToCurrentThread()); @@ -1331,6 +1464,12 @@ } void WebMediaPlayerImpl::NotifyPlaybackStarted() { +#if defined(OS_ANDROID) // WMPI_CAST + // We do not tell our delegates about remote playback, becuase that would + // keep the device awake, which is not what we want. + if (isRemote()) + return; +#endif if (delegate_) delegate_->DidPlay(this); if (!memory_usage_reporting_timer_.IsRunning()) { @@ -1341,6 +1480,10 @@ } void WebMediaPlayerImpl::NotifyPlaybackPaused() { +#if defined(OS_ANDROID) // WMPI_CAST + if (isRemote()) + return; +#endif if (delegate_) delegate_->DidPause(this); memory_usage_reporting_timer_.Stop();
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h index f9c868d..ba03528 100644 --- a/media/blink/webmediaplayer_impl.h +++ b/media/blink/webmediaplayer_impl.h
@@ -17,6 +17,7 @@ #include "base/memory/scoped_ptr.h" #include "base/memory/weak_ptr.h" #include "base/threading/thread.h" +#include "build/build_config.h" #include "media/base/cdm_factory.h" #include "media/base/pipeline.h" #include "media/base/renderer_factory.h" @@ -36,6 +37,11 @@ #include "third_party/WebKit/public/platform/WebMediaPlayer.h" #include "url/gurl.h" +#if defined(OS_ANDROID) // WMPI_CAST +// Delete this file when WMPI_CAST is no longer needed. +#include "media/blink/webmediaplayer_cast_android.h" +#endif + namespace blink { class WebGraphicsContext3D; class WebLocalFrame; @@ -189,10 +195,34 @@ void OnHidden() override; void OnShown() override; +#if defined(OS_ANDROID) // WMPI_CAST + bool isRemote() const override; + void requestRemotePlayback() override; + void requestRemotePlaybackControl() override; + + void SetMediaPlayerManager( + RendererMediaPlayerManagerInterface* media_player_manager); + void OnRemotePlaybackEnded(); + void OnDisconnectedFromRemoteDevice(double t); + void SuspendForRemote(); + void DisplayCastFrameAfterSuspend(const scoped_refptr<VideoFrame>& new_frame, + PipelineStatus status); + gfx::Size GetCanvasSize() const; + void SetDeviceScaleFactor(float scale_factor); +#endif + private: + // Ask for the pipeline to be suspended, will call Suspend() when ready. + // (Possibly immediately.) + void ScheduleSuspend(); + // Initiate suspending the pipeline. void Suspend(); + // Ask for the pipeline to be resumed, will call Resume() when ready. + // (Possibly immediately.) + void ScheduleResume(); + // Initiate resuming the pipeline. void Resume(); @@ -400,6 +430,10 @@ // Whether a CDM has been successfully attached. bool is_cdm_attached_; +#if defined(OS_ANDROID) // WMPI_CAST + WebMediaPlayerCast cast_impl_; +#endif + scoped_ptr<RendererFactory> renderer_factory_; DISALLOW_COPY_AND_ASSIGN(WebMediaPlayerImpl);
diff --git a/media/cast/net/udp_transport.cc b/media/cast/net/udp_transport.cc index 97ec7f4a..a0cc7dd7 100644 --- a/media/cast/net/udp_transport.cc +++ b/media/cast/net/udp_transport.cc
@@ -30,11 +30,6 @@ !addr.port(); } -bool IsEqual(const net::IPEndPoint& addr1, const net::IPEndPoint& addr2) { - return addr1.port() == addr2.port() && std::equal(addr1.address().begin(), - addr1.address().end(), - addr2.address().begin()); -} } // namespace UdpTransport::UdpTransport( @@ -187,7 +182,7 @@ VLOG(1) << "Packet was not valid, resetting remote address."; remote_addr_ = net::IPEndPoint(); } - } else if (!IsEqual(remote_addr_, recv_addr_)) { + } else if (!(remote_addr_ == recv_addr_)) { VLOG(1) << "Ignoring packet received from an unrecognized address: " << recv_addr_.ToString() << "."; } else {
diff --git a/media/cdm/cdm_adapter.cc b/media/cdm/cdm_adapter.cc index 4c159e6..fb89e1a2 100644 --- a/media/cdm/cdm_adapter.cc +++ b/media/cdm/cdm_adapter.cc
@@ -658,6 +658,8 @@ const scoped_refptr<DecoderBuffer>& encrypted, const VideoDecodeCB& video_decode_cb) { DCHECK(task_runner_->BelongsToCurrentThread()); + DVLOG(3) << __FUNCTION__ + << " encrypted: " << encrypted->AsHumanReadableString(); cdm::InputBuffer input_buffer; std::vector<cdm::SubsampleEntry> subsamples;
diff --git a/media/mojo/services/default_mojo_media_client.cc b/media/mojo/services/default_mojo_media_client.cc index 59c3393..661addd 100644 --- a/media/mojo/services/default_mojo_media_client.cc +++ b/media/mojo/services/default_mojo_media_client.cc
@@ -48,15 +48,22 @@ *audio_hardware_config_)); } - scoped_refptr<AudioRendererSink> CreateAudioRendererSink() override { - return new AudioOutputStreamSink(); + AudioRendererSink* CreateAudioRendererSink() override { + if (!audio_renderer_sink_) + audio_renderer_sink_ = new AudioOutputStreamSink(); + + return audio_renderer_sink_.get(); } - scoped_ptr<VideoRendererSink> CreateVideoRendererSink( + VideoRendererSink* CreateVideoRendererSink( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) override { - return make_scoped_ptr( - new NullVideoSink(false, base::TimeDelta::FromSecondsD(1.0 / 60), - NullVideoSink::NewFrameCB(), task_runner)); + if (!video_renderer_sink_) { + video_renderer_sink_ = make_scoped_ptr( + new NullVideoSink(false, base::TimeDelta::FromSecondsD(1.0 / 60), + NullVideoSink::NewFrameCB(), task_runner)); + } + + return video_renderer_sink_.get(); } scoped_ptr<CdmFactory> CreateCdmFactory( @@ -67,6 +74,8 @@ private: FakeAudioLogFactory fake_audio_log_factory_; scoped_ptr<AudioHardwareConfig> audio_hardware_config_; + scoped_refptr<AudioRendererSink> audio_renderer_sink_; + scoped_ptr<VideoRendererSink> video_renderer_sink_; DISALLOW_COPY_AND_ASSIGN(DefaultMojoMediaClient); };
diff --git a/media/mojo/services/mojo_media_client.cc b/media/mojo/services/mojo_media_client.cc index 63b013f9..09bf9315 100644 --- a/media/mojo/services/mojo_media_client.cc +++ b/media/mojo/services/mojo_media_client.cc
@@ -17,11 +17,11 @@ return nullptr; } -scoped_refptr<AudioRendererSink> MojoMediaClient::CreateAudioRendererSink() { +AudioRendererSink* MojoMediaClient::CreateAudioRendererSink() { return nullptr; } -scoped_ptr<VideoRendererSink> MojoMediaClient::CreateVideoRendererSink( +VideoRendererSink* MojoMediaClient::CreateVideoRendererSink( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner) { return nullptr; }
diff --git a/media/mojo/services/mojo_media_client.h b/media/mojo/services/mojo_media_client.h index 93d74d6..8f84395 100644 --- a/media/mojo/services/mojo_media_client.h +++ b/media/mojo/services/mojo_media_client.h
@@ -31,9 +31,10 @@ // CreateAudioDecoders() and CreateVideoDecoders(). virtual scoped_ptr<RendererFactory> CreateRendererFactory( const scoped_refptr<MediaLog>& media_log); - // The output sink used for rendering audio or video respectively. - virtual scoped_refptr<AudioRendererSink> CreateAudioRendererSink(); - virtual scoped_ptr<VideoRendererSink> CreateVideoRendererSink( + // The output sink used for rendering audio or video respectively. These + // sinks must be owned by the client. + virtual AudioRendererSink* CreateAudioRendererSink(); + virtual VideoRendererSink* CreateVideoRendererSink( const scoped_refptr<base::SingleThreadTaskRunner>& task_runner); // Returns the CdmFactory to be used by MojoCdmService.
diff --git a/media/mojo/services/service_factory_impl.cc b/media/mojo/services/service_factory_impl.cc index 4d38c47b..d00efdb 100644 --- a/media/mojo/services/service_factory_impl.cc +++ b/media/mojo/services/service_factory_impl.cc
@@ -38,15 +38,15 @@ void ServiceFactoryImpl::CreateRenderer( mojo::InterfaceRequest<interfaces::Renderer> request) { // The created object is owned by the pipe. + // The audio and video sinks are owned by the client. scoped_refptr<base::SingleThreadTaskRunner> task_runner( base::MessageLoop::current()->task_runner()); - scoped_refptr<AudioRendererSink> audio_renderer_sink = + AudioRendererSink* audio_renderer_sink = mojo_media_client_->CreateAudioRendererSink(); - scoped_ptr<VideoRendererSink> video_renderer_sink = + VideoRendererSink* video_renderer_sink = mojo_media_client_->CreateVideoRendererSink(task_runner); scoped_ptr<Renderer> renderer = GetRendererFactory()->CreateRenderer( - task_runner, task_runner, audio_renderer_sink.get(), - video_renderer_sink.get()); + task_runner, task_runner, audio_renderer_sink, video_renderer_sink); new MojoRendererService(cdm_service_context_.GetWeakPtr(), std::move(renderer), std::move(request));
diff --git a/mojo/edk/system/message_in_transit_queue.cc b/mojo/edk/system/message_in_transit_queue.cc index f95bf724..786c9d4 100644 --- a/mojo/edk/system/message_in_transit_queue.cc +++ b/mojo/edk/system/message_in_transit_queue.cc
@@ -14,7 +14,7 @@ MessageInTransitQueue::~MessageInTransitQueue() { if (!IsEmpty()) { - LOG(WARNING) << "Destroying nonempty message queue"; + DVLOG(1) << "Destroying nonempty message queue"; Clear(); } }
diff --git a/mojo/edk/system/raw_channel_win.cc b/mojo/edk/system/raw_channel_win.cc index 736716a..71b69d4 100644 --- a/mojo/edk/system/raw_channel_win.cc +++ b/mojo/edk/system/raw_channel_win.cc
@@ -157,7 +157,8 @@ if (write_wait_object_) UnregisterWaitEx(write_wait_object_, INVALID_HANDLE_VALUE); - DCHECK(ShouldSelfDestruct()); + DCHECK(ShouldSelfDestruct() || + !base::MessageLoop::current()->is_running()); } HANDLE handle() const { return handle_.get().handle; } @@ -226,7 +227,9 @@ preserved_write_buffer_after_detach_ = write_buffer.Pass(); owner_ = nullptr; - if (ShouldSelfDestruct()) + // On shutdown, the message loop won't be running. Since we'll never get + // notifications after this point, delete the object to avoid leaks. + if (ShouldSelfDestruct() || !base::MessageLoop::current()->is_running()) delete this; }
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java index 2ed71e1..ef573af 100644 --- a/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java +++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifier.java
@@ -7,6 +7,7 @@ import android.content.Context; import org.chromium.base.ObserverList; +import org.chromium.base.VisibleForTesting; import org.chromium.base.annotations.CalledByNative; import org.chromium.base.annotations.JNINamespace; import org.chromium.base.annotations.NativeClassQualifiedName; @@ -39,10 +40,12 @@ private NetworkChangeNotifierAutoDetect mAutoDetector; private int mCurrentConnectionType = ConnectionType.CONNECTION_UNKNOWN; private double mCurrentMaxBandwidth = Double.POSITIVE_INFINITY; + private int mMaxBandwidthConnectionType = mCurrentConnectionType; private static NetworkChangeNotifier sInstance; - private NetworkChangeNotifier(Context context) { + @VisibleForTesting + protected NetworkChangeNotifier(Context context) { mContext = context.getApplicationContext(); mNativeChangeNotifiers = new ArrayList<Long>(); mConnectionTypeObservers = new ObserverList<ConnectionTypeObserver>(); @@ -63,8 +66,8 @@ return sInstance != null; } - static void resetInstanceForTests(Context context) { - sInstance = new NetworkChangeNotifier(context); + static void resetInstanceForTests(NetworkChangeNotifier notifier) { + sInstance = notifier; } @CalledByNative @@ -272,14 +275,25 @@ getInstance().notifyObserversOfConnectionTypeChange(connectionType, netId); } + // For testing, pretend the max bandwidth has changed. + @CalledByNative + public static void fakeMaxBandwidthChanged(double maxBandwidthMbps) { + setAutoDetectConnectivityState(false); + getInstance().notifyObserversOfMaxBandwidthChange(maxBandwidthMbps); + } + private void updateCurrentConnectionType(int newConnectionType) { mCurrentConnectionType = newConnectionType; notifyObserversOfConnectionTypeChange(newConnectionType); } private void updateCurrentMaxBandwidth(double maxBandwidthMbps) { - if (maxBandwidthMbps == mCurrentMaxBandwidth) return; + if (maxBandwidthMbps == mCurrentMaxBandwidth + && mCurrentConnectionType == mMaxBandwidthConnectionType) { + return; + } mCurrentMaxBandwidth = maxBandwidthMbps; + mMaxBandwidthConnectionType = mCurrentConnectionType; notifyObserversOfMaxBandwidthChange(maxBandwidthMbps); }
diff --git a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java index 333c85c..24ab74d 100644 --- a/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java +++ b/net/android/java/src/org/chromium/net/NetworkChangeNotifierAutoDetect.java
@@ -348,6 +348,7 @@ private int mConnectionType; private String mWifiSSID; private double mMaxBandwidthMbps; + private int mMaxBandwidthConnectionType; /** * Observer interface by which observer is notified of network changes. @@ -420,6 +421,7 @@ mConnectionType = getCurrentConnectionType(networkState); mWifiSSID = getCurrentWifiSSID(networkState); mMaxBandwidthMbps = getCurrentMaxBandwidthInMbps(networkState); + mMaxBandwidthConnectionType = mConnectionType; mIntentFilter = new NetworkConnectivityIntentFilter(mWifiManagerDelegate.getHasWifiPermission()); mRegistrationPolicy = policy; @@ -687,8 +689,12 @@ private void maxBandwidthChanged(NetworkState networkState) { double newMaxBandwidthMbps = getCurrentMaxBandwidthInMbps(networkState); - if (newMaxBandwidthMbps == mMaxBandwidthMbps) return; + if (newMaxBandwidthMbps == mMaxBandwidthMbps + && mConnectionType == mMaxBandwidthConnectionType) { + return; + } mMaxBandwidthMbps = newMaxBandwidthMbps; + mMaxBandwidthConnectionType = mConnectionType; mObserver.onMaxBandwidthChanged(newMaxBandwidthMbps); }
diff --git a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java index ae667b58..91f40dfe 100644 --- a/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java +++ b/net/android/javatests/src/org/chromium/net/NetworkChangeNotifierTest.java
@@ -58,6 +58,30 @@ } /** + * Listens for native notifications of max bandwidth change. + */ + private static class TestNetworkChangeNotifier extends NetworkChangeNotifier { + private TestNetworkChangeNotifier(Context context) { + super(context); + } + + @Override + void notifyObserversOfMaxBandwidthChange(double maxBandwidthMbps) { + mReceivedMaxBandwidthNotification = true; + } + + public boolean hasReceivedMaxBandwidthNotification() { + return mReceivedMaxBandwidthNotification; + } + + public void resetHasReceivedMaxBandwidthNotification() { + mReceivedMaxBandwidthNotification = false; + } + + private boolean mReceivedMaxBandwidthNotification = false; + } + + /** * Mocks out calls to the ConnectivityManager. */ private static class MockConnectivityManagerDelegate extends ConnectivityManagerDelegate { @@ -210,6 +234,7 @@ } // Network.Network(int netId) pointer. + private TestNetworkChangeNotifier mNotifier; private Constructor<Network> mNetworkConstructor; private NetworkChangeNotifierAutoDetect mReceiver; private MockConnectivityManagerDelegate mConnectivityDelegate; @@ -227,7 +252,8 @@ */ private void createTestNotifier(WatchForChanges watchForChanges) { Context context = getInstrumentation().getTargetContext(); - NetworkChangeNotifier.resetInstanceForTests(context); + mNotifier = new TestNetworkChangeNotifier(context); + NetworkChangeNotifier.resetInstanceForTests(mNotifier); if (watchForChanges == WatchForChanges.ALWAYS) { NetworkChangeNotifier.registerToReceiveNotificationsAlways(); } else { @@ -468,6 +494,49 @@ } /** + * Tests that when Chrome gets an intent indicating a change in max bandwidth, it sends a + * notification to Java observers. + */ + @UiThreadTest + @MediumTest + @Feature({"Android-AppBase"}) + public void testNetworkChangeNotifierMaxBandwidthNotifications() throws InterruptedException { + // Initialize the NetworkChangeNotifier with a connection. + mConnectivityDelegate.setActiveNetworkExists(true); + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_WIFI); + mWifiDelegate.setLinkSpeedInMbps(1); + Intent connectivityIntent = new Intent(ConnectivityManager.CONNECTIVITY_ACTION); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + assertTrue(mNotifier.hasReceivedMaxBandwidthNotification()); + mNotifier.resetHasReceivedMaxBandwidthNotification(); + + // We shouldn't be re-notified if the connection hasn't actually changed. + NetworkChangeNotifierTestObserver observer = new NetworkChangeNotifierTestObserver(); + NetworkChangeNotifier.addConnectionTypeObserver(observer); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + assertFalse(mNotifier.hasReceivedMaxBandwidthNotification()); + + // We should be notified if the bandwidth changed but not the connection type. + mWifiDelegate.setLinkSpeedInMbps(2); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + assertTrue(mNotifier.hasReceivedMaxBandwidthNotification()); + mNotifier.resetHasReceivedMaxBandwidthNotification(); + + // We should be notified if bandwidth and connection type changed. + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_ETHERNET); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + assertTrue(mNotifier.hasReceivedMaxBandwidthNotification()); + mNotifier.resetHasReceivedMaxBandwidthNotification(); + + // We should be notified if the connection type changed, but not the bandwidth. + // Note that TYPE_ETHERNET and TYPE_BLUETOOTH have the same +INFINITY max bandwidth. + // This test will fail if that changes. + mConnectivityDelegate.setNetworkType(ConnectivityManager.TYPE_BLUETOOTH); + mReceiver.onReceive(getInstrumentation().getTargetContext(), connectivityIntent); + assertTrue(mNotifier.hasReceivedMaxBandwidthNotification()); + } + + /** * Tests that when setting {@code registerToReceiveNotificationsAlways()}, * a NetworkChangeNotifierAutoDetect object is successfully created. */
diff --git a/net/android/network_change_notifier_android_unittest.cc b/net/android/network_change_notifier_android_unittest.cc index bd5df46..e07a89e 100644 --- a/net/android/network_change_notifier_android_unittest.cc +++ b/net/android/network_change_notifier_android_unittest.cc
@@ -71,7 +71,7 @@ public: NetworkChangeNotifierObserver() : notifications_count_(0) {} - // NetworkChangeNotifier::Observer: + // NetworkChangeNotifier::ConnectionTypeObserver: void OnConnectionTypeChanged( NetworkChangeNotifier::ConnectionType connection_type) override { notifications_count_++; @@ -85,6 +85,22 @@ int notifications_count_; }; +class NetworkChangeNotifierMaxBandwidthObserver + : public NetworkChangeNotifier::MaxBandwidthObserver { + public: + // NetworkChangeNotifier::MaxBandwidthObserver: + void OnMaxBandwidthChanged( + double max_bandwidth_mbps, + NetworkChangeNotifier::ConnectionType type) override { + notifications_count_++; + } + + int notifications_count() const { return notifications_count_; } + + private: + int notifications_count_ = 0; +}; + class DNSChangeObserver : public NetworkChangeNotifier::DNSObserver { public: DNSChangeObserver() @@ -206,6 +222,11 @@ base::MessageLoop::current()->RunUntilIdle(); } + void FakeMaxBandwidthChange(double max_bandwidth_mbps) { + delegate_.FakeMaxBandwidthChanged(max_bandwidth_mbps); + base::MessageLoop::current()->RunUntilIdle(); + } + void FakeNetworkChange(ChangeType change, NetworkChangeNotifier::NetworkHandle network, ConnectionType type) { @@ -268,9 +289,37 @@ other_delegate->GetCurrentConnectionType()); } -class NetworkChangeNotifierDelegateAndroidTest +class NetworkChangeNotifierAndroidTest : public BaseNetworkChangeNotifierAndroidTest { protected: + void SetUp() override { + IPAddressNumber dns_number; + ASSERT_TRUE(ParseIPLiteralToNumber("8.8.8.8", &dns_number)); + dns_config_.nameservers.push_back( + IPEndPoint(dns_number, dns_protocol::kDefaultPort)); + notifier_.reset(new NetworkChangeNotifierAndroid(&delegate_, &dns_config_)); + NetworkChangeNotifier::AddConnectionTypeObserver( + &connection_type_observer_); + NetworkChangeNotifier::AddConnectionTypeObserver( + &other_connection_type_observer_); + NetworkChangeNotifier::AddMaxBandwidthObserver(&max_bandwidth_observer_); + } + + void ForceNetworkHandlesSupportedForTesting() { + notifier_->ForceNetworkHandlesSupportedForTesting(); + } + + NetworkChangeNotifierObserver connection_type_observer_; + NetworkChangeNotifierMaxBandwidthObserver max_bandwidth_observer_; + NetworkChangeNotifierObserver other_connection_type_observer_; + NetworkChangeNotifier::DisableForTest disable_for_test_; + DnsConfig dns_config_; + scoped_ptr<NetworkChangeNotifierAndroid> notifier_; +}; + +class NetworkChangeNotifierDelegateAndroidTest + : public NetworkChangeNotifierAndroidTest { + protected: NetworkChangeNotifierDelegateAndroidTest() { delegate_.AddObserver(&delegate_observer_); delegate_.AddObserver(&other_delegate_observer_); @@ -302,31 +351,6 @@ other_delegate_observer_.type_notifications_count()); } -class NetworkChangeNotifierAndroidTest - : public BaseNetworkChangeNotifierAndroidTest { - protected: - void SetUp() override { - IPAddressNumber dns_number; - ASSERT_TRUE(ParseIPLiteralToNumber("8.8.8.8", &dns_number)); - dns_config_.nameservers.push_back( - IPEndPoint(dns_number, dns_protocol::kDefaultPort)); - notifier_.reset(new NetworkChangeNotifierAndroid(&delegate_, &dns_config_)); - NetworkChangeNotifier::AddConnectionTypeObserver( - &connection_type_observer_); - NetworkChangeNotifier::AddConnectionTypeObserver( - &other_connection_type_observer_); - } - - void ForceNetworkHandlesSupportedForTesting() { - notifier_->ForceNetworkHandlesSupportedForTesting(); - } - - NetworkChangeNotifierObserver connection_type_observer_; - NetworkChangeNotifierObserver other_connection_type_observer_; - NetworkChangeNotifier::DisableForTest disable_for_test_; - DnsConfig dns_config_; - scoped_ptr<NetworkChangeNotifierAndroid> notifier_; -}; // When a NetworkChangeNotifierAndroid is observing a // NetworkChangeNotifierDelegateAndroid for network state changes, and the @@ -370,6 +394,22 @@ EXPECT_EQ(0.0, max_bandwidth_mbps); } +TEST_F(NetworkChangeNotifierDelegateAndroidTest, MaxBandwidthCallbackNotifier) { + // The bandwidth notification should always be forwarded, even if the value + // doesn't change (because the type might have changed). + FakeMaxBandwidthChange(100.0); + EXPECT_EQ(1, delegate_observer_.bandwidth_notifications_count()); + EXPECT_EQ(1, max_bandwidth_observer_.notifications_count()); + + FakeMaxBandwidthChange(100.0); + EXPECT_EQ(2, delegate_observer_.bandwidth_notifications_count()); + EXPECT_EQ(2, max_bandwidth_observer_.notifications_count()); + + FakeMaxBandwidthChange(101.0); + EXPECT_EQ(3, delegate_observer_.bandwidth_notifications_count()); + EXPECT_EQ(3, max_bandwidth_observer_.notifications_count()); +} + TEST_F(NetworkChangeNotifierDelegateAndroidTest, MaxBandwidthNotifiedOnConnectionChange) { EXPECT_EQ(0, delegate_observer_.bandwidth_notifications_count());
diff --git a/net/android/network_change_notifier_delegate_android.cc b/net/android/network_change_notifier_delegate_android.cc index 71aa166..ff072979 100644 --- a/net/android/network_change_notifier_delegate_android.cc +++ b/net/android/network_change_notifier_delegate_android.cc
@@ -356,4 +356,10 @@ Java_NetworkChangeNotifier_fakeDefaultNetwork(env, network, type); } +void NetworkChangeNotifierDelegateAndroid::FakeMaxBandwidthChanged( + double max_bandwidth_mbps) { + JNIEnv* env = base::android::AttachCurrentThread(); + Java_NetworkChangeNotifier_fakeMaxBandwidthChanged(env, max_bandwidth_mbps); +} + } // namespace net
diff --git a/net/android/network_change_notifier_delegate_android.h b/net/android/network_change_notifier_delegate_android.h index bd200d4..a9f18d5 100644 --- a/net/android/network_change_notifier_delegate_android.h +++ b/net/android/network_change_notifier_delegate_android.h
@@ -136,6 +136,7 @@ void FakeNetworkDisconnected(NetworkHandle network); void FakeUpdateActiveNetworkList(NetworkList networks); void FakeDefaultNetwork(NetworkHandle network, ConnectionType type); + void FakeMaxBandwidthChanged(double max_bandwidth_mbps); base::ThreadChecker thread_checker_; scoped_refptr<base::ObserverListThreadSafe<Observer>> observers_;
diff --git a/net/http/http_network_session.cc b/net/http/http_network_session.cc index d3f73aa..935453e5 100644 --- a/net/http/http_network_session.cc +++ b/net/http/http_network_session.cc
@@ -114,7 +114,7 @@ quic_packet_loss_threshold(1.0f), quic_socket_receive_buffer_size(kQuicSocketReceiveBufferSize), quic_delay_tcp_race(false), - quic_store_server_configs_in_properties(false), + quic_max_server_configs_stored_in_properties(0u), quic_clock(NULL), quic_random(NULL), quic_max_packet_length(kDefaultMaxPacketSize), @@ -176,7 +176,7 @@ params.quic_threshold_timeouts_streams_open, params.quic_socket_receive_buffer_size, params.quic_delay_tcp_race, - params.quic_store_server_configs_in_properties, + params.quic_max_server_configs_stored_in_properties, params.quic_close_sessions_on_ip_change, params.quic_idle_connection_timeout_seconds, params.quic_migrate_sessions_on_network_change, @@ -239,6 +239,8 @@ http_server_properties_->SetAlternativeServiceProbabilityThreshold( params.alternative_service_probability_threshold); + http_server_properties_->SetMaxServerConfigsStoredInProperties( + params.quic_max_server_configs_stored_in_properties); } HttpNetworkSession::~HttpNetworkSession() { @@ -324,8 +326,8 @@ params_.quic_max_number_of_lossy_connections); dict->SetDouble("packet_loss_threshold", params_.quic_packet_loss_threshold); dict->SetBoolean("delay_tcp_race", params_.quic_delay_tcp_race); - dict->SetBoolean("store_server_configs_in_properties", - params_.quic_store_server_configs_in_properties); + dict->SetInteger("max_server_configs_stored_in_properties", + params_.quic_max_server_configs_stored_in_properties); dict->SetInteger("idle_connection_timeout_seconds", params_.quic_idle_connection_timeout_seconds); dict->SetBoolean("disable_preconnect_if_0rtt",
diff --git a/net/http/http_network_session.h b/net/http/http_network_session.h index 09b4d7e..9f984896 100644 --- a/net/http/http_network_session.h +++ b/net/http/http_network_session.h
@@ -154,8 +154,9 @@ // Delay starting a TCP connection when QUIC believes it can speak // 0-RTT to a server. bool quic_delay_tcp_race; - // Store server configs in HttpServerProperties, instead of the disk cache. - bool quic_store_server_configs_in_properties; + // Maximum number of server configs that are to be stored in + // HttpServerProperties, instead of the disk cache. + size_t quic_max_server_configs_stored_in_properties; // If not empty, QUIC will be used for all connections to this origin. HostPortPair origin_to_force_quic_on; // Source of time for QUIC connections. Will be owned by QuicStreamFactory.
diff --git a/net/http/http_server_properties.h b/net/http/http_server_properties.h index ec3433e2..b8ea59b2 100644 --- a/net/http/http_server_properties.h +++ b/net/http/http_server_properties.h
@@ -379,6 +379,13 @@ // Returns all persistent QuicServerInfo objects. virtual const QuicServerInfoMap& quic_server_info_map() const = 0; + // Returns the number of server configs (QuicServerInfo objects) persisted. + virtual size_t max_server_configs_stored_in_properties() const = 0; + + // Sets the number of server configs (QuicServerInfo objects) to be persisted. + virtual void SetMaxServerConfigsStoredInProperties( + size_t max_server_configs_stored_in_properties) = 0; + private: DISALLOW_COPY_AND_ASSIGN(HttpServerProperties); };
diff --git a/net/http/http_server_properties_impl.cc b/net/http/http_server_properties_impl.cc index 89754d2..662aab6 100644 --- a/net/http/http_server_properties_impl.cc +++ b/net/http/http_server_properties_impl.cc
@@ -33,7 +33,8 @@ spdy_settings_map_(SpdySettingsMap::NO_AUTO_EVICT), server_network_stats_map_(ServerNetworkStatsMap::NO_AUTO_EVICT), alternative_service_probability_threshold_(1.0), - quic_server_info_map_(kMaxQuicServersToPersist), + quic_server_info_map_(QuicServerInfoMap::NO_AUTO_EVICT), + max_server_configs_stored_in_properties_(kMaxQuicServersToPersist), weak_ptr_factory_(this) { canonical_suffixes_.push_back(".c.youtube.com"); canonical_suffixes_.push_back(".googlevideo.com"); @@ -184,7 +185,7 @@ void HttpServerPropertiesImpl::InitializeQuicServerInfoMap( QuicServerInfoMap* quic_server_info_map) { // Add the entries from persisted data. - QuicServerInfoMap temp_map(kMaxQuicServersToPersist); + QuicServerInfoMap temp_map(QuicServerInfoMap::NO_AUTO_EVICT); for (QuicServerInfoMap::reverse_iterator it = quic_server_info_map->rbegin(); it != quic_server_info_map->rend(); ++it) { temp_map.Put(it->first, it->second); @@ -676,6 +677,28 @@ return quic_server_info_map_; } +size_t HttpServerPropertiesImpl::max_server_configs_stored_in_properties() + const { + return max_server_configs_stored_in_properties_; +} + +void HttpServerPropertiesImpl::SetMaxServerConfigsStoredInProperties( + size_t max_server_configs_stored_in_properties) { + max_server_configs_stored_in_properties_ = + max_server_configs_stored_in_properties; + + // MRUCache doesn't allow the size of the cache to be changed. Thus create a + // new map with the new size and add current elements and swap the new map. + quic_server_info_map_.ShrinkToSize(max_server_configs_stored_in_properties_); + QuicServerInfoMap temp_map(max_server_configs_stored_in_properties_); + for (QuicServerInfoMap::reverse_iterator it = quic_server_info_map_.rbegin(); + it != quic_server_info_map_.rend(); ++it) { + temp_map.Put(it->first, it->second); + } + + quic_server_info_map_.Swap(temp_map); +} + void HttpServerPropertiesImpl::SetAlternativeServiceProbabilityThreshold( double threshold) { alternative_service_probability_threshold_ = threshold;
diff --git a/net/http/http_server_properties_impl.h b/net/http/http_server_properties_impl.h index a169362..b8678be 100644 --- a/net/http/http_server_properties_impl.h +++ b/net/http/http_server_properties_impl.h
@@ -134,6 +134,9 @@ const std::string& server_info) override; const std::string* GetQuicServerInfo(const QuicServerId& server_id) override; const QuicServerInfoMap& quic_server_info_map() const override; + size_t max_server_configs_stored_in_properties() const override; + void SetMaxServerConfigsStoredInProperties( + size_t max_server_configs_stored_in_properties) override; private: friend class HttpServerPropertiesImplPeer; @@ -187,6 +190,7 @@ double alternative_service_probability_threshold_; QuicServerInfoMap quic_server_info_map_; + size_t max_server_configs_stored_in_properties_; base::WeakPtrFactory<HttpServerPropertiesImpl> weak_ptr_factory_;
diff --git a/net/http/http_server_properties_impl_unittest.cc b/net/http/http_server_properties_impl_unittest.cc index cf24fc7..a4e8131 100644 --- a/net/http/http_server_properties_impl_unittest.cc +++ b/net/http/http_server_properties_impl_unittest.cc
@@ -1389,6 +1389,11 @@ HostPortPair google_server("www.google.com", 443); QuicServerId google_quic_server_id(google_server, PRIVACY_MODE_ENABLED); + EXPECT_EQ(QuicServerInfoMap::NO_AUTO_EVICT, + impl_.quic_server_info_map().max_size()); + impl_.SetMaxServerConfigsStoredInProperties(10); + EXPECT_EQ(10u, impl_.quic_server_info_map().max_size()); + // Check empty map. QuicServerInfoMap init_quic_server_info_map(QuicServerInfoMap::NO_AUTO_EVICT); impl_.InitializeQuicServerInfoMap(&init_quic_server_info_map); @@ -1449,6 +1454,22 @@ ++memory_map_it; EXPECT_EQ(memory_map_it->first, mail_quic_server_id); EXPECT_EQ(mail_server_info, memory_map_it->second); + + // Shrink the size of |quic_server_info_map| and verify the MRU order is + // maintained. + impl_.SetMaxServerConfigsStoredInProperties(2); + EXPECT_EQ(2u, impl_.quic_server_info_map().max_size()); + + const QuicServerInfoMap& memory_map1 = impl_.quic_server_info_map(); + ASSERT_EQ(2u, memory_map1.size()); + QuicServerInfoMap::const_iterator memory_map1_it = memory_map1.begin(); + EXPECT_EQ(memory_map1_it->first, docs_quic_server_id); + EXPECT_EQ(new_docs_server_info, memory_map1_it->second); + ++memory_map1_it; + EXPECT_EQ(memory_map1_it->first, google_quic_server_id); + EXPECT_EQ(google_server_info, memory_map1_it->second); + // |QuicServerInfo| for |mail_quic_server_id| shouldn't be there. + EXPECT_EQ(nullptr, impl_.GetQuicServerInfo(mail_quic_server_id)); } TEST_F(QuicServerInfoServerPropertiesTest, SetQuicServerInfo) {
diff --git a/net/http/http_server_properties_manager.cc b/net/http/http_server_properties_manager.cc index 70dc3e8..f7493ff 100644 --- a/net/http/http_server_properties_manager.cc +++ b/net/http/http_server_properties_manager.cc
@@ -406,6 +406,20 @@ return http_server_properties_impl_->quic_server_info_map(); } +size_t HttpServerPropertiesManager::max_server_configs_stored_in_properties() + const { + DCHECK(network_task_runner_->RunsTasksOnCurrentThread()); + return http_server_properties_impl_ + ->max_server_configs_stored_in_properties(); +} + +void HttpServerPropertiesManager::SetMaxServerConfigsStoredInProperties( + size_t max_server_configs_stored_in_properties) { + DCHECK(network_task_runner_->RunsTasksOnCurrentThread()); + return http_server_properties_impl_->SetMaxServerConfigsStoredInProperties( + max_server_configs_stored_in_properties); +} + // // Update the HttpServerPropertiesImpl's cache with data from preferences. // @@ -497,7 +511,7 @@ scoped_ptr<ServerNetworkStatsMap> server_network_stats_map( new ServerNetworkStatsMap(kMaxServerNetworkStatsHostsToPersist)); scoped_ptr<QuicServerInfoMap> quic_server_info_map( - new QuicServerInfoMap(kMaxQuicServersToPersist)); + new QuicServerInfoMap(QuicServerInfoMap::NO_AUTO_EVICT)); if (version < 4) { if (!AddServersData(*servers_dict, spdy_servers.get(), @@ -980,7 +994,8 @@ const QuicServerInfoMap& main_quic_server_info_map = http_server_properties_impl_->quic_server_info_map(); if (main_quic_server_info_map.size() > 0) { - quic_server_info_map = new QuicServerInfoMap(kMaxQuicServersToPersist); + quic_server_info_map = + new QuicServerInfoMap(max_server_configs_stored_in_properties()); for (const std::pair<const QuicServerId, std::string>& entry : main_quic_server_info_map) { quic_server_info_map->Put(entry.first, entry.second);
diff --git a/net/http/http_server_properties_manager.h b/net/http/http_server_properties_manager.h index 6779a21..b08ae16 100644 --- a/net/http/http_server_properties_manager.h +++ b/net/http/http_server_properties_manager.h
@@ -134,6 +134,9 @@ const std::string& server_info) override; const std::string* GetQuicServerInfo(const QuicServerId& server_id) override; const QuicServerInfoMap& quic_server_info_map() const override; + size_t max_server_configs_stored_in_properties() const override; + void SetMaxServerConfigsStoredInProperties( + size_t max_server_configs_stored_in_properties) override; protected: // The location where ScheduleUpdatePrefsOnNetworkThread was called.
diff --git a/net/http/http_server_properties_manager_unittest.cc b/net/http/http_server_properties_manager_unittest.cc index 4256ae4..49d19db1 100644 --- a/net/http/http_server_properties_manager_unittest.cc +++ b/net/http/http_server_properties_manager_unittest.cc
@@ -276,7 +276,9 @@ http_server_properties_dict->SetWithoutPathExpansion("supports_quic", supports_quic); - // Set quic_server_info for www.google.com:80 and mail.google.com:80. + // Set quic_server_info for www.google.com:80, mail.google.com:80 and + // play.google.com:80 and verify the MRU. + http_server_props_manager_->SetMaxServerConfigsStoredInProperties(3); base::DictionaryValue* quic_servers_dict = new base::DictionaryValue; base::DictionaryValue* quic_server_pref_dict1 = new base::DictionaryValue; std::string quic_server_info1("quic_server_info1"); @@ -286,6 +288,10 @@ std::string quic_server_info2("quic_server_info2"); quic_server_pref_dict2->SetStringWithoutPathExpansion("server_info", quic_server_info2); + base::DictionaryValue* quic_server_pref_dict3 = new base::DictionaryValue; + std::string quic_server_info3("quic_server_info3"); + quic_server_pref_dict3->SetStringWithoutPathExpansion("server_info", + quic_server_info3); // Set the quic_server_info1 for www.google.com server. QuicServerId google_quic_server_id("www.google.com", 80); quic_servers_dict->SetWithoutPathExpansion(google_quic_server_id.ToString(), @@ -294,6 +300,10 @@ QuicServerId mail_quic_server_id("mail.google.com", 80); quic_servers_dict->SetWithoutPathExpansion(mail_quic_server_id.ToString(), quic_server_pref_dict2); + // Set the quic_server_info3 for play.google.com server. + QuicServerId play_quic_server_id("play.google.com", 80); + quic_servers_dict->SetWithoutPathExpansion(play_quic_server_id.ToString(), + quic_server_pref_dict3); http_server_properties_dict->SetWithoutPathExpansion("quic_servers", quic_servers_dict); @@ -375,6 +385,17 @@ google_quic_server_id)); EXPECT_EQ(quic_server_info2, *http_server_props_manager_->GetQuicServerInfo( mail_quic_server_id)); + EXPECT_EQ(quic_server_info3, *http_server_props_manager_->GetQuicServerInfo( + play_quic_server_id)); + + // Verify the MRU order. + http_server_props_manager_->SetMaxServerConfigsStoredInProperties(2); + EXPECT_EQ(nullptr, http_server_props_manager_->GetQuicServerInfo( + google_quic_server_id)); + EXPECT_EQ(quic_server_info2, *http_server_props_manager_->GetQuicServerInfo( + mail_quic_server_id)); + EXPECT_EQ(quic_server_info3, *http_server_props_manager_->GetQuicServerInfo( + play_quic_server_id)); } TEST_P(HttpServerPropertiesManagerTest, BadCachedHostPortPair) {
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h index 22c73439..a643ba9 100644 --- a/net/http/transport_security_state_static.h +++ b/net/http/transport_security_state_static.h
@@ -742,558 +742,558 @@ 0x0b, 0xf7, 0xed, 0x0c, 0x0d, 0xef, 0x05, 0x0e, 0x02, 0x0f, 0xeb, 0xe2, 0xe3, 0x11, 0xe1, 0x12, 0x13, 0xff, 0xec, 0xf3, 0xe5, 0x15, 0xb9, 0xb5, 0xb8, 0x17, 0xb2, 0x18, 0xb4, 0xf1, 0x19, 0x1a, 0xfa, 0x1b, 0x1c, 0xf6, - 0xad, 0xae, 0x1d, 0x1e, 0x1f, 0xee, 0xe8, 0xf0, 0xf4, 0x21, 0x20, 0x22, + 0x1d, 0xe8, 0x1e, 0xee, 0xad, 0xae, 0x20, 0xf0, 0xf4, 0x21, 0x1f, 0x22, 0x16, 0x23, 0x14, 0x24, 0x10, 0x25, }; static const uint8_t kPreloadedHSTSData[] = { - 0xfe, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x11, 0x2a, 0xef, 0xc0, 0x72, 0xf4, - 0x85, 0xac, 0xe5, 0xdf, 0x78, 0xe5, 0xff, 0xf4, 0x76, 0x24, 0x2e, 0xaf, - 0xd2, 0x8c, 0xf1, 0xcb, 0x9f, 0x67, 0x2a, 0x47, 0xfa, 0x11, 0x84, 0x4f, - 0xbf, 0xd8, 0xd8, 0xc7, 0xba, 0x87, 0x2f, 0xfe, 0x03, 0x3a, 0x39, 0xf7, + 0xfe, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x11, 0x2a, 0xef, 0xc0, 0x72, 0xf4, + 0x85, 0xac, 0xe5, 0xdc, 0xf8, 0xe5, 0xff, 0xf4, 0x76, 0x24, 0x2e, 0xaf, + 0x32, 0x8c, 0xf1, 0xcb, 0x9f, 0x67, 0x2a, 0x47, 0xfa, 0x11, 0x84, 0x4f, + 0xbf, 0xd8, 0xd8, 0xc7, 0xba, 0x87, 0x2f, 0xfe, 0x03, 0x3a, 0x39, 0xcf, 0x85, 0xfa, 0x72, 0xff, 0xfd, 0x21, 0x7f, 0x3b, 0x37, 0x01, 0x8e, 0xc4, 0x8e, 0x56, 0xd1, 0x2e, 0xa2, 0x25, 0xd9, 0xb3, 0x97, 0x9d, 0xd6, 0x68, 0x8b, 0x55, 0x23, 0xe2, 0xc2, 0x45, 0x8b, 0x5d, 0xad, 0x9c, 0xad, 0x1e, - 0x2e, 0xcb, 0xae, 0xf7, 0x8e, 0x5f, 0xff, 0x3f, 0x70, 0x75, 0xac, 0xfa, + 0x2e, 0xcb, 0xae, 0xf7, 0x8e, 0x5f, 0xff, 0x3f, 0x70, 0x75, 0xac, 0xe6, 0x5e, 0x46, 0x1c, 0xa9, 0x1f, 0x30, 0x05, 0xee, 0x5c, 0x1c, 0xbf, 0xf0, 0x1d, 0x41, 0xc9, 0xb5, 0x0d, 0x9c, 0xb8, 0x5b, 0x39, 0x58, 0x7d, 0xbd, 0x16, 0x6d, 0x02, 0xff, 0xf4, 0xa3, 0x07, 0xc0, 0x70, 0xee, 0x15, 0x39, - 0x7f, 0x04, 0x61, 0x6c, 0x01, 0xcb, 0xfa, 0x3e, 0x0e, 0x9e, 0x47, 0x2f, - 0x08, 0x60, 0xe5, 0xc1, 0x09, 0xcb, 0xfe, 0x6c, 0x53, 0x68, 0x3f, 0x48, + 0x7f, 0x04, 0x61, 0x6c, 0x01, 0xcb, 0xfa, 0x39, 0x0e, 0x9e, 0x47, 0x2f, + 0x08, 0x60, 0xe5, 0xc1, 0x09, 0xcb, 0xfe, 0x6c, 0x53, 0x68, 0x3c, 0xc8, 0xe5, 0xc9, 0x39, 0xcb, 0xfe, 0xf0, 0x34, 0xfb, 0x7c, 0xe9, 0xca, 0x09, 0xe7, 0xa0, 0xbd, 0x62, 0x30, 0x10, 0x5d, 0xe1, 0x11, 0x7f, 0xf2, 0xf5, 0x0a, 0xc0, 0xfb, 0x85, 0x70, 0xa6, 0xa4, 0xe5, 0xff, 0x76, 0x35, 0x9d, - 0x4f, 0x84, 0xe5, 0xfd, 0xd1, 0x03, 0xaa, 0xb3, 0x94, 0x13, 0xe6, 0x43, + 0x4e, 0x44, 0xe5, 0xfd, 0xd1, 0x03, 0xaa, 0xb3, 0x94, 0x13, 0xe6, 0x43, 0x8b, 0x87, 0x67, 0x2a, 0x11, 0xe7, 0x90, 0xbc, 0x12, 0x1b, 0xfe, 0x5a, 0x9e, 0x49, 0x37, 0x9d, 0x39, 0x7f, 0xe8, 0xef, 0x62, 0x5e, 0x55, 0x34, - 0x72, 0xcd, 0x67, 0x2f, 0xb5, 0xbc, 0x6c, 0xe5, 0xf0, 0xc7, 0xca, 0x41, + 0x72, 0xcd, 0x67, 0x2f, 0xb5, 0xbc, 0x6c, 0xe5, 0xf0, 0xc7, 0x2a, 0x41, 0xb7, 0xc1, 0x4a, 0x9d, 0x15, 0xa2, 0xed, 0x7f, 0x96, 0x9b, 0xd6, 0xa2, - 0x47, 0x2f, 0xff, 0xd9, 0xfe, 0xd3, 0xe6, 0xf1, 0x70, 0x20, 0x79, 0x1c, + 0x47, 0x2f, 0xff, 0xd9, 0xfe, 0xd3, 0x96, 0xf1, 0x70, 0x20, 0x79, 0x1c, 0xbf, 0xfa, 0x30, 0x7d, 0xbf, 0x66, 0x37, 0xb3, 0x95, 0x09, 0xeb, 0xa4, - 0x3a, 0x3a, 0x46, 0x26, 0x7e, 0x56, 0xbb, 0x3e, 0x29, 0x68, 0x29, 0x6f, - 0xf4, 0x69, 0xff, 0x17, 0xbf, 0xde, 0xcd, 0x7e, 0xc4, 0xd9, 0x4e, 0x66, + 0x3a, 0x3a, 0x46, 0x26, 0x7e, 0x56, 0xbb, 0x39, 0x29, 0x68, 0x29, 0x6f, + 0xf4, 0x69, 0xff, 0x17, 0xbf, 0xde, 0xcd, 0x7e, 0xc4, 0xd9, 0x4f, 0xa6, 0xa6, 0xfe, 0x97, 0x53, 0x8e, 0x4c, 0x72, 0xa0, 0xfd, 0x9d, 0x1a, 0xfe, 0xea, 0x2e, 0x18, 0x87, 0x2f, 0xf4, 0x7f, 0x3b, 0xca, 0x1a, 0xce, 0x58, - 0x60, 0xf8, 0xc4, 0xb2, 0xdc, 0xda, 0x96, 0x50, 0x07, 0x0b, 0x0c, 0x44, - 0x27, 0x27, 0x2e, 0xc8, 0xdc, 0x15, 0x84, 0x42, 0xe1, 0x1f, 0xf1, 0x7a, + 0x60, 0xf8, 0xc4, 0xb2, 0xdf, 0x5a, 0x96, 0x50, 0x07, 0x0b, 0x0c, 0x44, + 0x27, 0x27, 0x2e, 0xc8, 0xdc, 0x15, 0x84, 0x42, 0xe1, 0x1f, 0xc9, 0x7a, 0x24, 0xcc, 0x5b, 0xa2, 0xee, 0xc3, 0x6c, 0x63, 0x25, 0xdc, 0xa0, 0x96, - 0x91, 0x89, 0xa9, 0x08, 0x3b, 0xff, 0xff, 0x9d, 0x9c, 0xd3, 0x5a, 0x06, + 0x91, 0x89, 0xa9, 0x08, 0x3b, 0xff, 0xff, 0x9d, 0x9f, 0x53, 0x5a, 0x06, 0xb5, 0x03, 0x8a, 0xa7, 0x7b, 0x8a, 0x1c, 0xbf, 0xfd, 0xc2, 0x95, 0x6d, - 0xae, 0x70, 0xf0, 0xdc, 0xb9, 0x75, 0xa1, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, + 0xae, 0x70, 0xf0, 0xdf, 0x3e, 0x75, 0xa1, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x51, 0x2f, 0xce, 0x32, 0x46, 0x1c, 0xad, 0x1e, 0xa3, 0x0b, 0xaf, 0xbb, 0x9a, 0xc3, 0x97, 0x92, 0x6e, 0x03, 0x95, 0x07, 0x83, 0xd2, 0x1b, 0xf2, - 0xdf, 0xb1, 0xd3, 0x97, 0xff, 0xf0, 0x05, 0xd5, 0xe5, 0xe5, 0x60, 0x65, + 0xdf, 0xb1, 0xd3, 0x97, 0xff, 0xf0, 0x05, 0xd5, 0xf9, 0xe5, 0x60, 0x65, 0x9d, 0x46, 0x1c, 0xbf, 0xff, 0x7f, 0x29, 0xf8, 0x54, 0x35, 0x73, 0xaf, - 0x5c, 0xb9, 0x75, 0xa1, 0xcb, 0xff, 0xf8, 0x02, 0xea, 0xf2, 0xf2, 0xb0, + 0x5f, 0x3e, 0x75, 0xa1, 0xcb, 0xff, 0xf8, 0x02, 0xea, 0xfc, 0xf2, 0xb0, 0x32, 0xce, 0xa3, 0x0e, 0x5f, 0x6b, 0x58, 0xd0, 0xe5, 0x31, 0x10, 0x2e, - 0xbb, 0x7f, 0xfe, 0x79, 0x0c, 0x6f, 0x3e, 0x58, 0xbe, 0x7c, 0xb3, 0x96, - 0xe7, 0x25, 0x64, 0x79, 0x0b, 0x85, 0xb1, 0xa1, 0x0b, 0x09, 0xfa, 0xbb, - 0xb8, 0x76, 0xf1, 0x22, 0xbf, 0xf0, 0x71, 0x9c, 0xda, 0x60, 0xa7, 0x8e, + 0xbb, 0x7f, 0xfe, 0x79, 0x0c, 0x6f, 0x39, 0x58, 0xbe, 0x72, 0xb3, 0x96, + 0xfb, 0x25, 0x64, 0x79, 0x0b, 0x85, 0xb1, 0xa1, 0x0b, 0x09, 0xfa, 0xbb, + 0xb8, 0x76, 0xf1, 0x22, 0xbf, 0xf0, 0x71, 0x9f, 0x5a, 0x60, 0xa7, 0x8e, 0x5e, 0xc6, 0xf0, 0xe5, 0xe0, 0x44, 0xe7, 0x2f, 0xec, 0x9c, 0x31, 0x81, 0x39, 0x7c, 0x1e, 0xa4, 0xc7, 0x2b, 0x0f, 0x41, 0xcb, 0x6f, 0x36, 0xfd, 0x39, 0x74, 0x04, 0xe5, 0x41, 0xb3, 0xe8, 0xed, 0xfe, 0x88, 0x41, 0x10, 0x35, 0x9c, 0xb9, 0xc0, 0x72, 0xfe, 0x79, 0xf4, 0xef, 0xe3, 0x97, 0xdd, - 0x4e, 0xf3, 0xe1, 0x13, 0x72, 0x08, 0xe2, 0xad, 0xb3, 0x29, 0xf4, 0x81, + 0x4e, 0xfd, 0xe1, 0x13, 0x72, 0x08, 0xe2, 0xad, 0xb3, 0x29, 0xf4, 0x81, 0xb3, 0x36, 0x82, 0xd7, 0xed, 0x2d, 0xdd, 0x66, 0x8a, 0xf5, 0x7e, 0x4e, 0x05, 0x82, 0x73, 0x97, 0x44, 0x8e, 0x5d, 0x1f, 0x9c, 0xbf, 0xa7, 0x51, 0xa3, 0x8f, 0xe7, 0x2f, 0xfc, 0xe3, 0xfe, 0x7a, 0x05, 0x3f, 0x39, 0x50, - 0x7d, 0xed, 0x0c, 0xad, 0xcf, 0x13, 0x1f, 0xd1, 0xa3, 0x96, 0x7e, 0x2c, - 0xa4, 0x21, 0xaf, 0xfe, 0xe6, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x12, - 0x32, 0xff, 0xf7, 0x36, 0x3c, 0xb9, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xf0, - 0xbf, 0xfd, 0xcd, 0x8f, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x3f, 0xaf, - 0xff, 0x73, 0x63, 0xcb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x50, 0xcb, 0xff, - 0x98, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x14, 0x42, 0xff, 0xd2, 0xe6, - 0x0d, 0xf2, 0x8d, 0xc4, 0x8e, 0x57, 0x34, 0x4a, 0xc2, 0x95, 0xff, 0xa6, - 0x4e, 0xfd, 0x9e, 0x0e, 0x30, 0xe5, 0xf6, 0x7b, 0x3f, 0x39, 0x7e, 0x10, - 0x3c, 0xb6, 0x72, 0xf0, 0xbf, 0x31, 0x3c, 0x9f, 0x11, 0x5f, 0xb4, 0xb7, + 0x7d, 0xed, 0x0c, 0xad, 0xf7, 0x13, 0x1f, 0xd1, 0xa3, 0x96, 0x7e, 0x2c, + 0xa4, 0x21, 0xaf, 0xfe, 0xfa, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, + 0x32, 0xff, 0xf7, 0xd6, 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xf0, + 0xbf, 0xfd, 0xf5, 0x8f, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x3f, 0xaf, + 0xff, 0x7d, 0x63, 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x50, 0xcb, 0xff, + 0x98, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x14, 0x42, 0xff, 0xd2, 0xfa, + 0x0d, 0xfc, 0x8d, 0xc4, 0x8e, 0x57, 0xd4, 0x4a, 0xc2, 0x95, 0xff, 0xa6, + 0x4e, 0xf3, 0x9e, 0x0e, 0x30, 0xe5, 0xf6, 0x7b, 0x3f, 0x39, 0x7e, 0x10, + 0x3c, 0xb6, 0x72, 0xf0, 0xbf, 0xd1, 0x3c, 0x9f, 0x11, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x29, 0x15, 0xff, 0xdd, 0xe2, 0xfa, 0xdb, 0xf7, 0x71, 0x39, - 0xcb, 0xff, 0x9f, 0xed, 0xf5, 0xb8, 0xff, 0x92, 0x8c, 0x39, 0x7f, 0xd1, - 0x28, 0xd4, 0xf1, 0xa9, 0xce, 0x5e, 0x79, 0x73, 0xc4, 0xc0, 0x1c, 0xd3, - 0xf4, 0x71, 0x4b, 0xbf, 0xff, 0xb8, 0xf3, 0x51, 0x79, 0xe8, 0x1f, 0x6d, - 0xc4, 0x18, 0x72, 0xff, 0xf4, 0xb9, 0xe9, 0xff, 0x7f, 0x26, 0xb1, 0x87, - 0x2f, 0xfd, 0xff, 0x3d, 0x83, 0x5f, 0xf2, 0x0c, 0xc7, 0x2f, 0xe9, 0x67, - 0x7a, 0xf2, 0x39, 0x7f, 0xff, 0x60, 0x7b, 0x0a, 0x73, 0xf0, 0xbf, 0xfb, - 0xdc, 0x7e, 0x52, 0xdc, 0xe1, 0x5c, 0x4a, 0xe1, 0x12, 0xc8, 0xcc, 0xfa, + 0xcb, 0xff, 0x9f, 0x9d, 0xf5, 0xb8, 0xff, 0xe2, 0x8c, 0x39, 0x7f, 0xd1, + 0x28, 0xd4, 0xf1, 0xa9, 0xce, 0x5e, 0x79, 0x7d, 0xc4, 0xc0, 0x1c, 0xd3, + 0xf4, 0x71, 0x4b, 0xbf, 0xff, 0xb8, 0xfd, 0x51, 0x79, 0xe8, 0x1f, 0x6d, + 0xc4, 0x18, 0x72, 0xff, 0xf4, 0xbe, 0xe9, 0xff, 0x7f, 0x26, 0xb1, 0x87, + 0x2f, 0xfd, 0xff, 0xdd, 0x83, 0x5f, 0xfc, 0x0c, 0xc7, 0x2f, 0xe9, 0x67, + 0x7a, 0xf2, 0x39, 0x7f, 0xff, 0x60, 0x7b, 0x0a, 0x7d, 0xf0, 0xbf, 0xfb, + 0xdc, 0x7e, 0x52, 0xdf, 0x61, 0x5c, 0x4a, 0xe1, 0x12, 0xc8, 0xcc, 0xfa, 0x9e, 0xeb, 0xdf, 0xa6, 0x79, 0x21, 0xa1, 0x6d, 0xff, 0xf7, 0x63, 0xa8, 0xae, 0xf7, 0x83, 0xfb, 0x4c, 0x39, 0x7c, 0xb7, 0x75, 0x9a, 0x25, 0x05, 0xff, 0xa3, 0xf6, 0x3c, 0xbb, 0x0f, 0xa3, 0x95, 0x24, 0x5f, 0x69, 0x48, 0x4b, 0xaf, 0xff, 0x0b, 0xfb, 0x6a, 0x08, 0x24, 0x38, 0xc3, 0x97, 0xdb, - 0x70, 0xe1, 0xcb, 0xff, 0xcf, 0x3a, 0x6b, 0x49, 0xf4, 0xbc, 0xff, 0x1c, - 0xbe, 0xe6, 0xf2, 0xe7, 0x88, 0xe5, 0x61, 0x7e, 0xd2, 0x5a, 0x10, 0xd4, + 0x70, 0xe1, 0xcb, 0xff, 0xcf, 0x3a, 0x6b, 0x49, 0xcc, 0xbc, 0xfc, 0x9c, + 0xbe, 0xfa, 0xf2, 0xfb, 0x88, 0xe5, 0x61, 0x7e, 0xd2, 0x5a, 0x10, 0xd4, 0xed, 0xda, 0xe4, 0xa9, 0x48, 0x21, 0x8c, 0x99, 0x72, 0xe5, 0xd2, 0x10, 0xad, 0x71, 0xd9, 0xea, 0x3a, 0x76, 0x2c, 0x75, 0x53, 0xf5, 0xae, 0x1d, - 0x6b, 0x70, 0xef, 0x04, 0xba, 0xde, 0x09, 0x45, 0x57, 0xff, 0xb9, 0xb1, - 0xe5, 0xcf, 0x34, 0xb7, 0x75, 0x9a, 0x27, 0x35, 0xff, 0xee, 0x6c, 0x79, - 0x73, 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x25, 0x7f, 0xc0, 0x7d, 0x49, 0xa8, + 0x6b, 0x70, 0xef, 0x04, 0xba, 0xde, 0x09, 0x45, 0x57, 0xff, 0xbe, 0xb1, + 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x27, 0x35, 0xff, 0xef, 0xac, 0x79, + 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x25, 0x7f, 0xc0, 0x7d, 0x49, 0xa8, 0xf1, 0xfd, 0x0e, 0x5f, 0x20, 0xc3, 0x0e, 0x5f, 0xc9, 0xb9, 0xa4, 0x9f, - 0x9c, 0xbf, 0xd1, 0x3a, 0x8d, 0x1c, 0x7f, 0x39, 0x74, 0xb9, 0x85, 0x19, - 0x18, 0x85, 0xd2, 0x05, 0x0b, 0xef, 0xff, 0x73, 0xd8, 0xe7, 0xf1, 0xfe, + 0x9c, 0xbf, 0xd1, 0x3a, 0x8d, 0x1c, 0x7f, 0x39, 0x74, 0xbe, 0x85, 0x19, + 0x18, 0x85, 0xd2, 0x05, 0x0b, 0xef, 0xff, 0x7d, 0xd8, 0xe7, 0xf1, 0xfe, 0xb5, 0x0d, 0x9c, 0xad, 0x22, 0x67, 0xf4, 0xba, 0xd2, 0xa3, 0x9d, 0xad, 0x02, 0x3b, 0xbb, 0xf6, 0x96, 0xee, 0xb3, 0x44, 0x38, 0xbf, 0x80, 0xbd, - 0x24, 0x09, 0xcb, 0x73, 0xc3, 0xe0, 0xe9, 0xa5, 0xff, 0x46, 0xb1, 0x7d, - 0x8f, 0xa4, 0x72, 0xff, 0xe1, 0x75, 0x57, 0xd4, 0xd6, 0xa1, 0xb3, 0x97, + 0x24, 0x09, 0xcb, 0x7d, 0xc3, 0xe0, 0xe9, 0xa5, 0xff, 0x46, 0xb1, 0x7d, + 0x8e, 0x64, 0x72, 0xff, 0xe1, 0x75, 0x57, 0xd4, 0xd6, 0xa1, 0xb3, 0x97, 0xcb, 0x77, 0x59, 0xa2, 0x2f, 0x5f, 0x85, 0xff, 0x7d, 0x9c, 0xbf, 0x64, 0xd2, 0x7d, 0x9c, 0xad, 0x1f, 0xef, 0x8b, 0x94, 0x27, 0xbf, 0xb0, 0x3d, 0xcf, 0xdc, 0xe5, 0xf4, 0x03, 0x87, 0xd9, 0xca, 0xd9, 0xea, 0x36, 0x5b, 0x70, 0xce, 0x72, 0xff, 0xbc, 0x30, 0xc5, 0x03, 0xd8, 0x39, 0x50, 0x7a, - 0x08, 0x2f, 0x76, 0xfe, 0x39, 0x7d, 0xe9, 0x42, 0xa5, 0x29, 0x86, 0xed, - 0xc6, 0x2f, 0xcf, 0xf0, 0x1f, 0xc7, 0x2f, 0xcf, 0x3f, 0xb3, 0xa7, 0x2d, - 0xce, 0x75, 0x57, 0xa1, 0x39, 0xc8, 0x61, 0x4d, 0x08, 0x4e, 0xb9, 0x8a, - 0xd8, 0x08, 0x1a, 0x14, 0x5f, 0xff, 0xff, 0x0b, 0xf3, 0xc0, 0x70, 0xe8, - 0xaa, 0x7b, 0xb8, 0x92, 0xdf, 0x2c, 0x56, 0x24, 0x72, 0xfd, 0x9b, 0x60, - 0x60, 0xe5, 0xff, 0x9e, 0x5c, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0x64, 0x5b, - 0x9a, 0xd1, 0xf1, 0xa8, 0x42, 0xb0, 0x9e, 0xf7, 0xb1, 0x87, 0x2e, 0xeb, - 0x0e, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x2d, 0xe5, 0xb9, 0xc1, 0xf3, 0x84, - 0x73, 0x05, 0xef, 0xff, 0x73, 0x63, 0xcb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, + 0x08, 0x2f, 0x76, 0xf9, 0x39, 0x7d, 0xe9, 0x42, 0xa5, 0x29, 0x86, 0xed, + 0xc6, 0x2f, 0xcf, 0xc8, 0x1f, 0xc7, 0x2f, 0xcf, 0x3f, 0xb3, 0xa7, 0x2d, + 0xf6, 0x75, 0x57, 0xa1, 0x39, 0xc8, 0x61, 0x4d, 0x08, 0x4e, 0xb9, 0x8a, + 0xd8, 0x08, 0x1a, 0x14, 0x5f, 0xff, 0xff, 0x0b, 0xfd, 0xc0, 0x70, 0xe8, + 0xaa, 0x7b, 0xb8, 0x92, 0xdf, 0xcc, 0x56, 0x24, 0x72, 0xfd, 0x9b, 0x60, + 0x60, 0xe5, 0xff, 0x9e, 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x64, 0x5b, + 0xea, 0xd1, 0xf1, 0xa8, 0x42, 0xb0, 0x9e, 0xf7, 0xb1, 0x87, 0x2e, 0xeb, + 0x0e, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x2d, 0xe5, 0xbe, 0xc1, 0xf3, 0x84, + 0x73, 0x05, 0xef, 0xff, 0x7d, 0x63, 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x52, 0x6b, 0x9a, 0xa6, 0xac, 0xe5, 0xfd, 0x9e, 0x18, 0x86, 0x1c, 0xbf, - 0xbe, 0xfd, 0x4d, 0x3f, 0xe7, 0x2e, 0xef, 0x3e, 0x10, 0xff, 0xba, 0x42, + 0xb9, 0xfd, 0x4d, 0x3f, 0xe7, 0x2e, 0xef, 0xde, 0x10, 0xff, 0xba, 0x42, 0xe5, 0x75, 0x0b, 0xca, 0xf2, 0x95, 0xcd, 0x91, 0xbf, 0xee, 0x14, 0x9c, - 0x4d, 0x54, 0x86, 0xc5, 0xfe, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x10, 0xea, + 0x4d, 0x54, 0x86, 0xc5, 0xfe, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x10, 0xea, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x2c, 0x2f, 0xb3, 0xf6, 0x21, 0xcb, 0xf7, - 0x36, 0x3c, 0xb9, 0xe1, 0xeb, 0x34, 0x34, 0xbf, 0xdc, 0xf3, 0x4b, 0x77, - 0x59, 0xa2, 0x30, 0x5f, 0xee, 0x60, 0x96, 0x6d, 0xf6, 0x72, 0xff, 0xfc, - 0xff, 0xb4, 0xce, 0x62, 0xfe, 0x96, 0x7b, 0x02, 0x72, 0x85, 0x11, 0xbb, - 0x35, 0xbe, 0xe7, 0x2c, 0xd9, 0xcb, 0xff, 0xfe, 0x96, 0xf9, 0xaf, 0xaf, + 0xd6, 0x3c, 0xbe, 0xe1, 0xeb, 0x34, 0x34, 0xbf, 0xdf, 0x73, 0x4b, 0x77, + 0x59, 0xa2, 0x30, 0x5f, 0xef, 0xa0, 0x96, 0x6d, 0xf6, 0x72, 0xff, 0xfc, + 0xff, 0xb4, 0xcf, 0xa2, 0xfe, 0x96, 0x7b, 0x02, 0x72, 0x85, 0x11, 0xbb, + 0x35, 0xbe, 0xfb, 0x2c, 0xd9, 0xcb, 0xff, 0xfe, 0x96, 0xfe, 0xaf, 0xaf, 0x32, 0xfb, 0x9a, 0x6a, 0x7b, 0x33, 0x36, 0x72, 0xfd, 0x9e, 0xfe, 0x16, 0x72, 0xff, 0xf4, 0x79, 0x3f, 0x89, 0x07, 0xb0, 0x2b, 0x39, 0x7e, 0xd2, - 0xdd, 0xd6, 0x68, 0x8f, 0x57, 0xdb, 0x7f, 0xb8, 0x9c, 0xba, 0x5c, 0xf0, - 0xf6, 0x7c, 0x69, 0x7f, 0xff, 0x3f, 0x31, 0x06, 0x77, 0x07, 0xfc, 0x1f, - 0x77, 0x0e, 0x5b, 0x9f, 0xc9, 0xe2, 0xcc, 0xe5, 0xa2, 0x87, 0x85, 0x10, + 0xdd, 0xd6, 0x68, 0x8f, 0x57, 0xdb, 0x7e, 0x78, 0x9c, 0xba, 0x5f, 0x70, + 0xf6, 0x7c, 0x69, 0x7f, 0xff, 0x3f, 0xd1, 0x06, 0x77, 0x07, 0xfc, 0x1f, + 0x77, 0x0e, 0x5b, 0xef, 0x29, 0xe2, 0xcc, 0xe5, 0xa2, 0x87, 0x85, 0x10, 0x97, 0xdf, 0xb4, 0xb7, 0x75, 0x9a, 0x2c, 0x35, 0xfe, 0x90, 0xc6, 0x6f, - 0x04, 0xe5, 0xc9, 0x23, 0x96, 0xe7, 0x87, 0xf5, 0xf1, 0xa7, 0xe6, 0x17, - 0xf7, 0x86, 0x3f, 0x93, 0x0e, 0x5f, 0xff, 0xf4, 0x46, 0xf9, 0xf8, 0x28, - 0xcf, 0xa5, 0xbf, 0xa5, 0x9a, 0x9c, 0xe5, 0xd1, 0xae, 0x68, 0x9a, 0x12, - 0xeb, 0xfd, 0xcf, 0x34, 0xb7, 0x75, 0x9a, 0x2e, 0x75, 0xff, 0xff, 0xff, - 0xd1, 0xc2, 0xf2, 0x9d, 0x7d, 0xe5, 0xcb, 0xad, 0x39, 0xce, 0x05, 0x78, - 0x5a, 0x38, 0x4f, 0xa7, 0x9d, 0x6c, 0xe5, 0xcb, 0xad, 0x0e, 0x54, 0x2f, + 0x04, 0xe5, 0xc9, 0x23, 0x96, 0xfb, 0x87, 0xf5, 0xc9, 0xa7, 0xe6, 0x17, + 0xf7, 0x86, 0x3f, 0x93, 0x0e, 0x5f, 0xff, 0xf4, 0x46, 0xfe, 0xf8, 0x28, + 0xce, 0x65, 0xbe, 0x65, 0x9a, 0x9c, 0xe5, 0xd1, 0xaf, 0xa8, 0x9a, 0x12, + 0xeb, 0xfd, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x2e, 0x75, 0xff, 0xff, 0xff, + 0xd1, 0xc2, 0xf2, 0x9d, 0x7d, 0xf9, 0xf3, 0xad, 0x3e, 0xce, 0x05, 0x78, + 0x5a, 0x38, 0x4e, 0x67, 0x9d, 0x6c, 0xf9, 0xf3, 0xad, 0x0e, 0x54, 0x2f, 0x4a, 0x4f, 0x09, 0x79, 0x22, 0x64, 0x33, 0x96, 0x44, 0x91, 0xf4, 0xb2, - 0x1a, 0x5d, 0x86, 0x97, 0x8b, 0xf8, 0x10, 0x6f, 0xf7, 0x3c, 0xd2, 0xdd, + 0x1a, 0x5d, 0x86, 0x97, 0x8b, 0xf8, 0x10, 0x6f, 0xf7, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x87, 0x97, 0xcb, 0x77, 0x59, 0xa2, 0x26, 0x5f, 0xd9, 0xc0, - 0x06, 0x60, 0x4e, 0x58, 0x07, 0x2f, 0xf7, 0x80, 0xff, 0x76, 0x38, 0x9c, - 0xad, 0x22, 0x94, 0x4b, 0xb6, 0x61, 0xe1, 0x1b, 0xf7, 0xfb, 0xe5, 0x81, - 0x39, 0x7f, 0x91, 0xbc, 0x1c, 0xfb, 0xc7, 0x29, 0x0f, 0x7b, 0x45, 0x77, + 0x06, 0x60, 0x4e, 0x58, 0x07, 0x2f, 0xf7, 0x80, 0xfc, 0xf6, 0x38, 0x9c, + 0xad, 0x22, 0x94, 0x4b, 0xb6, 0x61, 0xe1, 0x1b, 0xf7, 0xfb, 0xf9, 0x81, + 0x39, 0x7f, 0x91, 0xbc, 0x1c, 0xe7, 0xc7, 0x29, 0x0f, 0x7b, 0x45, 0x77, 0xff, 0xe8, 0xd7, 0xfd, 0x8e, 0x33, 0x44, 0x33, 0x78, 0x13, 0x97, 0xfd, 0xde, 0xc7, 0x19, 0x66, 0xa0, 0xe5, 0xbd, 0xd4, 0x49, 0x3a, 0xc5, 0xff, 0x27, 0x93, 0xd9, 0xfc, 0x68, 0xe5, 0xf4, 0xfd, 0x04, 0xe7, 0x2b, 0x11, 0x0a, 0xe5, 0x00, 0x38, 0xbd, 0x81, 0xe9, 0xcb, 0xff, 0xfb, 0xdd, 0x8d, 0x7f, 0xbc, 0x0f, 0x80, 0xeb, 0xcd, 0x1c, 0xbb, 0xcc, 0x39, 0x7f, 0xfb, - 0x3a, 0xa4, 0xfb, 0x84, 0xfb, 0xd0, 0xc3, 0x97, 0xfd, 0x12, 0x53, 0x35, + 0x3a, 0xa4, 0xfb, 0x84, 0xe7, 0xd0, 0xc3, 0x97, 0xfd, 0x12, 0x53, 0x35, 0xbc, 0x6c, 0xe5, 0xfe, 0x94, 0x2a, 0x9d, 0x79, 0xce, 0x54, 0xe7, 0xdc, - 0x87, 0x55, 0x89, 0xa7, 0xfc, 0xb9, 0xd1, 0x70, 0x42, 0xea, 0xff, 0x83, + 0x87, 0x55, 0x89, 0xa7, 0xf2, 0xb9, 0xd1, 0x70, 0x42, 0xea, 0xff, 0x83, 0x9c, 0x74, 0xfc, 0x7a, 0x87, 0x2f, 0xcd, 0x82, 0x35, 0x39, 0xcb, 0x27, - 0x23, 0xe6, 0x6c, 0xf2, 0xfa, 0x5d, 0x53, 0x67, 0x2e, 0x75, 0x0d, 0x10, - 0xba, 0xde, 0xf8, 0xf2, 0x00, 0x49, 0x7e, 0xee, 0x4e, 0x01, 0x39, 0x7c, + 0xc3, 0xe6, 0x6c, 0xf2, 0xfa, 0x5d, 0x53, 0x67, 0x2e, 0x75, 0x0d, 0x10, + 0xba, 0xde, 0xe4, 0xf2, 0x00, 0x49, 0x7e, 0xee, 0x4e, 0x01, 0x39, 0x7c, 0xfa, 0x8e, 0x27, 0x28, 0x27, 0x97, 0xf9, 0x45, 0xfa, 0x69, 0x63, 0x89, - 0xcb, 0x73, 0xc5, 0xd4, 0x4d, 0x42, 0x6b, 0xb1, 0x9c, 0x09, 0x76, 0xe3, + 0xcb, 0x7d, 0xc5, 0xd4, 0x4d, 0x42, 0x6b, 0xb1, 0x9c, 0x09, 0x76, 0xe3, 0x6b, 0xf4, 0x2a, 0x40, 0xe5, 0xc5, 0xd1, 0xa1, 0x1d, 0xff, 0xb4, 0x09, 0xf3, 0xb3, 0x0c, 0x04, 0xe5, 0xff, 0xfe, 0x74, 0xf0, 0x34, 0xfb, 0xc1, 0xee, 0x60, 0xcb, 0x67, 0x2e, 0xeb, 0x9c, 0xb0, 0x0e, 0x56, 0x1a, 0x7d, - 0x8b, 0x5e, 0xff, 0x7c, 0xe1, 0x1c, 0x9d, 0x40, 0xf4, 0x21, 0x2f, 0xff, - 0xb1, 0x25, 0xbe, 0x79, 0xf4, 0x9e, 0x75, 0x16, 0x72, 0xa1, 0x13, 0xbd, + 0x8b, 0x5e, 0xff, 0x7f, 0x61, 0x1c, 0x9d, 0x40, 0xf4, 0x21, 0x2f, 0xff, + 0xb1, 0x25, 0xbf, 0xb9, 0xcc, 0x9e, 0x75, 0x16, 0x72, 0xa1, 0x13, 0xbd, 0x49, 0xbf, 0xe6, 0xab, 0x84, 0xd6, 0x79, 0x3a, 0x03, 0x97, 0xdb, 0x49, 0xf8, 0x43, 0x94, 0xd5, 0x1f, 0x5b, 0x52, 0x87, 0x7f, 0xe6, 0xab, 0x84, - 0x49, 0xe3, 0x92, 0xf7, 0x87, 0x2e, 0xe1, 0x42, 0x72, 0x9a, 0xa3, 0xe7, + 0x49, 0xe3, 0xe2, 0xf7, 0x87, 0x2e, 0xe1, 0x42, 0x72, 0x9a, 0xa3, 0xe7, 0x6a, 0x52, 0xef, 0xfb, 0x3c, 0xa4, 0xef, 0xa4, 0x98, 0xe5, 0xfd, 0x2e, 0x15, 0x3f, 0x09, 0xc2, 0xcd, 0x44, 0xe5, 0x70, 0x88, 0x83, 0x6a, 0xce, 0xef, 0xe6, 0xa9, 0x4e, 0xf7, 0x27, 0x39, 0x6e, 0x9c, 0xa6, 0xa8, 0xf1, 0x80, 0x6b, 0x7c, 0x1c, 0x19, 0x8e, 0x5c, 0x9e, 0x39, 0x6f, 0x21, 0xb8, - 0xe9, 0x15, 0xfe, 0xfb, 0xdf, 0x48, 0x02, 0xa9, 0xcb, 0xff, 0x44, 0xc3, + 0xe9, 0x15, 0xfe, 0xe7, 0xdc, 0xc8, 0x02, 0xa9, 0xcb, 0xff, 0x44, 0xc3, 0x9c, 0x5d, 0x8c, 0x43, 0x94, 0xe7, 0xec, 0x03, 0x7b, 0xff, 0xff, 0xba, 0x00, 0xa6, 0x6a, 0x61, 0xce, 0x3d, 0xc0, 0xc6, 0xf7, 0x0a, 0x9c, 0xbf, - 0xfc, 0x93, 0x4b, 0x3e, 0x97, 0x26, 0x3b, 0x89, 0xcb, 0x9f, 0x80, 0xe5, - 0xff, 0xfe, 0xde, 0x7b, 0x97, 0x71, 0x70, 0xd8, 0xe0, 0x7a, 0x93, 0x1c, + 0xfc, 0x93, 0x4b, 0x39, 0x97, 0xc6, 0x3b, 0x89, 0xcb, 0x9f, 0x80, 0xe5, + 0xff, 0xfe, 0xde, 0x7b, 0xe7, 0x71, 0x70, 0xd8, 0xe0, 0x7a, 0x93, 0x1c, 0xb7, 0x09, 0x89, 0xfc, 0xab, 0x09, 0xc5, 0x90, 0xf5, 0xd1, 0xd3, 0x3c, 0x33, 0x73, 0x45, 0x4e, 0x5f, 0x3c, 0xa3, 0xf3, 0x97, 0xee, 0xbf, 0x9e, 0x47, 0x2f, 0xe4, 0xd0, 0xe6, 0x68, 0xe5, 0xe5, 0xcf, 0xd3, 0x97, 0xf6, - 0xe3, 0x6d, 0x41, 0xaa, 0x6a, 0x8e, 0x5f, 0xa3, 0x60, 0xea, 0x1c, 0xae, - 0x48, 0x83, 0x90, 0xf6, 0xcf, 0xaf, 0xfe, 0x67, 0x2d, 0x8e, 0x7d, 0x21, + 0xe3, 0x6d, 0x41, 0xaa, 0x6a, 0x8e, 0x5f, 0xa3, 0x60, 0xea, 0x1c, 0xaf, + 0x88, 0x83, 0x90, 0xf6, 0xcf, 0xaf, 0xfe, 0x67, 0xcd, 0x8e, 0x73, 0x21, 0x79, 0xce, 0x5e, 0xda, 0x7e, 0x72, 0xb0, 0xf9, 0x11, 0x1e, 0xf3, 0x6d, - 0xb6, 0x52, 0xfc, 0xe3, 0xee, 0xe1, 0x4e, 0x66, 0x82, 0xff, 0xff, 0xe8, - 0x9f, 0x96, 0xc1, 0x1f, 0x7b, 0xb8, 0xcc, 0xf0, 0xc7, 0xff, 0xc1, 0xcb, + 0xb6, 0x52, 0xfc, 0xe3, 0xee, 0xe1, 0x4f, 0xa6, 0x82, 0xff, 0xff, 0xe8, + 0x9f, 0xe6, 0xc1, 0x1c, 0xfb, 0xb8, 0xcc, 0xf0, 0xc7, 0xff, 0xc1, 0xcb, 0xef, 0x4d, 0x9e, 0x39, 0x41, 0x44, 0xcb, 0xbb, 0x50, 0x53, 0x33, 0xfd, 0x00, 0x61, 0xa3, 0x7e, 0xe8, 0xb5, 0x16, 0x9c, 0x07, 0x2e, 0x77, 0x39, - 0x6e, 0xa1, 0xe4, 0x39, 0x9d, 0xff, 0xfd, 0xfe, 0xa3, 0x96, 0xa3, 0xdf, - 0x4a, 0x15, 0xd3, 0xb6, 0x72, 0xff, 0xc9, 0x37, 0x2e, 0xc2, 0x68, 0x0d, + 0x6e, 0xa1, 0xe4, 0x39, 0x9d, 0xff, 0xfd, 0xfe, 0xa3, 0xe6, 0xa3, 0xdc, + 0xca, 0x15, 0xd3, 0xb6, 0x72, 0xff, 0xc9, 0x37, 0xce, 0xc2, 0x68, 0x0d, 0x67, 0x2a, 0x11, 0x4b, 0xfb, 0x0d, 0xfd, 0xa4, 0xe0, 0xd6, 0xf6, 0x72, 0xfe, 0x10, 0x79, 0x27, 0x83, 0x97, 0xfe, 0x45, 0x60, 0x63, 0x70, 0x8c, 0x39, 0x7e, 0xe2, 0x09, 0x66, 0xce, 0x5f, 0x7e, 0x82, 0x03, 0x95, 0x87, - 0x98, 0x02, 0xab, 0xec, 0x0e, 0x4e, 0x72, 0xf9, 0xaf, 0x94, 0x35, 0x27, - 0x2e, 0xd4, 0x1c, 0xa0, 0xae, 0xcb, 0xe1, 0x12, 0xc9, 0xfe, 0x85, 0x72, + 0x98, 0x02, 0xab, 0xec, 0x0e, 0x4e, 0x72, 0xf9, 0xaf, 0xe4, 0x35, 0x27, + 0x2e, 0xd4, 0x1c, 0xa0, 0xae, 0xcb, 0xe1, 0x12, 0xc9, 0xf9, 0x85, 0x72, 0x47, 0x92, 0xd6, 0xfd, 0x34, 0x32, 0xf4, 0x46, 0xc3, 0x1e, 0x96, 0x8c, 0x22, 0x3c, 0x43, 0xc4, 0x8b, 0x80, 0xb2, 0xfc, 0xdc, 0x60, 0x50, 0xe5, - 0xe0, 0x7b, 0x67, 0x2f, 0xff, 0xff, 0xfb, 0x7c, 0xbb, 0x93, 0xc3, 0x7f, - 0x4b, 0x7c, 0x80, 0xbd, 0x6a, 0x39, 0x4c, 0xaf, 0xdc, 0xb9, 0x75, 0xa1, - 0xcb, 0xfb, 0xee, 0x53, 0x66, 0x2c, 0xe5, 0x62, 0x63, 0xeb, 0x27, 0xf0, - 0xe8, 0x21, 0x55, 0x70, 0x3f, 0x39, 0x73, 0x46, 0xa8, 0xe5, 0xee, 0x52, - 0x59, 0xca, 0x83, 0xd5, 0x54, 0x61, 0x83, 0xd7, 0xff, 0xf6, 0xb9, 0x0e, - 0x71, 0xcd, 0x4b, 0x94, 0x05, 0xe6, 0xd9, 0xcb, 0xff, 0xff, 0x87, 0xe8, - 0x54, 0x70, 0x3d, 0x49, 0xb9, 0x6f, 0x3e, 0x96, 0xb1, 0xb3, 0x95, 0x88, + 0xe0, 0x7b, 0x67, 0x2f, 0xff, 0xff, 0xfb, 0x7f, 0x3b, 0x93, 0xc3, 0x7c, + 0xcb, 0x7f, 0x00, 0xbd, 0x6a, 0x3e, 0x4c, 0xaf, 0x3f, 0x3e, 0x75, 0xa1, + 0xcb, 0xfb, 0x9f, 0x93, 0x66, 0x2c, 0xe5, 0x62, 0x63, 0xeb, 0x27, 0xf0, + 0xe8, 0x21, 0x55, 0x70, 0x3f, 0x39, 0x73, 0x46, 0xa8, 0xe5, 0xef, 0x92, + 0x59, 0xca, 0x83, 0xd5, 0x54, 0x61, 0x83, 0xd7, 0xff, 0xf6, 0xbe, 0x0e, + 0x71, 0xcd, 0x4b, 0xe4, 0x05, 0xe6, 0xd9, 0xcb, 0xff, 0xff, 0x87, 0x98, + 0x54, 0x70, 0x3d, 0x49, 0xbe, 0x6f, 0x39, 0x96, 0xb1, 0xb3, 0x95, 0x88, 0xd8, 0x16, 0x1b, 0xef, 0x02, 0x27, 0x39, 0x7f, 0x49, 0xf5, 0xb4, 0x09, 0xcb, 0xfb, 0x3b, 0x8c, 0x85, 0x9c, 0xa8, 0x3d, 0x99, 0x16, 0xd2, 0x22, - 0x77, 0xcf, 0x97, 0xff, 0xf7, 0xd2, 0xdb, 0x30, 0x79, 0x70, 0x27, 0x67, + 0x77, 0xcf, 0x97, 0xff, 0xf7, 0x32, 0xdb, 0x30, 0x7e, 0x70, 0x27, 0x67, 0x4c, 0xd1, 0xcb, 0x35, 0x9c, 0xac, 0x3f, 0x55, 0xb0, 0xdf, 0xff, 0xf9, - 0xbe, 0x43, 0x8b, 0xea, 0x0e, 0x03, 0xef, 0x72, 0x76, 0xf1, 0x53, 0x97, - 0xf9, 0x50, 0x82, 0x3a, 0x30, 0x72, 0xff, 0x7d, 0x2d, 0xaa, 0x08, 0xf8, + 0xbf, 0x83, 0x8b, 0xea, 0x0e, 0x03, 0x9f, 0x7c, 0x76, 0xf1, 0x53, 0x97, + 0xf9, 0x50, 0x82, 0x3a, 0x30, 0x72, 0xff, 0x73, 0x2d, 0xaa, 0x08, 0xe4, 0xe5, 0xfe, 0x76, 0xc1, 0x34, 0x79, 0xce, 0x5e, 0xe3, 0xe5, 0x0e, 0x54, 0x26, 0x61, 0x8e, 0x48, 0x66, 0x26, 0xed, 0x9a, 0x5f, 0xff, 0x87, 0x03, - 0xd0, 0x37, 0xb4, 0xf7, 0x51, 0xff, 0x39, 0x7f, 0x87, 0x38, 0xf2, 0x93, + 0xd0, 0x37, 0xb4, 0xf7, 0x51, 0xff, 0x39, 0x7f, 0x87, 0x38, 0xfc, 0x93, 0x24, 0x72, 0xb4, 0x88, 0xdd, 0xab, 0x5d, 0xbe, 0x27, 0x2a, 0x0d, 0xe0, 0x08, 0xef, 0xbf, 0xf2, 0x4e, 0x72, 0xff, 0x7b, 0xa8, 0x3f, 0xa8, 0xc3, 0x97, 0xff, 0xf7, 0x53, 0x07, 0x10, 0x39, 0x1f, 0xba, 0xdf, 0x47, 0x2f, - 0xf4, 0xf0, 0xc1, 0x8f, 0xbf, 0x39, 0x52, 0x46, 0x0f, 0xc6, 0xae, 0xaf, - 0x7e, 0xef, 0x27, 0xcd, 0x9c, 0xa8, 0x3d, 0x9c, 0x30, 0xbf, 0xf9, 0xf5, - 0x2e, 0x5e, 0x18, 0x96, 0x78, 0xe5, 0x42, 0xeb, 0xd6, 0x42, 0xf9, 0x21, + 0xf4, 0xf0, 0xc1, 0x8e, 0x7f, 0x39, 0x52, 0x46, 0x0f, 0x26, 0xae, 0xaf, + 0x7e, 0xef, 0xc7, 0xcd, 0x9c, 0xa8, 0x3d, 0x9c, 0x30, 0xbf, 0xf9, 0xf5, + 0x2f, 0x9e, 0x18, 0x96, 0x78, 0xe5, 0x42, 0xeb, 0xd6, 0x42, 0xf9, 0x21, 0x2f, 0xa8, 0xd4, 0x7b, 0x18, 0x8b, 0x90, 0x0c, 0x67, 0xc0, 0x20, 0xb3, - 0x59, 0xcb, 0xff, 0xed, 0x20, 0x38, 0x78, 0xe5, 0xb0, 0x7e, 0xcc, 0xf1, - 0xcb, 0xff, 0x42, 0xf7, 0x09, 0xf7, 0xa1, 0x87, 0x2d, 0x23, 0x94, 0x27, - 0x9e, 0x03, 0xeb, 0xef, 0xf7, 0x3f, 0x8e, 0x5f, 0xf9, 0xd5, 0xe5, 0xe7, - 0x71, 0xe5, 0x39, 0xca, 0x83, 0xe8, 0x12, 0x5b, 0xcf, 0xed, 0x9c, 0xb8, + 0x59, 0xcb, 0xff, 0xed, 0x20, 0x38, 0x78, 0xf9, 0xb0, 0x7e, 0xcc, 0xf1, + 0xcb, 0xff, 0x42, 0xf7, 0x09, 0xcf, 0xa1, 0x87, 0x2d, 0x23, 0x94, 0x27, + 0x9e, 0x03, 0xeb, 0xef, 0xf7, 0x3f, 0x8e, 0x5f, 0xf9, 0xd5, 0xf9, 0xe7, + 0x71, 0xf9, 0x39, 0xca, 0x83, 0xe8, 0x12, 0x5b, 0xcf, 0xed, 0x9c, 0xb8, 0x13, 0x9c, 0xa9, 0x1b, 0x4d, 0x0e, 0x5f, 0xb2, 0x5d, 0x79, 0x1c, 0xb8, 0x7d, 0x31, 0xe4, 0x74, 0x86, 0xff, 0x38, 0xa9, 0xde, 0xc0, 0x4e, 0x5f, - 0xc0, 0x5f, 0x20, 0xfc, 0xd9, 0xcb, 0xfe, 0x86, 0xfb, 0x83, 0xf4, 0x2a, - 0x72, 0xed, 0x48, 0xe5, 0x42, 0x39, 0x7e, 0x2e, 0x43, 0x3d, 0x19, 0xb0, - 0xea, 0xff, 0x6a, 0x03, 0x1d, 0x89, 0x1c, 0xbf, 0xfe, 0x8f, 0x72, 0x10, - 0x70, 0x72, 0xcf, 0x34, 0xcf, 0x1c, 0xa4, 0x44, 0x50, 0x0c, 0xaf, 0xfe, - 0xec, 0x2b, 0xcb, 0xc2, 0xfe, 0x8f, 0x1c, 0xbf, 0xdc, 0xbe, 0x92, 0x74, - 0x0c, 0x39, 0x5f, 0x9f, 0xe8, 0xa3, 0x5f, 0xfd, 0x9c, 0x70, 0x3c, 0xbc, - 0xaa, 0x37, 0xb3, 0x97, 0xfe, 0xd4, 0xdc, 0xb7, 0x09, 0x3b, 0xf8, 0xe5, - 0x42, 0x2b, 0x82, 0x44, 0x04, 0xab, 0x9f, 0xf3, 0x97, 0xff, 0xdc, 0x86, + 0xc0, 0x5f, 0xc0, 0xf2, 0xd9, 0xcb, 0xfe, 0x86, 0xfb, 0x83, 0xcc, 0x2a, + 0x72, 0xed, 0x48, 0xe5, 0x42, 0x39, 0x79, 0x2e, 0x43, 0x3d, 0x19, 0xb0, + 0xea, 0xff, 0x6a, 0x03, 0x1d, 0x89, 0x1c, 0xbf, 0xfe, 0x8f, 0x7c, 0x10, + 0x70, 0x7c, 0xcf, 0x34, 0xcf, 0x1c, 0xa4, 0x44, 0x50, 0x0c, 0xaf, 0xfe, + 0xec, 0x2b, 0xf3, 0xc2, 0xfe, 0x8f, 0x1c, 0xbf, 0xdf, 0x39, 0x92, 0x74, + 0x0c, 0x39, 0x5f, 0x9f, 0xe8, 0xa3, 0x5f, 0xfd, 0x9c, 0x70, 0x3f, 0x3c, + 0xaa, 0x37, 0xb3, 0x97, 0xfe, 0xd4, 0xdf, 0x37, 0x09, 0x3b, 0xf8, 0xe5, + 0x42, 0x2b, 0x82, 0x44, 0x04, 0xab, 0x9f, 0xf3, 0x97, 0xff, 0xdf, 0x06, 0x37, 0x13, 0x8e, 0x07, 0xa9, 0x31, 0xcb, 0xff, 0xff, 0xb7, 0xa1, 0x89, - 0xb9, 0x29, 0xe4, 0x96, 0x7d, 0xec, 0xe2, 0x39, 0xb3, 0x95, 0xa4, 0x64, - 0x0a, 0x8d, 0x79, 0x30, 0x10, 0x43, 0x7e, 0x8e, 0x5e, 0xf7, 0x25, 0x4e, - 0x5d, 0x34, 0x8e, 0x54, 0x1e, 0x1f, 0xc1, 0x7a, 0x20, 0xbf, 0xf8, 0x7d, - 0xbe, 0x29, 0xe8, 0xc1, 0x98, 0xe5, 0xfb, 0x49, 0xb8, 0xf8, 0xe5, 0x61, + 0xbe, 0x29, 0xe4, 0x96, 0x73, 0xec, 0xe2, 0x39, 0xb3, 0x95, 0xa4, 0x64, + 0x0a, 0x8d, 0x79, 0x30, 0x10, 0x43, 0x7e, 0x8e, 0x5e, 0xf7, 0xc5, 0x4e, + 0x5d, 0x34, 0x8e, 0x54, 0x1e, 0x1f, 0x21, 0x7a, 0x20, 0xbf, 0xf8, 0x7d, + 0xbe, 0x29, 0xe8, 0xc1, 0x98, 0xe5, 0xfb, 0x49, 0xb8, 0xe4, 0xe5, 0x61, 0xf6, 0xba, 0x2d, 0xfe, 0x9f, 0x84, 0x9a, 0x49, 0xed, 0x9c, 0xbf, 0x0f, 0xbb, 0x9c, 0x07, 0x2f, 0xd3, 0x6d, 0xf4, 0xa9, 0xcb, 0xce, 0xde, 0xa0, 0xf5, 0x30, 0xaa, 0xa4, 0x8e, 0x14, 0x20, 0xd4, 0x23, 0xef, 0xfb, 0xa9, - 0xa9, 0xba, 0xf9, 0xa3, 0x97, 0xff, 0xff, 0xf7, 0xfb, 0x1c, 0x7f, 0xb9, - 0x07, 0xa0, 0xe4, 0x39, 0xf4, 0xb0, 0x13, 0x8e, 0x3f, 0xc7, 0x29, 0x68, + 0xa9, 0xba, 0xf9, 0xa3, 0x97, 0xff, 0xff, 0xf7, 0xfb, 0x1c, 0x7e, 0x7e, + 0x07, 0xa0, 0xf8, 0x39, 0xcc, 0xb0, 0x13, 0x8e, 0x3f, 0x27, 0x29, 0x68, 0xc8, 0x43, 0x9b, 0xce, 0xeb, 0x34, 0x53, 0x0a, 0xc3, 0xca, 0x59, 0x15, - 0xff, 0xb0, 0x7e, 0x96, 0xfd, 0x1a, 0x98, 0xe5, 0xff, 0x9f, 0xec, 0x4d, - 0x23, 0x21, 0x53, 0x97, 0xb1, 0x3f, 0x39, 0x6c, 0x39, 0x7b, 0xe1, 0xcf, + 0xff, 0xb0, 0x79, 0x96, 0xfd, 0x1a, 0x98, 0xe5, 0xff, 0x9f, 0x9c, 0x4d, + 0x23, 0x21, 0x53, 0x97, 0xb1, 0x3f, 0x39, 0x6c, 0x39, 0x7b, 0x91, 0xcf, 0xcd, 0x67, 0x11, 0xca, 0x44, 0x6f, 0xe9, 0x01, 0xda, 0xaf, 0x60, 0x34, 0x72, 0xe9, 0xe6, 0x39, 0x66, 0xce, 0x5c, 0x81, 0x39, 0x4d, 0x66, 0xa3, 0x62, 0x57, 0x06, 0x63, 0x97, 0xfd, 0xac, 0x0f, 0x61, 0xb6, 0x00, 0xe5, 0xca, 0xce, 0x72, 0xa1, 0x1a, 0x18, 0x82, 0xc2, 0x4e, 0x8c, 0x36, 0x75, - 0x73, 0x3f, 0x39, 0x7b, 0x5d, 0x7e, 0x47, 0xc3, 0xfa, 0x4d, 0xfe, 0xe5, - 0xf4, 0x86, 0x33, 0x67, 0x2b, 0xe4, 0xee, 0x12, 0x34, 0xd7, 0x36, 0xbf, - 0xff, 0x7e, 0x9b, 0xe5, 0xd7, 0xdf, 0xa2, 0x6d, 0xf7, 0x0e, 0x5f, 0xdd, - 0x7d, 0xf5, 0xe4, 0x72, 0xfe, 0x4e, 0xba, 0x4f, 0x07, 0x2f, 0x4a, 0x3e, + 0x73, 0x3f, 0x39, 0x7b, 0x5d, 0x7f, 0x87, 0xc3, 0xfa, 0x4d, 0xfe, 0xf9, + 0xcc, 0x86, 0x33, 0x67, 0x2b, 0x94, 0xee, 0x12, 0x34, 0xd7, 0x36, 0xbf, + 0xff, 0x7e, 0x9b, 0xf9, 0xd7, 0xdf, 0xa2, 0x6d, 0xf7, 0x0e, 0x5f, 0xdd, + 0x7d, 0xf5, 0xe4, 0x72, 0xfe, 0x4e, 0xba, 0x4f, 0x07, 0x2f, 0x4a, 0x39, 0x39, 0x7f, 0x98, 0x1e, 0xc4, 0xf8, 0xd9, 0xca, 0x84, 0x55, 0xe1, 0x6f, - 0xc5, 0x8e, 0x3b, 0x7e, 0xf9, 0x63, 0x1c, 0x4e, 0x5f, 0xf9, 0xfe, 0xda, + 0x25, 0x8e, 0x3b, 0x7e, 0xe5, 0x63, 0x1c, 0x4e, 0x5f, 0xf9, 0xf9, 0xda, 0x9d, 0xec, 0x0a, 0xce, 0x56, 0x1f, 0x50, 0x0a, 0xae, 0xde, 0xce, 0x5b, - 0x0e, 0x5f, 0xfa, 0x64, 0x55, 0x3c, 0x39, 0xc1, 0xcb, 0x46, 0x9f, 0x88, - 0xbd, 0xff, 0xfe, 0x1c, 0x5f, 0xbd, 0x1e, 0xdc, 0xc3, 0x8d, 0xf2, 0x86, + 0x0e, 0x5f, 0xfa, 0x64, 0x55, 0x3c, 0x39, 0xc1, 0xf3, 0x46, 0x9f, 0x88, + 0xbd, 0xff, 0xfe, 0x1c, 0x5f, 0xbd, 0x1e, 0xdc, 0xc3, 0x8d, 0xfc, 0x86, 0xa4, 0xe5, 0xff, 0x97, 0x0c, 0xee, 0x6f, 0x10, 0x4e, 0x54, 0x22, 0x93, - 0xad, 0x17, 0xed, 0x47, 0x18, 0xd1, 0xcb, 0xf9, 0xc7, 0x90, 0x60, 0x4e, + 0xad, 0x17, 0xed, 0x47, 0x18, 0xd1, 0xcb, 0xf9, 0xc7, 0xe0, 0x60, 0x4e, 0x54, 0x26, 0xf1, 0x91, 0x80, 0x21, 0x10, 0x0a, 0x6f, 0xfa, 0x1b, 0x5a, - 0x4f, 0x9f, 0x78, 0xe5, 0x35, 0x6d, 0x82, 0x2c, 0x0a, 0x4f, 0x0a, 0x79, - 0x42, 0x24, 0x31, 0xc0, 0xab, 0x0d, 0x35, 0xc6, 0x9b, 0xf4, 0x66, 0x08, + 0x4f, 0x9c, 0xf8, 0xe5, 0x35, 0x6d, 0x82, 0x2c, 0x0a, 0x4f, 0x0a, 0x79, + 0x42, 0x24, 0x31, 0xc0, 0xab, 0x0d, 0x35, 0xc6, 0x9b, 0xcc, 0x66, 0x08, 0xd9, 0x34, 0x6f, 0xba, 0x8d, 0x19, 0x91, 0x80, 0x76, 0x3e, 0x6f, 0xcd, 0x86, 0x30, 0x4d, 0xc2, 0x97, 0xd1, 0xe0, 0x71, 0x41, 0xbf, 0xed, 0x3b, - 0x7c, 0x9c, 0x2f, 0x39, 0xcb, 0xf9, 0xdb, 0x98, 0x50, 0x27, 0x2f, 0xff, - 0xf0, 0x72, 0x77, 0x1f, 0x6e, 0x17, 0xc9, 0x8c, 0x41, 0x59, 0xcb, 0xf8, - 0x3b, 0x78, 0xfa, 0x47, 0x2a, 0x11, 0x20, 0xec, 0x57, 0xfa, 0x6e, 0xa4, - 0x31, 0xc2, 0x72, 0xff, 0x72, 0xd6, 0x27, 0x60, 0x27, 0x2a, 0x0f, 0x9c, + 0x7f, 0x1c, 0x2f, 0x39, 0xcb, 0xf9, 0xdb, 0x98, 0x50, 0x27, 0x2f, 0xff, + 0xf0, 0x72, 0x77, 0x1f, 0x6e, 0x17, 0xf1, 0x8c, 0x41, 0x59, 0xcb, 0xf8, + 0x3b, 0x78, 0xe6, 0x47, 0x2a, 0x11, 0x20, 0xec, 0x57, 0xfa, 0x6e, 0xa4, + 0x31, 0xc2, 0x72, 0xff, 0x7c, 0xd6, 0x27, 0x60, 0x27, 0x2a, 0x0f, 0x9c, 0x4c, 0xe9, 0x54, 0xe8, 0xb4, 0x78, 0x30, 0xbe, 0x04, 0x22, 0x2f, 0xb0, - 0x55, 0x6b, 0x39, 0x7f, 0xff, 0xfe, 0xea, 0x7b, 0xb9, 0xa8, 0xe3, 0xc9, - 0x80, 0xe0, 0xe5, 0x9f, 0x4b, 0x00, 0x3f, 0xec, 0xe5, 0xbc, 0x88, 0xb3, - 0xd9, 0x2d, 0xff, 0xa1, 0x7c, 0x85, 0xf6, 0xc8, 0x13, 0x97, 0xff, 0xba, - 0x8b, 0xee, 0x72, 0xd8, 0x3b, 0x0d, 0x67, 0x2f, 0xfb, 0xd9, 0xd1, 0xcf, - 0x75, 0x0e, 0x5b, 0x31, 0x10, 0xdf, 0x27, 0xdf, 0xff, 0x7b, 0xb9, 0xff, - 0x26, 0x46, 0x78, 0x38, 0x27, 0x2c, 0xd9, 0xcb, 0xf9, 0xc3, 0xad, 0x02, + 0x55, 0x6b, 0x39, 0x7f, 0xff, 0xfe, 0xea, 0x7b, 0xb9, 0xa8, 0xe3, 0xf1, + 0x80, 0xe0, 0xf9, 0x9c, 0xcb, 0x00, 0x3f, 0xec, 0xe5, 0xbc, 0x88, 0xb3, + 0xd9, 0x2d, 0xff, 0xa1, 0x7f, 0x05, 0xf6, 0xc8, 0x13, 0x97, 0xff, 0xba, + 0x8b, 0xee, 0x7c, 0xd8, 0x3b, 0x0d, 0x67, 0x2f, 0xfb, 0xd9, 0xd1, 0xcf, + 0x75, 0x0e, 0x5b, 0x31, 0x10, 0xdc, 0xa7, 0xdf, 0xff, 0x7b, 0xb9, 0xff, + 0xc6, 0x46, 0x78, 0x38, 0x27, 0x2c, 0xd9, 0xcb, 0xf9, 0xc3, 0xad, 0x02, 0x73, 0x97, 0xe8, 0xc1, 0xf3, 0x43, 0x94, 0xa9, 0xf4, 0xac, 0x49, 0x85, - 0xf7, 0xde, 0x4d, 0x61, 0xcb, 0x7d, 0xc8, 0xf4, 0x70, 0xc2, 0xdb, 0xc4, + 0xf7, 0xde, 0x4d, 0x61, 0xcb, 0x73, 0xf0, 0xf4, 0x70, 0xc2, 0xdb, 0xc4, 0xcd, 0x5e, 0x30, 0xba, 0x62, 0xa4, 0xf1, 0x86, 0x27, 0xa3, 0x5d, 0xbf, - 0xff, 0xfe, 0xcf, 0xa4, 0x9b, 0x1c, 0xe3, 0xdc, 0x9b, 0xb0, 0x33, 0x72, - 0x75, 0xa7, 0x13, 0x97, 0xff, 0xfd, 0x82, 0xaf, 0x2d, 0x47, 0x14, 0xf6, - 0xf1, 0x54, 0xd3, 0xfc, 0x72, 0x85, 0x1d, 0xca, 0x42, 0x0e, 0x91, 0x35, - 0x20, 0x46, 0x55, 0x7f, 0xf9, 0x03, 0xc9, 0x89, 0xca, 0x02, 0xf3, 0x6c, - 0xe5, 0xd2, 0x91, 0xcb, 0x6a, 0x0f, 0x96, 0x74, 0xeb, 0xf4, 0xa3, 0xe9, - 0x6c, 0xe5, 0xff, 0xff, 0xff, 0xb0, 0x55, 0xe4, 0x9d, 0x07, 0x39, 0x93, - 0xd0, 0xc1, 0x75, 0x7a, 0x9c, 0xf3, 0xbf, 0x7f, 0x01, 0x29, 0x7f, 0xff, - 0xf2, 0xd1, 0xb0, 0x83, 0x5c, 0x81, 0x13, 0xed, 0x7d, 0x07, 0x7e, 0x76, - 0xce, 0x5c, 0x09, 0xfe, 0x4d, 0x15, 0x0a, 0x77, 0x0a, 0x2b, 0xf9, 0x51, + 0xff, 0xfe, 0xce, 0x64, 0x9b, 0x1c, 0xe3, 0xdc, 0x9b, 0xb0, 0x33, 0x7c, + 0x75, 0xa7, 0x13, 0x97, 0xff, 0xfd, 0x82, 0xaf, 0xcd, 0x47, 0x14, 0xf6, + 0xf1, 0x54, 0xd3, 0xf2, 0x72, 0x85, 0x1d, 0xca, 0x42, 0x0e, 0x91, 0x35, + 0x20, 0x46, 0x55, 0x7f, 0xf9, 0x03, 0xf1, 0x89, 0xf2, 0x02, 0xf3, 0x6c, + 0xe5, 0xd2, 0x91, 0xcb, 0x6a, 0x0f, 0x96, 0x74, 0xeb, 0xf4, 0xa3, 0x99, + 0x6c, 0xe5, 0xff, 0xff, 0xff, 0xb0, 0x55, 0xf8, 0x9d, 0x07, 0xd9, 0x93, + 0xd0, 0xc1, 0x75, 0x7a, 0x9f, 0x73, 0xbc, 0xff, 0x01, 0x29, 0x7f, 0xff, + 0xf2, 0xd1, 0xb0, 0x83, 0x5f, 0x01, 0x13, 0xed, 0x7d, 0x07, 0x79, 0x76, + 0xce, 0x5c, 0x09, 0xf9, 0x4d, 0x15, 0x0a, 0x77, 0x0a, 0x2b, 0xf9, 0x51, 0xcf, 0x75, 0x0e, 0x54, 0x2f, 0x1a, 0x76, 0x5e, 0x4b, 0xc2, 0x38, 0x63, 0x6d, 0x02, 0x1d, 0x98, 0x72, 0xff, 0x3c, 0xb1, 0x8e, 0x3f, 0x9c, 0xbe, - 0xce, 0xc4, 0xc7, 0x2f, 0x31, 0x7c, 0x9a, 0xb3, 0xe5, 0xe8, 0x8b, 0x99, - 0x5f, 0xff, 0xfe, 0xd2, 0xc7, 0x38, 0xf2, 0xda, 0x60, 0xff, 0xc8, 0x73, - 0x88, 0xe6, 0xf8, 0x9c, 0xbf, 0xd8, 0xec, 0xe4, 0xd2, 0x18, 0x72, 0xff, - 0xf4, 0xa3, 0x7d, 0x06, 0xb3, 0xde, 0x46, 0x1c, 0xa5, 0xa2, 0x03, 0xe3, - 0x6b, 0xff, 0xf0, 0x23, 0x90, 0xe0, 0x7a, 0x8a, 0x86, 0x15, 0xfc, 0xe5, + 0xce, 0xc4, 0xc7, 0x2f, 0x31, 0x7f, 0x1a, 0xb3, 0xe5, 0xe8, 0x8b, 0x99, + 0x5f, 0xff, 0xfe, 0xd2, 0xc7, 0x38, 0xfc, 0xda, 0x60, 0xff, 0xf0, 0x73, + 0x88, 0xe6, 0xf8, 0x9c, 0xbf, 0xd8, 0xec, 0xf8, 0xd2, 0x18, 0x72, 0xff, + 0xf4, 0xa3, 0x7d, 0x06, 0xb3, 0xde, 0x46, 0x1c, 0xa5, 0xa2, 0x03, 0x93, + 0x6b, 0xff, 0xf0, 0x23, 0xe0, 0xe0, 0x7a, 0x8a, 0x86, 0x15, 0xfc, 0xe5, 0x62, 0x6f, 0x9a, 0x87, 0xf8, 0x92, 0x5f, 0xff, 0x90, 0x7d, 0xdc, 0xe0, - 0xf4, 0xd8, 0xd6, 0xe3, 0xf9, 0xcb, 0xe6, 0xf9, 0x6e, 0x63, 0x96, 0xf1, - 0xca, 0x83, 0x70, 0xe4, 0xf7, 0xfe, 0x19, 0xc7, 0x38, 0xec, 0x11, 0xf1, - 0xcb, 0xff, 0x07, 0xb1, 0xf7, 0x26, 0xa3, 0xc7, 0xf4, 0x39, 0x50, 0x88, + 0xf4, 0xd8, 0xd6, 0xe3, 0xf9, 0xcb, 0xe6, 0xfe, 0x6e, 0x63, 0x96, 0xf1, + 0xca, 0x83, 0x70, 0xe4, 0xf7, 0xfe, 0x19, 0xc7, 0x38, 0xec, 0x11, 0xc9, + 0xcb, 0xff, 0x07, 0xb1, 0xcf, 0xc6, 0xa3, 0xc7, 0xf4, 0x39, 0x50, 0x88, 0xc9, 0xd0, 0x69, 0x13, 0x95, 0xd9, 0xa7, 0xa1, 0x26, 0x08, 0x55, 0xdf, 0xfc, 0xde, 0x6c, 0x10, 0xae, 0xe3, 0x53, 0x1c, 0xbe, 0xd4, 0x9c, 0x27, 0x2f, 0xfc, 0x32, 0x5f, 0x53, 0xa2, 0x09, 0xce, 0x5e, 0xf6, 0x70, 0xe7, 0x2a, 0x0f, 0x83, 0x0f, 0xef, 0x34, 0xce, 0x9c, 0xbb, 0x02, 0x72, 0xa7, 0x5c, 0xbc, 0x94, 0xb5, 0x8c, 0x47, 0x74, 0x7d, 0xc2, 0x0b, 0xc4, 0x1c, 0x47, 0xaf, 0xc9, 0xed, 0xe7, 0xe7, 0x2f, 0xdd, 0xce, 0x29, 0xc4, 0xe5, - 0xff, 0xff, 0x85, 0xfd, 0xd8, 0x9b, 0x90, 0xe7, 0x53, 0xdb, 0x02, 0xc1, + 0xff, 0xff, 0x85, 0xfd, 0xd8, 0x9b, 0xe0, 0xe7, 0x53, 0xdb, 0x02, 0xc1, 0x07, 0x2e, 0xcf, 0xce, 0x5f, 0xfc, 0x3f, 0x8e, 0x24, 0xdd, 0x81, 0x54, 0xe5, 0x21, 0xed, 0xb8, 0xbd, 0xfa, 0x07, 0xaf, 0x23, 0x97, 0xa0, 0x30, 0x72, 0x82, 0x78, 0x2c, 0x26, 0xa3, 0x97, 0xa0, 0x30, 0x72, 0xfd, 0x9e, - 0xdb, 0xcd, 0xc8, 0xf2, 0x20, 0x89, 0x81, 0x77, 0xcd, 0x5b, 0x50, 0xe1, - 0x9a, 0xb3, 0x97, 0xc8, 0xe2, 0x13, 0x96, 0x6f, 0x91, 0xec, 0x04, 0xe2, + 0xdb, 0xcd, 0xf0, 0xf2, 0x20, 0x89, 0x81, 0x77, 0xcd, 0x5b, 0x50, 0xe1, + 0x9a, 0xb3, 0x97, 0xc8, 0xe2, 0x13, 0x96, 0x6f, 0xe1, 0xec, 0x04, 0xe2, 0xa4, 0x8d, 0x04, 0x85, 0x2d, 0xff, 0xfb, 0x40, 0xd6, 0xa0, 0x71, 0x54, - 0xef, 0x71, 0x43, 0x97, 0xc0, 0x7f, 0xbc, 0x72, 0xa4, 0xac, 0xd0, 0x25, + 0xef, 0x71, 0x43, 0x97, 0xc0, 0x7e, 0x7c, 0x72, 0xa4, 0xac, 0xd0, 0x25, 0x18, 0x56, 0xac, 0x32, 0x26, 0x8d, 0xe7, 0x44, 0xfd, 0x56, 0xa3, 0x97, 0xf6, 0xd6, 0xb7, 0x15, 0x4e, 0x57, 0x0a, 0x37, 0x3e, 0x0b, 0xbf, 0xc3, - 0xcb, 0x8f, 0xd2, 0xdc, 0xc7, 0x2e, 0x9f, 0xe3, 0x97, 0xee, 0xbb, 0x5c, + 0xf3, 0x8f, 0x32, 0xdc, 0xc7, 0x2e, 0x9f, 0x93, 0x97, 0xee, 0xbb, 0x5c, 0x7e, 0x72, 0x82, 0x7f, 0xce, 0x75, 0xc0, 0x33, 0x7f, 0xb5, 0x30, 0xe7, 0x5f, 0xc7, 0x2a, 0x13, 0x09, 0xc8, 0x52, 0xa1, 0x8d, 0xf9, 0x34, 0x1c, - 0x13, 0x97, 0xef, 0xf3, 0xca, 0x4e, 0x72, 0xff, 0x37, 0xec, 0xef, 0x2f, - 0xb6, 0x72, 0xa0, 0xf8, 0xdc, 0xae, 0xa4, 0x8d, 0xce, 0x99, 0x8c, 0x22, - 0x6f, 0xee, 0xe2, 0xe5, 0x0c, 0x39, 0x7f, 0xbb, 0x92, 0x71, 0xcf, 0x8e, + 0x13, 0x97, 0xef, 0xf3, 0xca, 0x4e, 0x72, 0xff, 0x37, 0xec, 0xef, 0xce, + 0x76, 0x72, 0xa0, 0xf8, 0xdc, 0xae, 0xa4, 0x8d, 0xce, 0x99, 0x8c, 0x22, + 0x6f, 0xee, 0xe2, 0xe5, 0x0c, 0x39, 0x7f, 0xbb, 0x92, 0x71, 0xce, 0x4e, 0x56, 0x1e, 0xff, 0x8b, 0x6f, 0xff, 0xf8, 0x5f, 0xfd, 0xcf, 0x88, 0x3e, - 0x1c, 0xe3, 0xcb, 0x6d, 0x89, 0xcb, 0xfb, 0xb8, 0x3f, 0x42, 0xa7, 0x28, + 0x1c, 0xe3, 0xf3, 0x6d, 0x89, 0xcb, 0xfb, 0xb8, 0x3c, 0xc2, 0xa7, 0x28, 0x51, 0x73, 0xe2, 0x16, 0xda, 0xaf, 0x62, 0x4c, 0x72, 0xff, 0xc9, 0x93, - 0x72, 0xdc, 0x75, 0xda, 0xce, 0x5f, 0xff, 0x4b, 0x60, 0xc1, 0xe4, 0x39, - 0xde, 0xb8, 0x4e, 0x5f, 0xf7, 0xd9, 0x1f, 0x4c, 0x30, 0xc3, 0x97, 0xf7, - 0xdb, 0xee, 0x3e, 0x8e, 0x5f, 0xff, 0xf9, 0x19, 0xa4, 0xcf, 0x84, 0x1e, - 0x8e, 0xf2, 0xe2, 0x9e, 0x9a, 0x0e, 0x53, 0xa2, 0x7b, 0xc5, 0xd5, 0x3a, - 0x75, 0x21, 0x1c, 0xf9, 0x0f, 0xaa, 0x1e, 0x86, 0xc5, 0xff, 0xf6, 0x3c, + 0x7c, 0xdc, 0x75, 0xda, 0xce, 0x5f, 0xff, 0x4b, 0x60, 0xc1, 0xf8, 0x39, + 0xde, 0xb8, 0x4e, 0x5f, 0xf7, 0x39, 0x1c, 0xcc, 0x30, 0xc3, 0x97, 0xf7, + 0x3b, 0xee, 0x3e, 0x8e, 0x5f, 0xff, 0xf9, 0x19, 0xa4, 0xce, 0x44, 0x1e, + 0x8e, 0xfc, 0xe2, 0x9e, 0x9a, 0x0e, 0x53, 0xa2, 0x7b, 0xc5, 0xd5, 0x3a, + 0x75, 0x21, 0x1c, 0xe5, 0x0f, 0xaa, 0x1e, 0x86, 0xc5, 0xff, 0xf6, 0x3c, 0xfd, 0x84, 0xf6, 0xe2, 0x7c, 0xd9, 0xcb, 0xfe, 0xcd, 0x4f, 0x09, 0xac, - 0x13, 0x96, 0x61, 0xce, 0x46, 0xde, 0xf0, 0xe0, 0x4e, 0x54, 0x1b, 0xef, - 0x88, 0xef, 0xef, 0xb7, 0x98, 0x2a, 0x9c, 0xbe, 0x62, 0x91, 0xf9, 0xcb, + 0x13, 0x96, 0x61, 0xcf, 0x86, 0xde, 0xf0, 0xe0, 0x4e, 0x54, 0x1b, 0xee, + 0x48, 0xef, 0xee, 0x77, 0x98, 0x2a, 0x9c, 0xbe, 0x62, 0x91, 0xf9, 0xcb, 0xff, 0xd3, 0x87, 0x4e, 0xb1, 0xce, 0x3a, 0x4d, 0x9c, 0xac, 0x44, 0xf2, 0x17, 0x00, 0x92, 0xfe, 0xf7, 0x5e, 0x65, 0x18, 0x72, 0xfe, 0xf4, 0x7f, - 0x2c, 0xd9, 0xca, 0x73, 0xde, 0x13, 0x0b, 0xc0, 0xfb, 0xf3, 0x97, 0xf6, - 0xe3, 0xef, 0xf5, 0x07, 0x2e, 0x0a, 0x1c, 0xa8, 0x5c, 0xbe, 0xc8, 0xf6, + 0x2c, 0xd9, 0xca, 0x73, 0xde, 0x13, 0x0b, 0xc0, 0xe7, 0xf3, 0x97, 0xf6, + 0xe3, 0x9f, 0xf5, 0x07, 0x2e, 0x0a, 0x1c, 0xa8, 0x5c, 0xbe, 0xc8, 0xf6, 0x56, 0xa4, 0x90, 0xc4, 0xd4, 0x2f, 0xde, 0x11, 0x82, 0x41, 0xb1, 0xfe, - 0x25, 0xf7, 0xf7, 0x9f, 0xbc, 0x83, 0x07, 0x2f, 0xff, 0x7b, 0x6a, 0x6f, - 0x97, 0x86, 0x25, 0x9e, 0x39, 0x7f, 0xbc, 0x93, 0xe7, 0x41, 0xe3, 0x97, + 0x25, 0xf7, 0xf7, 0x9f, 0xbf, 0x03, 0x07, 0x2f, 0xff, 0x7b, 0x6a, 0x6f, + 0xe7, 0x86, 0x25, 0x9e, 0x39, 0x7f, 0xbc, 0x93, 0xe7, 0x41, 0xe3, 0x97, 0xde, 0xdc, 0x2a, 0x72, 0xd3, 0x1c, 0xbf, 0xb0, 0x19, 0xd5, 0xce, 0x72, - 0xdf, 0x41, 0xe0, 0x6c, 0x4a, 0xa1, 0x11, 0x78, 0xc7, 0x7f, 0x75, 0xe4, - 0xcd, 0x21, 0xcb, 0xff, 0x95, 0x55, 0xfd, 0xbf, 0x0c, 0x7d, 0x23, 0x97, + 0xdc, 0xc1, 0xe0, 0x6c, 0x4a, 0xa1, 0x11, 0x78, 0xc7, 0x7f, 0x75, 0xe4, + 0xcd, 0x21, 0xcb, 0xff, 0x95, 0x55, 0xfd, 0xbf, 0x0c, 0x73, 0x23, 0x97, 0xf7, 0x86, 0x25, 0x9e, 0x39, 0x50, 0x7e, 0x72, 0x47, 0xb9, 0x36, 0x72, - 0xcc, 0x39, 0x7b, 0x59, 0xf1, 0xca, 0x09, 0xe2, 0x74, 0x5b, 0xf1, 0x1b, + 0xcc, 0x39, 0x7b, 0x59, 0xc9, 0xca, 0x09, 0xe2, 0x74, 0x5b, 0xf1, 0x1b, 0xff, 0xce, 0xaf, 0x95, 0x81, 0x96, 0x75, 0x18, 0x72, 0xfc, 0x9b, 0xdc, 0x30, 0xe5, 0x22, 0x28, 0x44, 0xc3, 0x8a, 0x55, 0x42, 0xb3, 0x2c, 0x2f, 0x55, 0x35, 0x21, 0x7f, 0xf9, 0x08, 0xc2, 0x80, 0x11, 0x83, 0x5f, 0x82, - 0x82, 0xe1, 0x39, 0x7b, 0x61, 0xf8, 0xe5, 0xdf, 0xac, 0xe5, 0xff, 0xec, + 0x82, 0xe1, 0x39, 0x7b, 0x61, 0xe4, 0xe5, 0xdf, 0xac, 0xe5, 0xff, 0xec, 0x9b, 0xb0, 0x2a, 0x8e, 0x7b, 0xa0, 0x39, 0x4a, 0x9f, 0x17, 0x46, 0x2b, - 0x92, 0x28, 0xe5, 0x08, 0x0a, 0x44, 0x79, 0xea, 0x19, 0x37, 0xff, 0xf9, - 0x33, 0xe9, 0x6f, 0xdd, 0x86, 0x42, 0x07, 0x94, 0x35, 0x27, 0x2f, 0xf3, - 0x8f, 0x25, 0xef, 0xf0, 0x9c, 0xbf, 0xf0, 0x37, 0xc9, 0x8a, 0x75, 0xfb, - 0x07, 0x2f, 0xd9, 0xe0, 0x67, 0xc7, 0x2f, 0x2b, 0x9f, 0x1c, 0xba, 0x26, - 0xe4, 0x78, 0xde, 0x28, 0xa1, 0x45, 0xc0, 0x21, 0x11, 0x7f, 0xff, 0xfe, - 0x00, 0xf2, 0x6d, 0xfe, 0x96, 0x9f, 0xfe, 0x5b, 0x04, 0x7d, 0xdc, 0x41, - 0xc5, 0x4e, 0x5f, 0xff, 0xef, 0x03, 0x07, 0x92, 0x67, 0x86, 0x3f, 0xe5, - 0x88, 0x13, 0x97, 0xfc, 0xcc, 0x67, 0x26, 0x35, 0xf1, 0x91, 0xca, 0xd2, - 0x28, 0xd8, 0xc5, 0x7f, 0xfd, 0xad, 0x67, 0xb7, 0xd4, 0xce, 0x5d, 0xfe, + 0xe2, 0x28, 0xe5, 0x08, 0x0a, 0x44, 0x79, 0xea, 0x19, 0x37, 0xff, 0xf9, + 0x33, 0x99, 0x6f, 0xdd, 0x86, 0x42, 0x07, 0xe4, 0x35, 0x27, 0x2f, 0xf3, + 0x8f, 0xc5, 0xef, 0xf0, 0x9c, 0xbf, 0xf0, 0x37, 0xf1, 0x8a, 0x75, 0xfb, + 0x07, 0x2f, 0xd9, 0xe0, 0x67, 0x27, 0x2f, 0x2b, 0x9c, 0x9c, 0xba, 0x26, + 0xf8, 0x78, 0xde, 0x28, 0xa1, 0x45, 0xc0, 0x21, 0x11, 0x7f, 0xff, 0xfe, + 0x00, 0xfc, 0x6d, 0xf9, 0x96, 0x9f, 0xff, 0x9b, 0x04, 0x73, 0xdc, 0x41, + 0xc5, 0x4e, 0x5f, 0xff, 0xef, 0x03, 0x07, 0xe2, 0x67, 0x86, 0x3f, 0xf9, + 0x88, 0x13, 0x97, 0xfc, 0xcc, 0x67, 0xc6, 0x35, 0xf1, 0x91, 0xca, 0xd2, + 0x28, 0xd8, 0xc5, 0x7f, 0xfd, 0xad, 0x67, 0xb7, 0xd4, 0xcf, 0x9d, 0xfe, 0x0e, 0x52, 0x1f, 0xa8, 0x08, 0xeb, 0x13, 0xc3, 0xec, 0x74, 0x57, 0xec, 0x15, 0xa8, 0xc3, 0x97, 0xff, 0x77, 0x20, 0x66, 0x1c, 0xf6, 0xdc, 0xe5, - 0xa5, 0xe3, 0xea, 0xe0, 0x28, 0xbf, 0xff, 0x07, 0x19, 0xcb, 0x83, 0xd1, - 0xb9, 0xa4, 0xfa, 0x9c, 0xe5, 0xff, 0xfd, 0xe4, 0x9f, 0x03, 0xc9, 0x8f, + 0xa5, 0xe3, 0xea, 0xe0, 0x28, 0xbf, 0xff, 0x07, 0x19, 0xf3, 0x83, 0xd1, + 0xb9, 0xa4, 0xfa, 0x9c, 0xe5, 0xff, 0xfd, 0xe4, 0x9f, 0x03, 0xf1, 0x8f, 0x2d, 0x24, 0xee, 0xc3, 0x97, 0xfa, 0x77, 0x60, 0xc6, 0xa6, 0x39, 0x7f, - 0xdf, 0x62, 0xbf, 0xb3, 0x39, 0x6b, 0x11, 0x24, 0x8b, 0xd7, 0xfd, 0x83, - 0x3f, 0x2f, 0xdd, 0xe6, 0x39, 0x7f, 0xfd, 0x80, 0xd7, 0x29, 0xba, 0x05, - 0x53, 0x05, 0x53, 0x97, 0xff, 0xcf, 0xe8, 0xd0, 0x18, 0x9b, 0xe5, 0xb9, - 0x6c, 0xe5, 0xff, 0x6a, 0x78, 0x9e, 0x70, 0x6a, 0x73, 0x97, 0xfe, 0xe5, - 0x37, 0x40, 0xaa, 0x60, 0xaa, 0x72, 0xff, 0x0f, 0x2d, 0x81, 0xa0, 0x34, + 0xdc, 0xe2, 0xbf, 0xb3, 0x3e, 0x6b, 0x11, 0x24, 0x8b, 0xd7, 0xfd, 0x83, + 0x3f, 0xcf, 0xdd, 0xe6, 0x39, 0x7f, 0xfd, 0x80, 0xd7, 0xc9, 0xba, 0x05, + 0x53, 0x05, 0x53, 0x97, 0xff, 0xcf, 0xe8, 0xd0, 0x18, 0x9b, 0xf9, 0xb9, + 0x6c, 0xe5, 0xff, 0x6a, 0x78, 0x9e, 0x70, 0x6a, 0x73, 0x97, 0xfe, 0xf9, + 0x37, 0x40, 0xaa, 0x60, 0xaa, 0x72, 0xff, 0x0f, 0xcd, 0x81, 0xa0, 0x34, 0x72, 0xb0, 0xfe, 0xc0, 0x87, 0x50, 0x8d, 0xad, 0xc2, 0xe6, 0xff, 0xf4, - 0xfc, 0xb7, 0xd0, 0x72, 0xf6, 0xf7, 0x1a, 0x39, 0x7f, 0xfd, 0xd8, 0x9f, - 0x90, 0xe7, 0x17, 0xef, 0x63, 0xe3, 0x97, 0xff, 0xfd, 0xf6, 0xd3, 0x1b, - 0xe5, 0xdc, 0xf6, 0xf2, 0x7e, 0x58, 0x81, 0x39, 0x41, 0x46, 0x06, 0x2a, + 0xff, 0x37, 0xd0, 0x7c, 0xf6, 0xf7, 0x1a, 0x39, 0x7f, 0xfd, 0xd8, 0x9f, + 0xe0, 0xe7, 0x17, 0xef, 0x63, 0x93, 0x97, 0xff, 0xfd, 0xce, 0xd3, 0x1b, + 0xf9, 0xdc, 0xf6, 0xf2, 0x7f, 0x98, 0x81, 0x39, 0x41, 0x46, 0x06, 0x2a, 0x5f, 0xf0, 0xe6, 0xb1, 0x78, 0x81, 0x39, 0x7f, 0x4f, 0xe9, 0x86, 0x18, - 0x72, 0xff, 0xfe, 0xc9, 0xf1, 0x02, 0x20, 0xef, 0x28, 0x0b, 0xcd, 0xb3, + 0x72, 0xff, 0xfe, 0xc9, 0xf1, 0x02, 0x20, 0xef, 0xc8, 0x0b, 0xcd, 0xb3, 0x97, 0xfd, 0x8d, 0xe7, 0x53, 0x5d, 0x73, 0x95, 0x8a, 0x8b, 0x52, 0x31, 0x1e, 0x91, 0x39, 0xb6, 0xcb, 0xfc, 0xbb, 0x53, 0xb2, 0x6b, 0x02, 0xce, - 0xac, 0x3b, 0x97, 0x1f, 0x57, 0xd0, 0x93, 0x42, 0xbd, 0x43, 0xbd, 0x8a, + 0xac, 0x3b, 0x97, 0x1f, 0x57, 0x30, 0x93, 0x42, 0xbd, 0x43, 0xbd, 0x8a, 0x9d, 0x3c, 0x15, 0x4d, 0xc6, 0x59, 0xe9, 0x4a, 0x97, 0xfb, 0xc3, 0x9e, 0xee, 0x4e, 0x72, 0xff, 0xcf, 0xae, 0xe7, 0xa0, 0x53, 0xf3, 0x97, 0xff, - 0xc3, 0x93, 0xf2, 0xfc, 0x1e, 0xcc, 0x67, 0xed, 0x9c, 0xbe, 0x97, 0x92, - 0x73, 0x97, 0xfd, 0x8d, 0xfd, 0x2d, 0xf2, 0xf2, 0x1c, 0xbf, 0xf4, 0xa3, - 0x3f, 0xee, 0x60, 0xac, 0xe5, 0xff, 0xee, 0xa0, 0x87, 0x92, 0x8b, 0x1c, + 0xc3, 0x93, 0xfc, 0xfc, 0x1e, 0xcc, 0x67, 0xed, 0x9c, 0xbe, 0x97, 0x92, + 0x73, 0x97, 0xfd, 0x8d, 0xf3, 0x2d, 0xfc, 0xf2, 0x1c, 0xbf, 0xf4, 0xa3, + 0x3f, 0xee, 0x60, 0xac, 0xe5, 0xff, 0xee, 0xa0, 0x87, 0xe2, 0x8b, 0x1c, 0xee, 0x1c, 0xbf, 0xe7, 0xf6, 0xe6, 0x90, 0x07, 0xc7, 0x2b, 0x11, 0x85, 0x31, 0xef, 0xe9, 0x77, 0xfd, 0xd4, 0x64, 0x60, 0xfb, 0x67, 0x2f, 0xff, - 0xf0, 0x3d, 0xa0, 0x4d, 0xcb, 0xd3, 0x74, 0x1f, 0xf9, 0x33, 0x80, 0xe5, - 0xf4, 0x2e, 0x19, 0xc9, 0x1a, 0x6b, 0x31, 0x13, 0x7a, 0x85, 0x60, 0x2b, + 0xf0, 0x3d, 0xa0, 0x4d, 0xf3, 0xd3, 0x74, 0x1f, 0xf9, 0x33, 0x80, 0xe5, + 0xf4, 0x2e, 0x19, 0xf1, 0x1a, 0x6b, 0x31, 0x13, 0x7a, 0x85, 0x60, 0x2b, 0x33, 0xd1, 0xeb, 0xaa, 0x89, 0x1f, 0x04, 0x7a, 0x57, 0xff, 0xf6, 0xb1, - 0xd9, 0xc9, 0x57, 0xfb, 0xb9, 0xde, 0xc7, 0x8e, 0x5f, 0x66, 0xa6, 0x91, - 0xcb, 0xff, 0xca, 0xa7, 0xd2, 0xdf, 0x20, 0xa7, 0x18, 0x09, 0xcb, 0xfe, - 0xc9, 0xa5, 0x9d, 0xce, 0x3b, 0x39, 0x7f, 0xfe, 0x0f, 0x41, 0xbe, 0x5d, - 0x4f, 0x77, 0x35, 0x1c, 0x4e, 0x5f, 0xd9, 0xf0, 0xe6, 0x7e, 0x72, 0xb1, + 0xd9, 0xf1, 0x57, 0xe7, 0xb9, 0xde, 0xc7, 0x8e, 0x5f, 0x66, 0xa6, 0x91, + 0xcb, 0xff, 0xca, 0xa7, 0x32, 0xdf, 0xc0, 0xa7, 0x18, 0x09, 0xcb, 0xfe, + 0xc9, 0xa5, 0x9d, 0xce, 0x3b, 0x39, 0x7f, 0xfe, 0x0f, 0x41, 0xbf, 0x9d, + 0x4f, 0x77, 0x35, 0x1c, 0x4e, 0x5f, 0xd9, 0xc8, 0xe6, 0x7e, 0x72, 0xb1, 0x10, 0xe2, 0xb5, 0x74, 0x33, 0x13, 0x56, 0x54, 0x8f, 0x4a, 0x03, 0x0c, - 0x2b, 0x41, 0xcb, 0xe4, 0xd3, 0xfc, 0x72, 0xe4, 0xf2, 0x1b, 0x2d, 0x88, - 0x5f, 0xfc, 0x9c, 0x50, 0x3c, 0xa2, 0x60, 0xbb, 0x67, 0x2f, 0xff, 0xff, - 0x0a, 0x2b, 0xd7, 0x9b, 0x90, 0x83, 0x83, 0x96, 0x7d, 0x2c, 0x00, 0xff, + 0x2b, 0x41, 0xcb, 0xe4, 0xd3, 0xf2, 0x72, 0xe4, 0xf2, 0x1b, 0x2d, 0x88, + 0x5f, 0xfc, 0x9c, 0x50, 0x3f, 0x22, 0x60, 0xbb, 0x67, 0x2f, 0xff, 0xff, + 0x0a, 0x2b, 0xd7, 0x9b, 0xe0, 0x83, 0x83, 0xe6, 0x73, 0x2c, 0x00, 0xff, 0xb3, 0x97, 0xee, 0xa4, 0x0c, 0xe7, 0x29, 0x88, 0xa8, 0xe3, 0x08, 0x1b, 0xe6, 0x22, 0x36, 0x72, 0xa0, 0xf3, 0x1c, 0xaa, 0xb6, 0x9a, 0xef, 0xa3, 0x3d, 0xa9, 0x27, 0x64, 0x91, 0xc4, 0x5e, 0x98, 0x01, 0x39, 0x50, 0xd9, 0x15, 0xe5, 0x27, 0x4d, 0x25, 0xe6, 0xe9, 0x7f, 0xb1, 0xda, 0x3c, 0xa3, 0x10, 0x14, 0xdf, 0xa0, 0x7c, 0x9c, 0x4e, 0x5f, 0x7b, 0x6f, 0xf9, 0xcb, - 0xff, 0xba, 0x9c, 0x93, 0x40, 0x9d, 0xf4, 0xb3, 0x97, 0xc9, 0xd7, 0x9c, + 0xff, 0xba, 0x9f, 0x13, 0x40, 0x9d, 0xf4, 0xb3, 0x97, 0xc9, 0xd7, 0x9c, 0xe5, 0xf7, 0x18, 0xf4, 0x1c, 0xbf, 0x6f, 0x3c, 0x9b, 0x39, 0x7f, 0xf2, 0x7b, 0xa9, 0x98, 0x11, 0xc6, 0xce, 0x5e, 0xd2, 0x2a, 0x72, 0xff, 0xf8, - 0x18, 0x9d, 0xc5, 0xf5, 0x39, 0x36, 0xc5, 0x9c, 0xbd, 0xec, 0x6c, 0xe5, + 0x18, 0x9d, 0xc5, 0xf5, 0x3e, 0x36, 0xc5, 0x9c, 0xbd, 0xec, 0x6c, 0xe5, 0xec, 0x04, 0xe2, 0x7d, 0xfe, 0x52, 0xbf, 0x03, 0x87, 0x17, 0xf1, 0xcb, - 0xfb, 0xaf, 0x3f, 0x29, 0x78, 0xe5, 0xfc, 0xf3, 0x29, 0xb8, 0xc3, 0x97, - 0xe7, 0xd0, 0xfc, 0x87, 0x2a, 0x11, 0x64, 0x85, 0x9d, 0x31, 0xf1, 0x75, + 0xfb, 0xaf, 0x3f, 0xc9, 0x78, 0xe5, 0xfc, 0xf3, 0x29, 0xb8, 0xc3, 0x97, + 0xe7, 0xd0, 0xf2, 0x87, 0x2a, 0x11, 0x64, 0x85, 0x9d, 0x31, 0xf1, 0x75, 0xee, 0xb8, 0x9c, 0xa0, 0xab, 0x07, 0xc2, 0x85, 0x48, 0xd6, 0x8e, 0x84, 0x53, 0x11, 0xb0, 0x9d, 0xd0, 0x86, 0x11, 0x9e, 0x87, 0x2b, 0x67, 0x77, 0xc3, 0xe8, 0x61, 0xcb, 0xfd, 0xd8, 0x41, 0x7d, 0x2a, 0x72, 0xfe, 0x84, - 0x17, 0xd2, 0xa7, 0x2f, 0xe7, 0xff, 0x5a, 0x4d, 0x72, 0x3d, 0xee, 0x99, - 0x5f, 0xff, 0xfe, 0xe4, 0xc8, 0xcf, 0x72, 0xc9, 0x27, 0x11, 0xcd, 0xf2, - 0x80, 0xbc, 0xdb, 0x39, 0x7f, 0x0a, 0xf9, 0x37, 0xbf, 0xce, 0x54, 0x91, + 0x17, 0xd2, 0xa7, 0x2f, 0xe7, 0xff, 0x5a, 0x4d, 0x7c, 0x3d, 0xee, 0x99, + 0x5f, 0xff, 0xfe, 0xf8, 0xc8, 0xcf, 0x7c, 0xc9, 0x27, 0x11, 0xcd, 0xfc, + 0x80, 0xbc, 0xdb, 0x39, 0x7f, 0x0a, 0xfe, 0x37, 0xbf, 0xce, 0x54, 0x91, 0x60, 0xef, 0xd4, 0x89, 0xcc, 0x7e, 0xfe, 0x08, 0x7b, 0xde, 0xdf, 0x90, - 0xe5, 0xe9, 0xbf, 0xf8, 0xe5, 0xe8, 0x57, 0x92, 0xcd, 0xe7, 0xe3, 0x96, + 0xe5, 0xe9, 0xbf, 0xe4, 0xe5, 0xe8, 0x57, 0xe2, 0xcd, 0xe7, 0xe3, 0x96, 0xfc, 0xe5, 0xfd, 0x1a, 0x9e, 0x35, 0x39, 0xcb, 0xff, 0x26, 0x37, 0xb0, 0x4c, 0x30, 0xc3, 0x97, 0x80, 0xfb, 0x39, 0x52, 0x44, 0x53, 0x0b, 0xd4, - 0x3f, 0xbf, 0xff, 0x93, 0x5c, 0xb1, 0x30, 0x55, 0xea, 0x63, 0x31, 0x67, - 0x2f, 0xff, 0xfc, 0xcd, 0xaf, 0xb0, 0xbf, 0xa4, 0x20, 0x0f, 0x24, 0x55, - 0xc7, 0xf3, 0x97, 0xff, 0xfa, 0x7d, 0x43, 0x36, 0x08, 0xe5, 0x1a, 0x80, + 0x3f, 0xbf, 0xff, 0x93, 0x5f, 0x31, 0x30, 0x55, 0xea, 0x63, 0x31, 0x67, + 0x2f, 0xff, 0xfc, 0xcd, 0xaf, 0xb0, 0xbe, 0x64, 0x20, 0x0f, 0xc4, 0x55, + 0xc7, 0xf3, 0x97, 0xff, 0xfa, 0x7d, 0x43, 0x36, 0x08, 0xf9, 0x1a, 0x80, 0xf6, 0x18, 0x72, 0xb1, 0x1a, 0x88, 0xe3, 0x58, 0x9a, 0x7e, 0xa3, 0x2e, - 0xbf, 0x7f, 0xb4, 0xf9, 0xb3, 0x97, 0xfe, 0xd6, 0x7d, 0xdf, 0xa1, 0x93, - 0xc1, 0xcb, 0xff, 0xff, 0xda, 0xd2, 0x4f, 0xcb, 0xb9, 0xe1, 0x89, 0xbb, - 0x93, 0xc7, 0xde, 0x02, 0xce, 0x5f, 0xff, 0xfd, 0x0a, 0xf6, 0x39, 0x0e, - 0x01, 0x5e, 0x5f, 0x4b, 0x68, 0x2a, 0x44, 0xe7, 0x2f, 0xdf, 0x6d, 0x30, + 0xbf, 0x7f, 0xb4, 0xe5, 0xb3, 0x97, 0xfe, 0xd6, 0x73, 0xde, 0x61, 0x93, + 0xc1, 0xcb, 0xff, 0xff, 0xda, 0xd2, 0x4f, 0xf3, 0xb9, 0xe1, 0x89, 0xbb, + 0x93, 0xc7, 0x3e, 0x02, 0xce, 0x5f, 0xff, 0xfd, 0x0a, 0xf6, 0x3e, 0x0e, + 0x01, 0x5f, 0x9c, 0xcb, 0x68, 0x2a, 0x44, 0xe7, 0x2f, 0xdc, 0xed, 0x30, 0x4e, 0x56, 0x22, 0x80, 0x0f, 0x34, 0x89, 0x9f, 0xf6, 0x31, 0xdb, 0xff, - 0xb4, 0x3f, 0x66, 0xc1, 0x30, 0xc3, 0x0e, 0x5f, 0xf2, 0x2b, 0xd8, 0x49, + 0xb4, 0x3c, 0xe6, 0xc1, 0x30, 0xc3, 0x0e, 0x5f, 0xf2, 0x2b, 0xd8, 0x49, 0xe1, 0x53, 0x96, 0x92, 0x1f, 0xfe, 0xd1, 0x6f, 0xf8, 0x41, 0x30, 0xe7, 0x5f, 0xc7, 0x2f, 0xf7, 0x61, 0xb0, 0xf5, 0xd8, 0x72, 0xff, 0x99, 0x9b, - 0xe5, 0x30, 0xc3, 0x0e, 0x5f, 0xff, 0xb7, 0x3b, 0xf2, 0x0f, 0x63, 0x5a, - 0xce, 0x31, 0xf1, 0xca, 0x0a, 0x32, 0x98, 0x69, 0xe3, 0xbb, 0xff, 0xfe, - 0x7d, 0x77, 0x3c, 0x98, 0x33, 0xee, 0x30, 0x43, 0xd8, 0x39, 0x7d, 0xee, - 0x53, 0xe8, 0xe5, 0x7c, 0x88, 0x97, 0x63, 0xbf, 0xff, 0xf7, 0xd9, 0x38, - 0x38, 0x39, 0x7d, 0x2f, 0x43, 0x7c, 0xb3, 0x5f, 0xff, 0x07, 0x2f, 0xff, - 0x36, 0xe3, 0x3b, 0x00, 0x81, 0x41, 0x43, 0x97, 0xf4, 0xdf, 0x48, 0x11, - 0xe3, 0x97, 0xff, 0xf4, 0xa3, 0x5f, 0x4b, 0x7c, 0xbb, 0x08, 0x2f, 0xa5, + 0xf9, 0x30, 0xc3, 0x0e, 0x5f, 0xff, 0xb7, 0x3b, 0xfc, 0x0f, 0x63, 0x5a, + 0xce, 0x31, 0xc9, 0xca, 0x0a, 0x32, 0x98, 0x69, 0xe3, 0xbb, 0xff, 0xfe, + 0x7d, 0x77, 0x3c, 0x98, 0x33, 0xee, 0x30, 0x43, 0xd8, 0x39, 0x7d, 0xef, + 0x93, 0xe8, 0xe5, 0x72, 0x88, 0x97, 0x63, 0xbf, 0xff, 0xf7, 0x39, 0x38, + 0x38, 0x3e, 0x73, 0x2f, 0x43, 0x7f, 0x33, 0x5f, 0xff, 0x07, 0x2f, 0xff, + 0x36, 0xe3, 0x3b, 0x00, 0x81, 0x41, 0x43, 0x97, 0xf4, 0xdc, 0xc8, 0x11, + 0xe3, 0x97, 0xff, 0xf4, 0xa3, 0x5c, 0xcb, 0x7f, 0x3b, 0x08, 0x2f, 0xa5, 0x4e, 0x5f, 0xd9, 0x2f, 0x0e, 0x48, 0xe5, 0xff, 0x75, 0xd8, 0x39, 0xd7, 0xf1, 0xcb, 0xbf, 0x6c, 0xe5, 0xf3, 0x4c, 0xd4, 0x1c, 0xb6, 0x68, 0xde, - 0x71, 0x19, 0xa8, 0x4d, 0x57, 0xe3, 0x0e, 0xaf, 0x6c, 0xb3, 0xce, 0x77, - 0xff, 0x67, 0xb7, 0xcb, 0x58, 0x9d, 0x80, 0x9c, 0xbf, 0xb3, 0xda, 0xd6, + 0x71, 0x19, 0xa8, 0x4d, 0x57, 0x93, 0x0e, 0xaf, 0x6c, 0xb3, 0xce, 0x77, + 0xff, 0x67, 0xb7, 0xf3, 0x58, 0x9d, 0x80, 0x9c, 0xbf, 0xb3, 0xda, 0xd6, 0x48, 0xe5, 0x1c, 0xbf, 0x67, 0x47, 0x16, 0x72, 0xbf, 0x36, 0x22, 0x17, - 0x53, 0x1f, 0xff, 0x97, 0xaf, 0x67, 0xde, 0x39, 0x78, 0x73, 0x7c, 0x8f, + 0x53, 0x1f, 0xff, 0x97, 0xaf, 0x67, 0x3e, 0x39, 0x78, 0x73, 0x7f, 0x0f, 0x01, 0xac, 0x8e, 0xff, 0xb1, 0x9d, 0x84, 0xd0, 0x1a, 0xce, 0x50, 0x59, - 0x0b, 0x58, 0x52, 0xa9, 0x5a, 0xe3, 0x80, 0xfa, 0x15, 0x08, 0x4f, 0xa8, + 0x0b, 0x58, 0x52, 0xa9, 0x5a, 0xe3, 0x80, 0xe6, 0x15, 0x08, 0x4f, 0xa8, 0xc0, 0xbb, 0x0b, 0x97, 0x23, 0xdb, 0xd7, 0xa3, 0x9e, 0x02, 0x5f, 0x18, 0xc1, 0x14, 0x37, 0xbf, 0xe8, 0x60, 0xe0, 0x74, 0x93, 0x9c, 0xbf, 0xff, - 0xcd, 0xf4, 0x11, 0xf7, 0x2d, 0x6a, 0x27, 0x17, 0x7d, 0x2a, 0x72, 0xff, + 0xcd, 0xf4, 0x11, 0xcf, 0xcd, 0x6a, 0x27, 0x17, 0x7d, 0x2a, 0x72, 0xff, 0x0e, 0x03, 0x15, 0x97, 0xe7, 0x29, 0xd1, 0x34, 0xdb, 0x35, 0x49, 0x1e, - 0xb9, 0x0d, 0x2b, 0xca, 0xc6, 0x8e, 0x5f, 0xf8, 0x73, 0x96, 0xb3, 0xa3, - 0x93, 0x1c, 0xbf, 0xff, 0xdd, 0x7f, 0xf7, 0xc8, 0x73, 0x88, 0xe6, 0xf1, + 0xb9, 0x0d, 0x2b, 0xca, 0xc6, 0x8e, 0x5f, 0xf8, 0x73, 0xe6, 0xb3, 0xa3, + 0x93, 0x1c, 0xbf, 0xff, 0xdd, 0x7f, 0xf7, 0xf0, 0x73, 0x88, 0xe6, 0xf1, 0x90, 0xb3, 0x95, 0x32, 0x2f, 0xc4, 0x77, 0x67, 0xf5, 0xc2, 0x99, 0xad, - 0x11, 0x09, 0xcc, 0xa4, 0xed, 0x7d, 0x1e, 0xe3, 0xc3, 0x9a, 0xfe, 0xce, - 0xa8, 0x3f, 0x7e, 0x72, 0xfe, 0xee, 0x0f, 0xbf, 0x01, 0xcb, 0xfe, 0x08, - 0x63, 0xfe, 0x59, 0xf7, 0x8e, 0x5c, 0xcd, 0x9c, 0xbc, 0xfb, 0x43, 0x95, + 0x11, 0x09, 0xcc, 0xa4, 0xed, 0x73, 0x1e, 0xe3, 0xc3, 0x9a, 0xfe, 0xce, + 0xa8, 0x3c, 0xfe, 0x72, 0xfe, 0xee, 0x0f, 0xbf, 0x01, 0xcb, 0xfe, 0x08, + 0x63, 0xff, 0x99, 0xcf, 0x8e, 0x5c, 0xcd, 0x9c, 0xbc, 0xfb, 0x43, 0x95, 0x06, 0xcb, 0xf1, 0x7a, 0x44, 0x48, 0x0b, 0x7d, 0xfe, 0xde, 0xe1, 0x27, 0x7f, 0x1c, 0xbf, 0x95, 0x1c, 0xdc, 0x68, 0xe5, 0xa5, 0x07, 0xc0, 0x03, 0x3b, 0x48, 0xe5, 0xf4, 0x31, 0xc2, 0x72, 0xa0, 0xd9, 0x08, 0x8d, 0xfe, 0xc9, 0xbb, 0x9e, 0x80, 0x9c, 0xbf, 0x87, 0xce, 0xc4, 0xf1, 0xcb, 0x48, 0xe5, 0x41, 0xbd, 0xf1, 0x65, 0xe1, 0x5c, 0x1c, 0xbf, 0xff, 0xfe, 0xee, - 0x7b, 0x6f, 0x37, 0x21, 0xcf, 0xa5, 0x80, 0x9c, 0x70, 0x3d, 0x49, 0x8e, + 0x7b, 0x6f, 0x37, 0xc1, 0xce, 0x65, 0x80, 0x9c, 0x70, 0x3d, 0x49, 0x8e, 0x5c, 0x05, 0x4e, 0x52, 0x22, 0xd3, 0x43, 0x7e, 0x84, 0x0d, 0xfe, 0xfd, - 0x3d, 0xef, 0x63, 0x67, 0x2f, 0xec, 0x9c, 0x73, 0xed, 0x9c, 0xbf, 0xf8, + 0x3d, 0xef, 0x63, 0x67, 0x2f, 0xec, 0x9c, 0x73, 0x9d, 0x9c, 0xbf, 0xf8, 0x7f, 0x69, 0x9d, 0x48, 0x63, 0x84, 0xe5, 0xff, 0xff, 0xfa, 0x5b, 0xd8, - 0x23, 0xc8, 0x1c, 0x19, 0xb9, 0x0e, 0x6a, 0x07, 0xdd, 0xce, 0x03, 0x97, - 0xff, 0x7d, 0x2d, 0xe3, 0x3e, 0x8e, 0xf6, 0x0e, 0x57, 0xc8, 0xcc, 0xd4, + 0x23, 0xc8, 0x1c, 0x19, 0xbe, 0x0e, 0x6a, 0x07, 0xdd, 0xce, 0x03, 0x97, + 0xff, 0x73, 0x2d, 0xe3, 0x39, 0x8e, 0xf6, 0x0e, 0x57, 0x28, 0xcc, 0xd4, 0x21, 0xad, 0xb3, 0x95, 0x89, 0xa5, 0x82, 0x31, 0x15, 0x0a, 0x6d, 0x39, - 0xcb, 0xf6, 0xb3, 0xe9, 0x6c, 0xe5, 0xe5, 0xf7, 0x0e, 0x5b, 0x27, 0x3c, - 0x5d, 0x14, 0xdf, 0xf7, 0xd1, 0xa9, 0xf9, 0x62, 0x04, 0xe5, 0xd3, 0x21, - 0xca, 0xc4, 0x69, 0x0a, 0xb8, 0x0a, 0x38, 0x9e, 0x5f, 0xd9, 0xf4, 0xa3, - 0xf8, 0x39, 0x7e, 0x1c, 0xeb, 0xf8, 0xe5, 0x7c, 0x7a, 0x8c, 0x2e, 0xbe, - 0x4e, 0x39, 0xa3, 0x95, 0x07, 0x8d, 0xd2, 0x3b, 0xee, 0x4b, 0x9d, 0xb3, - 0x97, 0xe9, 0xf9, 0x02, 0x26, 0x39, 0x7f, 0xff, 0xc3, 0x1f, 0xfd, 0x2d, + 0xcb, 0xf6, 0xb3, 0x99, 0x6c, 0xe5, 0xe5, 0xf7, 0x0e, 0x5b, 0x27, 0x3c, + 0x5d, 0x14, 0xdf, 0xf7, 0x31, 0xa9, 0xfe, 0x62, 0x04, 0xe5, 0xd3, 0x21, + 0xca, 0xc4, 0x69, 0x0a, 0xb8, 0x0a, 0x38, 0x9e, 0x5f, 0xd9, 0xcc, 0xa3, + 0xf8, 0x39, 0x7e, 0x1c, 0xeb, 0xf8, 0xe5, 0x72, 0x7a, 0x8c, 0x2e, 0xbe, + 0x4e, 0x39, 0xa3, 0x95, 0x07, 0x8d, 0xd2, 0x3b, 0xef, 0x8b, 0x9d, 0xb3, + 0x97, 0xe9, 0xfe, 0x02, 0x26, 0x39, 0x7f, 0xff, 0xc3, 0x1f, 0xf3, 0x2d, 0x82, 0x3c, 0x38, 0x14, 0xcd, 0x4c, 0x72, 0x9d, 0x12, 0x7e, 0x2c, 0xa8, - 0x5f, 0xea, 0x09, 0x86, 0x42, 0xfb, 0xe8, 0x40, 0xa2, 0xcc, 0xc3, 0xfd, + 0x5f, 0xea, 0x09, 0x86, 0x42, 0xfb, 0x98, 0x40, 0xa2, 0xcc, 0xc3, 0xfd, 0x70, 0x78, 0x6a, 0x7e, 0x68, 0x26, 0xbb, 0x8d, 0xe7, 0xd1, 0x84, 0x82, - 0x1a, 0xfc, 0x48, 0x54, 0x85, 0xd5, 0xfa, 0x49, 0xac, 0xf8, 0xe5, 0xed, - 0xf7, 0x0e, 0x5f, 0xb3, 0x73, 0xe3, 0x67, 0x2b, 0xe3, 0xed, 0x98, 0xa3, - 0xa3, 0x97, 0xff, 0xfb, 0xdb, 0xee, 0x7d, 0x8f, 0xf7, 0x20, 0xc4, 0xfc, - 0x95, 0x54, 0xe5, 0xff, 0x62, 0xa3, 0x9e, 0xea, 0x36, 0x72, 0xa1, 0x14, - 0x7a, 0x6a, 0xbf, 0xfe, 0x9f, 0x16, 0x1e, 0xa6, 0x2b, 0xc9, 0x50, 0x41, - 0xcb, 0xff, 0xa4, 0x9e, 0xee, 0x6b, 0x59, 0xed, 0x9c, 0xbf, 0xee, 0x4a, + 0x1a, 0xfc, 0x48, 0x54, 0x85, 0xd5, 0xfa, 0x49, 0xac, 0xe4, 0xe5, 0xed, + 0xf7, 0x0e, 0x5f, 0xb3, 0x73, 0xe3, 0x67, 0x2b, 0x93, 0xed, 0x98, 0xa3, + 0xa3, 0x97, 0xff, 0xfb, 0xdb, 0xee, 0x73, 0x8f, 0xcf, 0xc0, 0xc4, 0xff, + 0x15, 0x54, 0xe5, 0xff, 0x62, 0xa3, 0x9e, 0xea, 0x36, 0x72, 0xa1, 0x14, + 0x7a, 0x6a, 0xbf, 0xfe, 0x9f, 0x16, 0x1e, 0xa6, 0x2b, 0xf1, 0x50, 0x41, + 0xcb, 0xff, 0xa4, 0x9e, 0xee, 0x6b, 0x59, 0xed, 0x9c, 0xbf, 0xef, 0x8a, 0x79, 0x38, 0xc0, 0xac, 0xe5, 0x22, 0x35, 0x66, 0x54, 0xea, 0x25, 0xff, - 0xa5, 0xbf, 0x3c, 0xfc, 0x03, 0x9f, 0x1c, 0xbf, 0xd2, 0xec, 0x48, 0x0e, - 0xa1, 0xcb, 0x47, 0xc7, 0xee, 0x28, 0x77, 0xfd, 0xd9, 0xd3, 0x07, 0xe9, - 0x6c, 0xe5, 0xff, 0x7d, 0xdc, 0x58, 0xe0, 0x1a, 0xce, 0x5f, 0xff, 0x37, + 0xa5, 0xbf, 0x3c, 0xfc, 0x03, 0x9c, 0x9c, 0xbf, 0xd2, 0xec, 0x48, 0x0e, + 0xa1, 0xcb, 0x47, 0x27, 0xee, 0x28, 0x77, 0xfd, 0xd9, 0xd3, 0x07, 0x99, + 0x6c, 0xe5, 0xff, 0x73, 0xdc, 0x58, 0xe0, 0x1a, 0xce, 0x5f, 0xff, 0x37, 0x8b, 0xde, 0x7a, 0x6c, 0x54, 0x73, 0xf3, 0x96, 0x94, 0x23, 0x23, 0x0e, - 0x90, 0xf2, 0xfe, 0x4f, 0xbf, 0xd3, 0x84, 0xe5, 0xec, 0xd7, 0xe7, 0x2f, + 0x90, 0xf2, 0xfe, 0x4e, 0x7f, 0xd3, 0x84, 0xe5, 0xec, 0xd7, 0xe7, 0x2f, 0xdb, 0x4c, 0x1f, 0xce, 0x5b, 0x10, 0xf1, 0x36, 0x3b, 0x7e, 0x4f, 0xff, 0xcd, 0x1c, 0xae, 0xa3, 0x08, 0x5c, 0xf6, 0x4d, 0x7d, 0xc1, 0xec, 0xe9, - 0xcb, 0x91, 0x87, 0x2f, 0xff, 0xfd, 0xf4, 0x9f, 0xee, 0x42, 0x0e, 0x0e, - 0x59, 0xf4, 0xb0, 0x03, 0xfe, 0xce, 0x53, 0x11, 0x1b, 0xc0, 0x2d, 0x79, - 0xa2, 0x70, 0xe7, 0x2b, 0x92, 0x65, 0x53, 0x97, 0xe4, 0x2c, 0x9a, 0x13, - 0x5f, 0xff, 0xff, 0x7d, 0xb0, 0x47, 0xdc, 0xbb, 0x81, 0xe4, 0x38, 0x05, - 0x79, 0x6f, 0xff, 0xd3, 0xc7, 0x2f, 0xff, 0xff, 0x36, 0x38, 0x16, 0x32, + 0xcb, 0x91, 0x87, 0x2f, 0xff, 0xfd, 0xcc, 0x9f, 0x9f, 0x82, 0x0e, 0x0f, + 0x99, 0xcc, 0xb0, 0x03, 0xfe, 0xce, 0x53, 0x11, 0x1b, 0xc0, 0x2d, 0x79, + 0xa2, 0x70, 0xe7, 0x2b, 0xe2, 0x65, 0x53, 0x97, 0xe4, 0x2c, 0x9a, 0x13, + 0x5f, 0xff, 0xff, 0x73, 0xb0, 0x47, 0x3f, 0x3b, 0x81, 0xf8, 0x38, 0x05, + 0x7e, 0x6f, 0xff, 0xd3, 0xc7, 0x2f, 0xff, 0xff, 0x36, 0x38, 0x16, 0x32, 0x3d, 0xbc, 0xf6, 0xf4, 0x98, 0xb1, 0xc0, 0x9c, 0xa8, 0x47, 0xfe, 0x42, - 0x26, 0xfd, 0x03, 0xf3, 0xce, 0x72, 0xff, 0xff, 0xff, 0xd8, 0xb8, 0xec, + 0x26, 0xfd, 0x03, 0xcb, 0xce, 0x72, 0xff, 0xff, 0xff, 0xd8, 0xb8, 0xec, 0x33, 0xd9, 0xbd, 0xc6, 0xb5, 0x03, 0x93, 0xe0, 0x36, 0x09, 0x86, 0x18, 0x72, 0xf0, 0x34, 0xa9, 0xca, 0x62, 0x2d, 0x9a, 0x42, 0x62, 0xfc, 0xff, 0xa8, 0xf3, 0x9c, 0xac, 0x3d, 0x44, 0x2a, 0xbc, 0x9f, 0xc1, 0xcb, 0xf8, - 0x23, 0x9d, 0x7f, 0x1c, 0xbf, 0x7b, 0xe9, 0x26, 0x8e, 0x56, 0x1e, 0xae, + 0x23, 0x9d, 0x7f, 0x1c, 0xbf, 0x7b, 0x99, 0x26, 0x8e, 0x56, 0x1e, 0xae, 0xcb, 0x2a, 0x74, 0x49, 0x7e, 0xe3, 0x7b, 0x4e, 0xa1, 0xcb, 0xf4, 0x79, 0x89, 0xe3, 0x96, 0x9d, 0xcf, 0x10, 0x03, 0xb7, 0xfe, 0x85, 0x78, 0x01, - 0x83, 0x32, 0x8c, 0x39, 0x7f, 0xff, 0xff, 0x95, 0x1c, 0xe4, 0x98, 0x2f, - 0xee, 0xc4, 0xdc, 0x87, 0x3a, 0x9e, 0xd8, 0x16, 0x08, 0x39, 0x58, 0x8f, - 0xcf, 0x8a, 0x00, 0x89, 0x7f, 0xec, 0xcf, 0xf7, 0xcb, 0x5b, 0x0e, 0xce, + 0x83, 0x32, 0x8c, 0x39, 0x7f, 0xff, 0xff, 0x95, 0x1c, 0xf8, 0x98, 0x2f, + 0xee, 0xc4, 0xdf, 0x07, 0x3a, 0x9e, 0xd8, 0x16, 0x08, 0x39, 0x58, 0x8f, + 0xce, 0x4a, 0x00, 0x89, 0x7f, 0xec, 0xcf, 0xf7, 0xf3, 0x5b, 0x0e, 0xce, 0x5f, 0xed, 0x62, 0xfa, 0x9a, 0x98, 0xe5, 0xbc, 0x13, 0xf6, 0xc4, 0x2b, 0xfd, 0x8b, 0x4f, 0x68, 0x0c, 0x39, 0x58, 0x7b, 0x48, 0x4f, 0x79, 0x07, 0xc7, 0x2f, 0xe9, 0x6d, 0xd8, 0x0d, 0x9c, 0xa9, 0xcf, 0x25, 0xc6, 0xef, 0xd9, 0xde, 0xbc, 0x8e, 0x5f, 0xde, 0x4d, 0x4f, 0x8b, 0x39, 0x50, 0xcc, - 0x15, 0x0c, 0x35, 0x32, 0x1e, 0xea, 0xc2, 0x9f, 0xe8, 0x77, 0xa4, 0xa1, + 0x15, 0x0c, 0x35, 0x32, 0x1e, 0xea, 0xc2, 0x9f, 0x98, 0x77, 0xa4, 0xa1, 0xfd, 0x46, 0x8c, 0xc2, 0x6e, 0xc6, 0x64, 0xf0, 0xb2, 0x18, 0xd9, 0x77, 0x18, 0x00, 0x1a, 0x5a, 0x11, 0x70, 0x13, 0xde, 0x75, 0xe1, 0xca, 0x39, - 0x7f, 0xdc, 0xbc, 0x38, 0xde, 0x26, 0xce, 0x53, 0x54, 0x78, 0xb3, 0x05, + 0x7f, 0xdf, 0x3c, 0x38, 0xde, 0x26, 0xce, 0x53, 0x54, 0x78, 0xb3, 0x05, 0xd7, 0x0c, 0x88, 0x88, 0x60, 0xa3, 0x97, 0xf6, 0x32, 0x3a, 0xfd, 0x39, - 0x77, 0x29, 0x8e, 0x57, 0x23, 0xc6, 0x09, 0x65, 0xff, 0xf7, 0xd2, 0x18, - 0xe4, 0xc1, 0x85, 0x7c, 0x93, 0x9c, 0xa8, 0x46, 0x46, 0x28, 0xa1, 0x25, - 0xfb, 0x5c, 0x87, 0x8b, 0x67, 0x2f, 0xba, 0xff, 0xc1, 0xcb, 0xdd, 0xcd, + 0x77, 0xc9, 0x8e, 0x57, 0xc3, 0xc6, 0x09, 0x65, 0xff, 0xf7, 0x32, 0x18, + 0xf8, 0xc1, 0x85, 0x7c, 0x93, 0x9c, 0xa8, 0x46, 0x46, 0x28, 0xa1, 0x25, + 0xfb, 0x5f, 0x07, 0x8b, 0x67, 0x2f, 0xba, 0xff, 0xc1, 0xcb, 0xdd, 0xcd, 0x1c, 0xa8, 0x3e, 0xb7, 0x2d, 0xe0, 0x22, 0xbf, 0xa7, 0x9a, 0x5c, 0x36, 0xa7, 0x39, 0x7e, 0x62, 0x07, 0x02, 0x72, 0xd3, 0x1c, 0xba, 0x18, 0x72, 0xde, 0x39, 0x5a, 0x34, 0xee, 0x2d, 0x41, 0x3d, 0x9e, 0x9c, 0xde, 0xd4, - 0x4c, 0x72, 0xf6, 0xdf, 0xe3, 0x94, 0xe6, 0xeb, 0xc3, 0xb7, 0x4c, 0xe7, - 0x2f, 0xe7, 0x6e, 0x3d, 0x93, 0x9c, 0xbf, 0x93, 0x5f, 0x48, 0x60, 0xe5, - 0xfe, 0x0f, 0x63, 0xe9, 0x67, 0x8e, 0x57, 0x4f, 0x87, 0xc5, 0xb7, 0xfe, + 0x4c, 0x72, 0xf6, 0xdf, 0x93, 0x94, 0xe6, 0xeb, 0xc3, 0xb7, 0x4c, 0xe7, + 0x2f, 0xe7, 0x6e, 0x3d, 0x93, 0x9c, 0xbf, 0x93, 0x5c, 0xc8, 0x60, 0xe5, + 0xfe, 0x0f, 0x63, 0x99, 0x67, 0x8e, 0x57, 0x4f, 0x87, 0xc5, 0xb7, 0xfe, 0x69, 0x03, 0xed, 0x27, 0x1c, 0x09, 0xcb, 0x86, 0x63, 0x94, 0xd5, 0x2a, 0x53, 0x83, 0x7c, 0x84, 0x02, 0x2e, 0x30, 0x80, 0x45, 0xc1, 0x08, 0xf6, - 0x84, 0x4a, 0x20, 0xdf, 0xe6, 0xf2, 0x42, 0x07, 0xd9, 0xcb, 0xf7, 0xcd, + 0x84, 0x4a, 0x20, 0xdf, 0xe6, 0xf2, 0x42, 0x07, 0xd9, 0xcb, 0xf7, 0x2d, 0xb8, 0xfe, 0x72, 0xe1, 0x54, 0xe5, 0xb6, 0x87, 0x82, 0x02, 0xab, 0xff, - 0xf3, 0x07, 0x17, 0xf7, 0x85, 0xfa, 0xc8, 0xcf, 0x1c, 0xbf, 0xfe, 0xc9, - 0xdc, 0x57, 0xcb, 0x70, 0xc7, 0xfb, 0xc7, 0x2a, 0x11, 0x4d, 0xa5, 0x4b, + 0xf3, 0x07, 0x17, 0xcf, 0x85, 0xfa, 0xc8, 0xcf, 0x1c, 0xbf, 0xfe, 0xc9, + 0xdc, 0x57, 0xf3, 0x70, 0xc7, 0xe7, 0xc7, 0x2a, 0x11, 0x4d, 0xa5, 0x4b, 0xff, 0xec, 0xe2, 0xf2, 0xc1, 0x08, 0xc4, 0x83, 0xb3, 0x97, 0xff, 0xff, - 0xc9, 0xd0, 0x31, 0x8f, 0x2e, 0x5c, 0x03, 0x8c, 0x85, 0xf2, 0x52, 0x79, - 0xdf, 0xe3, 0x97, 0xff, 0xe8, 0xd4, 0x2f, 0x19, 0x0b, 0x92, 0x6c, 0x0c, + 0xc9, 0xd0, 0x31, 0x8f, 0x2f, 0x9c, 0x03, 0x8c, 0x85, 0xfc, 0x52, 0x79, + 0xdf, 0x93, 0x97, 0xff, 0xe8, 0xd4, 0x2f, 0x19, 0x0b, 0x92, 0x6c, 0x0c, 0x39, 0x50, 0xaa, 0x3a, 0x67, 0x4e, 0xc3, 0x34, 0x48, 0xbc, 0x9e, 0xd2, 0x11, 0x17, 0xf6, 0xb2, 0x15, 0x81, 0x39, 0x78, 0x5d, 0x87, 0x2e, 0xfe, - 0x0e, 0x5f, 0xfd, 0xd6, 0x67, 0xd2, 0xdb, 0xc7, 0xd2, 0x39, 0x72, 0x93, + 0x0e, 0x5f, 0xfd, 0xd6, 0x67, 0x32, 0xdb, 0xc7, 0x32, 0x39, 0x72, 0x93, 0x9c, 0xa4, 0x3d, 0xf1, 0x46, 0xa9, 0x23, 0x75, 0x0b, 0x04, 0x6f, 0xce, 0xd4, 0xd5, 0x42, 0x2c, 0x41, 0xa9, 0x84, 0x9f, 0x09, 0x0a, 0xf6, 0xad, 0xcf, 0x86, 0x94, 0xb1, 0xc2, 0xec, 0xf1, 0x3b, 0x63, 0x3c, 0x7f, 0xb2, 0x84, 0xb8, 0x67, 0xa0, 0x72, 0xb0, 0xd0, 0x56, 0x57, 0x6a, 0xe7, 0xcb, - 0xfe, 0x9d, 0x7d, 0x49, 0x75, 0x13, 0x4a, 0x90, 0xd4, 0xf0, 0x53, 0x25, + 0xf9, 0x9d, 0x7d, 0x49, 0x75, 0x13, 0x4a, 0x90, 0xd4, 0xf0, 0x53, 0x25, 0xe2, 0xf6, 0xb3, 0x92, 0x79, 0x71, 0x3f, 0xca, 0x3b, 0xe1, 0xdc, 0x86, 0x9b, 0x3d, 0xba, 0x42, 0xaf, 0xa9, 0xae, 0xe0, 0x8e, 0x4b, 0x8c, 0x3b, 0xdb, 0x84, 0xc3, 0x49, 0x50, 0x6a, 0x4b, 0x1c, 0xe0, 0x8d, 0x06, 0xff, - 0xfe, 0x02, 0xf9, 0xfd, 0xed, 0x46, 0x7d, 0xc3, 0x05, 0xdd, 0x53, 0x95, - 0xcd, 0x57, 0xc2, 0x4a, 0x93, 0xbf, 0x9d, 0x3d, 0xb4, 0x13, 0x97, 0x93, + 0xfe, 0x02, 0xfe, 0xf3, 0xed, 0x46, 0x73, 0xc3, 0x05, 0xdd, 0x53, 0x95, + 0xf5, 0x57, 0xc2, 0x4a, 0x93, 0xbf, 0x9d, 0x3d, 0xb4, 0x13, 0x97, 0x93, 0x58, 0x72, 0x9a, 0xcf, 0x1b, 0x65, 0x77, 0xed, 0x2d, 0xdd, 0x66, 0x8a, - 0x75, 0x76, 0x7c, 0x72, 0xff, 0xf0, 0x00, 0x28, 0x31, 0xd4, 0x66, 0x6c, - 0xe5, 0xb9, 0xc2, 0x2d, 0xf0, 0x97, 0xe3, 0x46, 0x0b, 0xdf, 0xfc, 0x9a, - 0xe6, 0xd1, 0xe7, 0xf6, 0xdf, 0xf3, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x8a, - 0x8d, 0x7f, 0xe7, 0x97, 0x3c, 0xd2, 0xdd, 0xd6, 0x68, 0x9a, 0x17, 0xff, - 0x87, 0x26, 0x93, 0xea, 0x43, 0x9c, 0x5c, 0xe5, 0xf0, 0xc6, 0x7c, 0x72, - 0xb1, 0x1d, 0x6c, 0x34, 0xda, 0x67, 0x92, 0xaf, 0xf2, 0x8f, 0xc7, 0x9f, - 0x92, 0x73, 0x95, 0xcc, 0xfd, 0x60, 0xf2, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, + 0x75, 0x76, 0x72, 0x72, 0xff, 0xf0, 0x00, 0x28, 0x31, 0xd4, 0x66, 0x6c, + 0xe5, 0xbe, 0xc2, 0x2d, 0xf0, 0x97, 0x93, 0x46, 0x0b, 0xdf, 0xfc, 0x9a, + 0xfa, 0xd1, 0xe7, 0xf6, 0xdf, 0xf3, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x8a, + 0x8d, 0x7f, 0xe7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x9a, 0x17, 0xff, + 0x87, 0x26, 0x93, 0xea, 0x43, 0x9c, 0x5c, 0xe5, 0xf0, 0xc6, 0x72, 0x72, + 0xb1, 0x1d, 0x6c, 0x34, 0xda, 0x67, 0x92, 0xaf, 0xf2, 0x8f, 0xc7, 0xef, + 0x92, 0x73, 0x95, 0xf4, 0xfd, 0x60, 0xf2, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x57, 0xaf, 0xec, 0xe3, 0x03, 0xd0, 0x1c, 0xbf, 0x90, 0x21, 0x8d, 0x41, - 0xcb, 0xff, 0xfb, 0xef, 0xc4, 0x0c, 0x50, 0x21, 0x8f, 0xd9, 0x19, 0xe3, - 0x96, 0xe7, 0x88, 0xed, 0xd1, 0xa7, 0x4b, 0x94, 0x2c, 0xbf, 0x69, 0x6e, - 0xeb, 0x34, 0x56, 0xcb, 0xfe, 0x97, 0x3c, 0xd2, 0xdd, 0xd6, 0x68, 0x90, - 0x56, 0xe7, 0x87, 0xf6, 0xe6, 0x97, 0xff, 0x73, 0x79, 0x73, 0xcd, 0x2d, - 0xdd, 0x66, 0x89, 0x0d, 0x7f, 0xed, 0xf3, 0xcf, 0x20, 0x70, 0x66, 0x39, + 0xcb, 0xff, 0xfb, 0x9f, 0xc4, 0x0c, 0x50, 0x21, 0x8f, 0xd9, 0x19, 0xe3, + 0x96, 0xfb, 0x88, 0xed, 0xd1, 0xa7, 0x4b, 0x94, 0x2c, 0xbf, 0x69, 0x6e, + 0xeb, 0x34, 0x56, 0xcb, 0xfe, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x90, + 0x56, 0xfb, 0x87, 0xf6, 0xe6, 0x97, 0xff, 0x7d, 0x79, 0x7d, 0xcd, 0x2d, + 0xdd, 0x66, 0x89, 0x0d, 0x7f, 0xed, 0xfd, 0xcf, 0x20, 0x70, 0x66, 0x39, 0x79, 0xdd, 0x67, 0x8c, 0x0d, 0x50, 0x7d, 0x0b, 0x40, 0xbb, 0xad, 0x67, 0x2f, 0xfd, 0x2e, 0xc7, 0xb6, 0xd4, 0xed, 0xab, 0x13, 0x97, 0xde, 0xf6, 0x70, 0x1c, 0xbf, 0xfd, 0xc2, 0xdc, 0x2c, 0xd4, 0xf6, 0x18, 0x2f, 0xd4, - 0xd1, 0xcb, 0x7c, 0x72, 0xe4, 0x13, 0x97, 0xfb, 0x19, 0x8b, 0x17, 0x6b, + 0xd1, 0xcb, 0x72, 0x72, 0xe4, 0x13, 0x97, 0xfb, 0x19, 0x8b, 0x17, 0x6b, 0x39, 0x7f, 0x40, 0x63, 0xce, 0x13, 0x97, 0xbb, 0x9b, 0x39, 0x67, 0x39, 0x41, 0x35, 0x9e, 0x1c, 0xa0, 0xa3, 0x52, 0x61, 0x2d, 0x8a, 0xf8, 0xd1, 0x45, 0x8b, 0xef, 0x6d, 0x38, 0x9c, 0xbf, 0xf9, 0x06, 0x78, 0x55, 0x4f, - 0xff, 0x8f, 0x8e, 0x5f, 0x60, 0xff, 0xb3, 0x97, 0xff, 0x0b, 0xb7, 0xd4, - 0x79, 0x79, 0x27, 0x39, 0x7d, 0x3e, 0xfe, 0x43, 0x95, 0x88, 0x8a, 0xd1, + 0xff, 0x8e, 0x4e, 0x5f, 0x60, 0xff, 0xb3, 0x97, 0xff, 0x0b, 0xb7, 0xd4, + 0x79, 0x79, 0x27, 0x39, 0x7d, 0x3e, 0xf9, 0x43, 0x95, 0x88, 0x8a, 0xd1, 0x16, 0xd1, 0x2f, 0xce, 0x15, 0x20, 0x4e, 0x5f, 0xfb, 0x5e, 0x50, 0x5d, 0x78, 0x2b, 0x39, 0x7c, 0xb7, 0x75, 0x9a, 0x2c, 0x45, 0xfb, 0x5a, 0x71, 0xf1, 0xcb, 0xe7, 0x0f, 0x40, 0x72, 0xf2, 0x23, 0x67, 0x2f, 0x00, 0x64, @@ -1304,13 +1304,13 @@ 0x4e, 0x54, 0x1f, 0x6e, 0x15, 0x21, 0x45, 0x2a, 0x8c, 0x2e, 0xc2, 0x5a, 0xff, 0xe8, 0xcd, 0xe0, 0x85, 0x3f, 0x81, 0x39, 0x78, 0x62, 0x73, 0x94, 0x27, 0xba, 0x04, 0x1b, 0xe8, 0xd4, 0x30, 0xe5, 0x48, 0xf0, 0xb6, 0x43, - 0x79, 0x8f, 0xe3, 0x97, 0xff, 0xde, 0xcf, 0xa4, 0x20, 0xf3, 0xa0, 0xc0, - 0x4e, 0x5c, 0x9f, 0x9c, 0xbc, 0xf1, 0xf1, 0xca, 0xd2, 0x27, 0x7c, 0x38, + 0x79, 0x8f, 0xe3, 0x97, 0xff, 0xde, 0xce, 0x64, 0x20, 0xf3, 0xa0, 0xc0, + 0x4e, 0x5c, 0x9f, 0x9c, 0xbc, 0xf1, 0xc9, 0xca, 0xd2, 0x27, 0x7c, 0x38, 0xd1, 0x3b, 0x80, 0x5e, 0xff, 0xfc, 0xfa, 0x93, 0x06, 0x35, 0x01, 0xc9, 0xa3, 0xa7, 0x2f, 0xb8, 0x81, 0xf6, 0x72, 0xc8, 0x72, 0xa4, 0x88, 0x84, 0x54, 0x98, 0x92, 0xff, 0x83, 0xdc, 0x66, 0x3e, 0xa7, 0x39, 0x7e, 0xf7, - 0x9e, 0x5b, 0x39, 0x7f, 0xe0, 0x67, 0xc1, 0xe3, 0xdc, 0x79, 0x8e, 0x57, - 0xc7, 0xd5, 0xc4, 0xa2, 0xd2, 0x39, 0x7d, 0x98, 0xde, 0xce, 0x54, 0x1b, + 0x9e, 0x5b, 0x39, 0x7f, 0xe0, 0x67, 0x21, 0xe3, 0xdc, 0x79, 0x8e, 0x57, + 0x27, 0xd5, 0xc4, 0xa2, 0xd2, 0x39, 0x7d, 0x98, 0xde, 0xce, 0x54, 0x1b, 0x3f, 0x08, 0xdc, 0x01, 0x39, 0x50, 0x99, 0x8e, 0x42, 0x8f, 0x4b, 0x1b, 0x20, 0xbf, 0xdb, 0x53, 0x35, 0x99, 0x31, 0xcb, 0xfe, 0x7f, 0x6c, 0x20, 0x7d, 0x48, 0xe5, 0xf8, 0x7c, 0x20, 0x9c, 0xe5, 0x42, 0x25, 0x44, 0xd0, @@ -1318,364 +1318,364 @@ 0xc3, 0xd1, 0xd1, 0x7d, 0xf4, 0x94, 0xec, 0x1c, 0xbd, 0xa8, 0x91, 0xca, 0x73, 0x7f, 0xc4, 0x8e, 0xfe, 0x86, 0x62, 0x6a, 0x63, 0x97, 0xca, 0x47, 0x06, 0xce, 0x5f, 0xb0, 0x3d, 0x8e, 0x9c, 0xbe, 0xd2, 0x36, 0xd6, 0x72, - 0x84, 0xf3, 0x76, 0x4f, 0x7f, 0xfb, 0x48, 0xc8, 0xfb, 0xb0, 0x11, 0x76, + 0x84, 0xf3, 0x76, 0x4f, 0x7f, 0xfb, 0x48, 0xc8, 0xe7, 0xb0, 0x11, 0x76, 0xb3, 0x94, 0x14, 0x70, 0x6d, 0xcf, 0xc4, 0x35, 0x09, 0xdf, 0xa3, 0x07, - 0x48, 0x9e, 0x30, 0xdb, 0xfb, 0xe5, 0xf6, 0x3e, 0xe0, 0x39, 0x7f, 0x20, + 0x48, 0x9e, 0x30, 0xdb, 0xfb, 0x95, 0xf6, 0x39, 0xe0, 0x39, 0x7f, 0x20, 0xbb, 0x23, 0xa7, 0x2f, 0xff, 0x43, 0x22, 0x41, 0x18, 0xeb, 0xe6, 0x8e, 0x51, 0xca, 0x91, 0xe9, 0x34, 0x47, 0xbd, 0xec, 0xfc, 0xe5, 0xfc, 0xc4, 0xde, 0xd0, 0x27, 0x2f, 0x3e, 0x95, 0x39, 0x40, 0x3c, 0xa6, 0xcb, 0x6f, - 0xf2, 0xc7, 0x38, 0x8e, 0x6c, 0xe5, 0xfe, 0x6b, 0xe4, 0xa4, 0x0b, 0xaa, - 0x72, 0xff, 0x49, 0xf0, 0x73, 0xdb, 0x39, 0x58, 0x7d, 0x5f, 0x1c, 0xdf, - 0xfb, 0x3e, 0x97, 0x63, 0x6a, 0xf6, 0x0e, 0x54, 0x2a, 0x5d, 0x91, 0x9f, - 0xcf, 0xb3, 0x12, 0x69, 0x9f, 0xa4, 0x63, 0x09, 0xde, 0x02, 0x2b, 0x34, - 0x39, 0x74, 0xb6, 0x72, 0xcf, 0x23, 0x55, 0xf0, 0x9d, 0xf7, 0x90, 0x5b, - 0x29, 0x60, 0x1c, 0xb4, 0x61, 0xb3, 0xe9, 0x15, 0xff, 0x38, 0xfb, 0x7f, - 0x6d, 0xda, 0xce, 0x53, 0xa2, 0xef, 0xf5, 0xa0, 0x12, 0xdf, 0xf9, 0x80, - 0x9b, 0xed, 0xc4, 0xc9, 0xc4, 0xe5, 0xfe, 0xec, 0x30, 0x63, 0xe9, 0x1c, + 0xf2, 0xc7, 0x38, 0x8e, 0x6c, 0xe5, 0xfe, 0x6b, 0xf8, 0xa4, 0x0b, 0xaa, + 0x72, 0xff, 0x49, 0xf0, 0x73, 0xdb, 0x39, 0x58, 0x7d, 0x5c, 0x9c, 0xdf, + 0xfb, 0x39, 0x97, 0x63, 0x6a, 0xf6, 0x0e, 0x54, 0x2a, 0x5d, 0x91, 0x9f, + 0x2f, 0xb3, 0x12, 0x69, 0x9f, 0xa4, 0x63, 0x09, 0xde, 0x02, 0x2b, 0x34, + 0x39, 0x74, 0xb6, 0x72, 0xcf, 0x23, 0x55, 0xc8, 0x9d, 0xf7, 0x90, 0x5b, + 0x29, 0x60, 0x1c, 0xb4, 0x61, 0xb3, 0xe9, 0x15, 0xff, 0x38, 0xfb, 0x7c, + 0xed, 0xda, 0xce, 0x53, 0xa2, 0xef, 0xf5, 0xa0, 0x12, 0xdf, 0xf9, 0x80, + 0x9b, 0x9d, 0xc4, 0xc9, 0xc4, 0xe5, 0xfe, 0xec, 0x30, 0x63, 0x99, 0x1c, 0xbf, 0xba, 0x9b, 0xd6, 0xb0, 0xe5, 0xff, 0x93, 0x3d, 0xbd, 0x66, 0xe3, - 0xe3, 0x97, 0xfe, 0x86, 0xd4, 0x9f, 0x78, 0xc8, 0x6b, 0x39, 0x73, 0xb6, + 0x93, 0x97, 0xfe, 0x86, 0xd4, 0x9f, 0x78, 0xc8, 0x6b, 0x39, 0x73, 0xb6, 0x72, 0x82, 0x8f, 0x95, 0x99, 0xf4, 0xb7, 0xc7, 0xdc, 0x51, 0x2e, 0xcd, 0x9c, 0xa8, 0x4e, 0x7f, 0x23, 0x3d, 0x51, 0x32, 0xff, 0xee, 0xba, 0x7a, 0x58, 0xa8, 0xe7, 0xe7, 0x2f, 0x77, 0x1b, 0x39, 0x7f, 0x98, 0x9b, 0xea, 0x42, 0x1c, 0xbf, 0x0c, 0xd1, 0xd8, 0x39, 0x7e, 0xfd, 0xf8, 0xe0, 0x4e, - 0x5f, 0xb3, 0xbf, 0x3b, 0x59, 0xcb, 0xef, 0xf7, 0x02, 0x72, 0xff, 0x6b, + 0x5f, 0xb3, 0xbc, 0xbb, 0x59, 0xcb, 0xef, 0xf7, 0x02, 0x72, 0xff, 0x6b, 0xae, 0x9b, 0x4e, 0x27, 0x2e, 0x55, 0x0e, 0x54, 0x1f, 0x6e, 0x11, 0x39, - 0xa5, 0xff, 0xdd, 0xc1, 0x17, 0xf7, 0x29, 0x43, 0x0e, 0x52, 0x27, 0xd6, + 0xa5, 0xff, 0xdd, 0xc1, 0x17, 0xf7, 0xc9, 0x43, 0x0e, 0x52, 0x27, 0xd6, 0xd6, 0x88, 0xc1, 0xd7, 0x31, 0xfc, 0x9c, 0x4a, 0xb7, 0x09, 0x8f, 0x16, 0x5f, 0xcd, 0xc6, 0xb4, 0xf3, 0x1c, 0xbf, 0xe0, 0xc2, 0xd4, 0xff, 0xf8, - 0xf8, 0xe5, 0xff, 0x3e, 0xb1, 0x88, 0xd2, 0x18, 0x72, 0x96, 0x7e, 0xc0, - 0x3d, 0xbe, 0xcd, 0x66, 0xce, 0x5f, 0x7a, 0x3e, 0x91, 0xcb, 0xf9, 0x3f, + 0xe4, 0xe5, 0xff, 0x3e, 0xb1, 0x88, 0xd2, 0x18, 0x72, 0x96, 0x7e, 0xc0, + 0x3d, 0xbe, 0xcd, 0x66, 0xce, 0x5f, 0x7a, 0x39, 0x91, 0xcb, 0xf9, 0x3f, 0x68, 0x29, 0xf9, 0xca, 0x9c, 0xf4, 0xf4, 0x47, 0x7c, 0x00, 0xf5, 0x0e, 0x5e, 0xf6, 0x28, 0x72, 0xa1, 0x39, 0xdc, 0x85, 0x2f, 0x48, 0x9d, 0xd3, 0x64, 0x7c, 0x04, 0x57, 0xf0, 0xc4, 0xa3, 0x8c, 0x1c, 0xba, 0x3f, 0x39, 0x7f, 0x71, 0xd3, 0xc2, 0x34, 0x39, 0x72, 0x4e, 0x72, 0xd8, 0x72, 0x91, 0x13, 0x73, 0x16, 0xb0, 0x5d, 0xcc, 0x04, 0x5e, 0xfa, 0x7f, 0x62, 0xce, 0x5f, 0xe7, 0x55, 0x4e, 0xf6, 0x24, 0x72, 0x9c, 0xf6, 0x1a, 0x11, 0xdf, - 0xfb, 0xb8, 0x10, 0xa7, 0xd9, 0xf7, 0x8e, 0x5f, 0xdc, 0x82, 0xa3, 0xeb, + 0xfb, 0xb8, 0x10, 0xa7, 0x39, 0xcf, 0x8e, 0x5f, 0xdf, 0x02, 0xa3, 0xeb, 0x47, 0x2a, 0x73, 0xf1, 0x0a, 0x05, 0xfe, 0x0e, 0x7b, 0xb0, 0x2b, 0x39, - 0x7c, 0xf0, 0x8d, 0x0e, 0x5f, 0xf0, 0x79, 0x66, 0xe3, 0x35, 0xf9, 0xcb, - 0xdd, 0x53, 0x67, 0x2b, 0x0f, 0x65, 0xce, 0xef, 0xf2, 0x07, 0xc2, 0xff, - 0x6c, 0xe5, 0xfe, 0xf6, 0xd3, 0xec, 0xfb, 0xc7, 0x2e, 0x9e, 0x0e, 0x54, + 0x7c, 0xf0, 0x8d, 0x0e, 0x5f, 0xf0, 0x7e, 0x66, 0xe3, 0x35, 0xf9, 0xcb, + 0xdd, 0x53, 0x67, 0x2b, 0x0f, 0x65, 0xce, 0xef, 0xf2, 0x07, 0xc2, 0xfc, + 0xec, 0xe5, 0xfe, 0xf6, 0xd3, 0x9c, 0xe7, 0xc7, 0x2e, 0x9e, 0x0e, 0x54, 0x1f, 0xfb, 0x99, 0x80, 0xd6, 0xa1, 0x39, 0xc9, 0xc8, 0xc2, 0x65, 0xd7, 0xb1, 0x84, 0xfd, 0x35, 0x2d, 0xd6, 0x6b, 0x56, 0x35, 0xc3, 0x24, 0xb5, 0x02, 0x58, 0x8c, 0xc2, 0x74, 0xc9, 0x12, 0x06, 0x1a, 0x79, 0x1b, 0xc2, - 0xae, 0x2b, 0x8c, 0x27, 0xe8, 0x64, 0x24, 0x2f, 0xe6, 0x86, 0x56, 0xa3, + 0xae, 0x2b, 0x8c, 0x27, 0x98, 0x64, 0x24, 0x2f, 0xe6, 0x86, 0x56, 0xa3, 0x61, 0x64, 0x35, 0xbb, 0x28, 0xf9, 0xe5, 0x4f, 0x7f, 0x1b, 0x00, 0xc7, 0x9f, 0xb9, 0x44, 0x3e, 0x94, 0x2a, 0x08, 0x7c, 0x34, 0x85, 0x02, 0x92, 0x8c, 0x2f, 0xdc, 0x0e, 0xb8, 0xd1, 0xcb, 0xff, 0x24, 0x7b, 0xae, 0xae, - 0x0f, 0xe7, 0x2f, 0xff, 0x3e, 0xb9, 0x3f, 0xb9, 0x7b, 0xe5, 0xa0, 0x9c, + 0x0f, 0xe7, 0x2f, 0xff, 0x3e, 0xbe, 0x3f, 0xbe, 0x7b, 0x95, 0xa0, 0x9c, 0xae, 0xa2, 0x33, 0x89, 0xf5, 0xfd, 0x9e, 0x84, 0x66, 0xce, 0x5f, 0xe0, - 0xc4, 0xb3, 0x59, 0xb3, 0x97, 0xff, 0xd9, 0xad, 0x02, 0x5a, 0xc8, 0xfa, - 0x48, 0xc3, 0x97, 0xb6, 0xa6, 0xce, 0x5f, 0xff, 0x67, 0xd2, 0xf0, 0x27, - 0xe7, 0xd7, 0x62, 0x6c, 0xe5, 0xff, 0xbd, 0x0c, 0xdc, 0x24, 0xef, 0xe3, - 0x97, 0xf3, 0xb5, 0xbe, 0x7d, 0xe3, 0x95, 0xf1, 0xf7, 0x74, 0xfa, 0xff, - 0x3e, 0x05, 0x3e, 0x17, 0x39, 0x58, 0x7a, 0x80, 0x23, 0xb9, 0xb1, 0x39, - 0x7b, 0xc3, 0x07, 0x2e, 0xef, 0x38, 0x56, 0x21, 0x90, 0xb6, 0x98, 0x95, + 0xc4, 0xb3, 0x59, 0xb3, 0x97, 0xff, 0xd9, 0xad, 0x02, 0x5a, 0xc8, 0xe6, + 0x48, 0xc3, 0x97, 0xb6, 0xa6, 0xce, 0x5f, 0xff, 0x67, 0x32, 0xf0, 0x27, + 0xfb, 0xd7, 0x62, 0x6c, 0xe5, 0xff, 0xbd, 0x0c, 0xdc, 0x24, 0xef, 0xe3, + 0x97, 0xf3, 0xb5, 0xbe, 0x73, 0xe3, 0x95, 0xc9, 0xf7, 0x74, 0xfa, 0xff, + 0x3e, 0x05, 0x39, 0x17, 0x39, 0x58, 0x7a, 0x80, 0x23, 0xb9, 0xb1, 0x39, + 0x7b, 0xc3, 0x07, 0x2e, 0xef, 0xd8, 0x56, 0x21, 0x90, 0xb6, 0x98, 0x95, 0x85, 0x9d, 0x32, 0x75, 0x01, 0x1e, 0xdc, 0x62, 0xcd, 0x90, 0xa8, 0x2f, - 0x5c, 0xd7, 0x62, 0xa2, 0x73, 0x96, 0xfe, 0xcd, 0x2d, 0xdd, 0x66, 0x8b, - 0x35, 0x7f, 0xf6, 0xba, 0xfc, 0xd8, 0x09, 0xba, 0x81, 0x39, 0x7f, 0xe8, - 0xd7, 0xfe, 0xdf, 0x71, 0x02, 0x72, 0xfd, 0x93, 0x4a, 0x3e, 0x39, 0x7c, + 0x5f, 0x57, 0x62, 0xa2, 0x73, 0x96, 0xfe, 0xcd, 0x2d, 0xdd, 0x66, 0x8b, + 0x35, 0x7f, 0xf6, 0xba, 0xff, 0x58, 0x09, 0xba, 0x81, 0x39, 0x7f, 0xe8, + 0xd7, 0xfe, 0xdf, 0x71, 0x02, 0x72, 0xfd, 0x93, 0x4a, 0x39, 0x39, 0x7c, 0x82, 0xf3, 0x9c, 0xae, 0xa2, 0x24, 0x4f, 0xf6, 0x53, 0x6e, 0x9c, 0xba, - 0x3a, 0x72, 0xfe, 0x1c, 0xe3, 0xd7, 0x91, 0xcb, 0x73, 0x9c, 0xf5, 0x7a, - 0x23, 0xe1, 0x6a, 0xe6, 0x8b, 0xce, 0x08, 0x42, 0x57, 0x34, 0xfc, 0xd0, + 0x3a, 0x72, 0xfe, 0x1c, 0xe3, 0xd7, 0x91, 0xcb, 0x7d, 0x9c, 0xf5, 0x7a, + 0x23, 0xe1, 0x6a, 0xfa, 0x8b, 0xce, 0x08, 0x42, 0x57, 0xd4, 0xfc, 0xd0, 0xe5, 0xe3, 0x8d, 0xbe, 0x46, 0x29, 0xa3, 0x97, 0xd0, 0xbc, 0xe9, 0xcb, 0xe4, 0x1d, 0x00, 0xe5, 0xfe, 0x8e, 0x2a, 0x78, 0x63, 0xf3, 0x97, 0xca, - 0x0e, 0x6c, 0xe5, 0xcc, 0xe7, 0x08, 0xbd, 0x42, 0x39, 0x88, 0x7a, 0x42, - 0xe6, 0xd7, 0x62, 0x1c, 0xbb, 0x02, 0x72, 0xff, 0xcf, 0x2e, 0x79, 0xa5, + 0x0e, 0x6c, 0xe5, 0xcc, 0xfb, 0x08, 0xbd, 0x42, 0x39, 0x88, 0x7a, 0x42, + 0xe6, 0xd7, 0x62, 0x1c, 0xbb, 0x02, 0x72, 0xff, 0xcf, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x40, 0x2f, 0xf2, 0x32, 0x1a, 0xfb, 0x93, 0x9c, 0xb7, - 0x39, 0x22, 0xb7, 0x05, 0x58, 0x2d, 0xd4, 0xcb, 0xa4, 0xc3, 0x97, 0xcf, - 0xaf, 0xa4, 0x72, 0xfd, 0x1f, 0x79, 0xf4, 0x72, 0xfd, 0xed, 0xc9, 0x3f, - 0x39, 0x52, 0x44, 0x5e, 0x0b, 0xa1, 0x1b, 0x94, 0x5f, 0xb9, 0xe4, 0xd1, + 0xd9, 0x22, 0xb7, 0x05, 0x58, 0x2d, 0xd4, 0xcb, 0xa4, 0xc3, 0x97, 0xcf, + 0xae, 0x64, 0x72, 0xfd, 0x1c, 0xf9, 0xf4, 0x72, 0xfd, 0xed, 0xc9, 0x3f, + 0x39, 0x52, 0x44, 0x5e, 0x0b, 0xa1, 0x1b, 0x94, 0x5f, 0xbe, 0xe4, 0xd1, 0x23, 0x97, 0xfd, 0x1e, 0xee, 0x33, 0x35, 0x87, 0x2f, 0xa6, 0xcc, 0x59, - 0xcb, 0xf7, 0x95, 0x7d, 0xf3, 0xd1, 0xec, 0xa8, 0x6f, 0x52, 0x46, 0x33, - 0x70, 0x83, 0xae, 0x69, 0x94, 0xc4, 0x60, 0x17, 0x03, 0xa7, 0x2f, 0xff, + 0xcb, 0xf7, 0x95, 0x7d, 0xfd, 0xd1, 0xec, 0xa8, 0x6f, 0x52, 0x46, 0x33, + 0x70, 0x83, 0xaf, 0xa9, 0x94, 0xc4, 0x60, 0x17, 0x03, 0xa7, 0x2f, 0xff, 0xdc, 0x63, 0xa8, 0x1e, 0xc4, 0xb6, 0xfd, 0x4d, 0x9c, 0xbf, 0xb7, 0x0c, 0x18, 0x98, 0xe5, 0xba, 0x72, 0xf2, 0x83, 0x31, 0xcb, 0x7b, 0x0d, 0x7f, 0xe2, 0x37, 0x64, 0xe7, 0x2b, 0x0d, 0xf0, 0x93, 0xd2, 0x26, 0x1f, 0xfa, - 0xb0, 0xc2, 0x6a, 0xee, 0x5b, 0x39, 0x78, 0x01, 0xc3, 0x97, 0xfb, 0x35, + 0xb0, 0xc2, 0x6a, 0xef, 0x9b, 0x39, 0x78, 0x01, 0xc3, 0x97, 0xfb, 0x35, 0xe1, 0x86, 0x6c, 0xe5, 0x9a, 0x1c, 0xa4, 0x3e, 0x1e, 0x8e, 0x7e, 0x65, 0x7c, 0xb7, 0x75, 0x9a, 0x2d, 0xf5, 0xe6, 0x8f, 0xe3, 0x97, 0xf2, 0x9e, 0x75, 0xbe, 0x8e, 0x56, 0x8f, 0xe9, 0x85, 0xdf, 0x8f, 0x5c, 0xab, 0x67, 0x2f, 0xb0, 0x52, 0x63, 0x97, 0xbb, 0x1a, 0x39, 0x7e, 0xea, 0x6b, 0xae, 0x72, 0xff, 0xf7, 0x62, 0x7f, 0x67, 0x47, 0x3d, 0xd4, 0x39, 0x79, 0x98, - 0x13, 0x96, 0x61, 0xcb, 0xfe, 0xec, 0x4e, 0x1c, 0x6f, 0x7c, 0xe1, 0x17, + 0x13, 0x96, 0x61, 0xcb, 0xfe, 0xec, 0x4e, 0x1c, 0x6f, 0x7f, 0x61, 0x17, 0x38, 0x39, 0x31, 0x3b, 0xa4, 0xa8, 0x39, 0x7e, 0xf4, 0xb6, 0xa6, 0xce, 0x5e, 0xdf, 0x42, 0x72, 0xfc, 0xa7, 0x86, 0x3f, 0x39, 0x4c, 0x3c, 0x6e, 0x23, 0xb7, 0xff, 0x7b, 0x69, 0xb8, 0x1c, 0xf7, 0x50, 0xe5, 0xe1, 0xce, 0x9c, 0xa6, 0x1e, 0xef, 0x14, 0x2b, 0xf0, 0x61, 0xac, 0x0c, 0x39, 0x7f, - 0xcf, 0xb8, 0xc1, 0x0f, 0x60, 0xe5, 0xff, 0xd8, 0xcd, 0x67, 0xdd, 0x17, + 0xcf, 0xb8, 0xc1, 0x0f, 0x60, 0xe5, 0xff, 0xd8, 0xcd, 0x67, 0x3d, 0x17, 0x6b, 0x9c, 0xe5, 0xdb, 0xde, 0x8f, 0xf8, 0x4d, 0xaa, 0x13, 0x7b, 0xc8, 0x40, 0xa1, 0x23, 0xc2, 0xa6, 0xf9, 0xd0, 0x7c, 0x72, 0xfd, 0xfe, 0xfd, 0x0c, 0x39, 0x7b, 0x51, 0xe3, 0x97, 0xf4, 0xce, 0x1e, 0xa3, 0x0e, 0x5f, 0xde, 0x4c, 0x0c, 0x30, 0xe5, 0x78, 0xf6, 0x9b, 0x2e, 0xbb, 0x62, 0x72, - 0xfe, 0xfb, 0x70, 0xbc, 0x61, 0xca, 0x84, 0xc1, 0xb4, 0x52, 0xee, 0xdb, + 0xfe, 0xe7, 0x70, 0xbc, 0x61, 0xca, 0x84, 0xc1, 0xb4, 0x52, 0xee, 0xdb, 0x23, 0x00, 0xb5, 0xfc, 0x93, 0x40, 0x8c, 0x1c, 0xbe, 0xea, 0xa1, 0x61, - 0xcb, 0x48, 0xe5, 0xfe, 0xff, 0xf0, 0x6d, 0xaf, 0x3e, 0x39, 0x58, 0x79, + 0xcb, 0x48, 0xe5, 0xfe, 0xff, 0xf0, 0x6d, 0xaf, 0x39, 0x39, 0x58, 0x79, 0x6e, 0x23, 0x58, 0x88, 0xf1, 0x6f, 0xbf, 0xde, 0x4d, 0xba, 0xde, 0x73, 0x94, 0xd5, 0xb2, 0x32, 0x22, 0x32, 0x69, 0x1a, 0x85, 0xeb, 0x21, 0x53, - 0xf1, 0x82, 0x0c, 0xcd, 0x0d, 0xad, 0x3d, 0xf6, 0x3e, 0xbf, 0xd1, 0x06, - 0x32, 0x6d, 0xa4, 0xfa, 0x17, 0x4a, 0x10, 0xdf, 0xcf, 0xf7, 0x36, 0x3f, - 0x8e, 0x57, 0x34, 0xc9, 0x86, 0x1e, 0xd7, 0xf0, 0x79, 0xef, 0xdb, 0xf8, - 0xe5, 0xcd, 0x53, 0x56, 0x72, 0xf3, 0x1f, 0xe3, 0x97, 0xbf, 0x7e, 0x9c, + 0xc9, 0x82, 0x0c, 0xcd, 0x0d, 0xad, 0x3d, 0xf6, 0x3e, 0xbf, 0xd1, 0x06, + 0x32, 0x6d, 0xa4, 0xfa, 0x17, 0x4a, 0x10, 0xdf, 0xcf, 0xcf, 0xd6, 0x3f, + 0x8e, 0x57, 0xd4, 0xc9, 0x86, 0x1e, 0xd7, 0xf0, 0x7e, 0xef, 0xdb, 0xe4, + 0xe5, 0xcd, 0x53, 0x56, 0x72, 0xf3, 0x1f, 0x93, 0x97, 0xbf, 0x7e, 0x9c, 0xbb, 0x8a, 0x1c, 0xbe, 0xd6, 0xb1, 0x43, 0x97, 0xfd, 0x12, 0x6d, 0xf5, - 0xac, 0x50, 0xe5, 0xfb, 0x73, 0xe3, 0x7c, 0xda, 0x94, 0x68, 0x41, 0x0e, + 0xac, 0x50, 0xe5, 0xfb, 0x73, 0xe3, 0x7f, 0x5a, 0x94, 0x68, 0x41, 0x0e, 0x0e, 0xcc, 0x3a, 0xe3, 0x02, 0x47, 0x50, 0x9b, 0xe2, 0x46, 0x05, 0x7f, - 0xff, 0xdc, 0x3a, 0x78, 0x0f, 0x3f, 0x3c, 0x97, 0x63, 0x59, 0x82, 0xa9, + 0xff, 0xdc, 0x3a, 0x78, 0x0f, 0x3f, 0xdc, 0x97, 0x63, 0x59, 0x82, 0xa9, 0xcb, 0xff, 0xff, 0xc8, 0xb7, 0xd3, 0xf6, 0x59, 0xec, 0x0e, 0xdd, 0x99, - 0xa9, 0xe3, 0xe3, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x8a, 0x51, 0x7f, 0xfc, - 0xfe, 0x1c, 0x9f, 0x51, 0xd4, 0xee, 0x68, 0xe5, 0xe7, 0x97, 0x38, 0x47, - 0xce, 0x3b, 0xfe, 0x69, 0x7f, 0xd2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x12, - 0x72, 0x98, 0x88, 0x97, 0x42, 0xbf, 0xda, 0xe7, 0x9d, 0x89, 0x9c, 0xe5, - 0x73, 0x3d, 0x77, 0x22, 0xa8, 0x86, 0x8c, 0x34, 0xf3, 0xc5, 0x52, 0x94, + 0xa9, 0xe3, 0x93, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x8a, 0x51, 0x7f, 0xfc, + 0xfe, 0x1c, 0x9f, 0x51, 0xd4, 0xee, 0x68, 0xe5, 0xe7, 0x97, 0xd8, 0x47, + 0xce, 0x3b, 0xfe, 0x69, 0x7f, 0xd2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, + 0x72, 0x98, 0x88, 0x97, 0x42, 0xbf, 0xda, 0xfb, 0x9d, 0x89, 0x9c, 0xe5, + 0x7d, 0x3d, 0x77, 0x22, 0xa8, 0x86, 0x8c, 0x34, 0xf3, 0xc5, 0x52, 0x94, 0x44, 0x1c, 0x47, 0x4a, 0xe4, 0x65, 0x4a, 0xa2, 0x2e, 0x3a, 0xa4, 0x8c, 0x41, 0xae, 0x18, 0x13, 0x14, 0x6a, 0x17, 0x8c, 0xb4, 0x0f, 0x1d, 0x94, 0x44, 0xf0, 0xf4, 0xfe, 0x30, 0x31, 0x8f, 0xe3, 0x74, 0xa1, 0x9f, 0x47, 0x4c, 0x02, 0x8e, 0x32, 0x91, 0xaf, 0xda, 0x5b, 0xba, 0xcd, 0x10, 0xfa, - 0xff, 0xcf, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x29, 0xad, 0xcf, 0x11, - 0x00, 0xc3, 0x4b, 0xfd, 0xcf, 0x34, 0xb7, 0x75, 0x9a, 0x22, 0x75, 0xf9, + 0xff, 0xcf, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x29, 0xad, 0xf7, 0x11, + 0x00, 0xc3, 0x4b, 0xfd, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x22, 0x75, 0xf9, 0x3d, 0xb0, 0x30, 0xe5, 0xee, 0xc4, 0xc7, 0x2a, 0x63, 0xc5, 0xe9, 0x45, - 0xff, 0xee, 0x14, 0xab, 0x6d, 0x73, 0x87, 0x86, 0xe5, 0xcb, 0xad, 0x0e, - 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x23, 0x15, 0xff, 0xfc, 0x01, 0x75, 0x79, + 0xff, 0xee, 0x14, 0xab, 0x6d, 0x73, 0x87, 0x86, 0xf9, 0xf3, 0xad, 0x0e, + 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x23, 0x15, 0xff, 0xfc, 0x01, 0x75, 0x7e, 0x79, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2f, 0xa1, 0x8b, 0xfc, 0xe5, 0xff, - 0xf4, 0xa7, 0xe1, 0x50, 0xd5, 0xce, 0xbd, 0x72, 0xe5, 0xd6, 0x87, 0x2b, - 0xa8, 0x88, 0xfc, 0x8e, 0xfe, 0xcf, 0x46, 0x7d, 0xe3, 0x97, 0xfe, 0xf2, + 0xf4, 0xa7, 0xe1, 0x50, 0xd5, 0xce, 0xbd, 0x7c, 0xf9, 0xd6, 0x87, 0x2b, + 0xa8, 0x88, 0xfc, 0x8e, 0xfe, 0xcf, 0x46, 0x73, 0xe3, 0x97, 0xfe, 0xf2, 0xb0, 0x32, 0xce, 0xa3, 0x0e, 0x5f, 0xf2, 0xb0, 0x32, 0xce, 0xa3, 0x0e, - 0x5f, 0x00, 0x5d, 0x5e, 0x47, 0xed, 0xe3, 0xeb, 0xf6, 0xbf, 0x4e, 0xc1, - 0xca, 0x61, 0xf1, 0x80, 0xee, 0xf9, 0x3e, 0x93, 0x56, 0x72, 0xfd, 0xca, - 0x61, 0x80, 0x9c, 0xb7, 0x38, 0x56, 0x7d, 0x22, 0x3c, 0x64, 0x61, 0xa7, - 0x61, 0xca, 0x24, 0x9b, 0x8c, 0x1b, 0xc4, 0x4d, 0x0a, 0x2f, 0xff, 0x73, - 0x63, 0xcb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x4f, 0x2b, 0xe8, 0xe3, 0x1d, + 0x5f, 0x00, 0x5d, 0x5f, 0x87, 0xed, 0xe3, 0xeb, 0xf6, 0xbf, 0x4e, 0xc1, + 0xca, 0x61, 0xf1, 0x80, 0xee, 0xf9, 0x39, 0x93, 0x56, 0x72, 0xfd, 0xf2, + 0x61, 0x80, 0x9c, 0xb7, 0xd8, 0x56, 0x7d, 0x22, 0x3c, 0x64, 0x61, 0xa7, + 0x61, 0xca, 0x24, 0x9b, 0x8c, 0x1b, 0xc4, 0x4d, 0x0a, 0x2f, 0xff, 0x7d, + 0x63, 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x4f, 0x2b, 0xe8, 0xe3, 0x1d, 0x39, 0x7d, 0x03, 0x2d, 0x9c, 0xbf, 0x75, 0x07, 0x38, 0x9c, 0xad, 0x1f, 0x67, 0xe4, 0x6a, 0x10, 0xdf, 0x01, 0xf5, 0x23, 0x97, 0xe7, 0x0f, 0x63, - 0x67, 0x2d, 0xcc, 0x27, 0x92, 0x24, 0x55, 0xcd, 0x14, 0x6d, 0xbd, 0x54, + 0x67, 0x2d, 0xf4, 0x27, 0x92, 0x24, 0x55, 0xf5, 0x14, 0x6d, 0xbd, 0x54, 0x2f, 0x07, 0xce, 0x55, 0x29, 0x78, 0x9d, 0x84, 0x97, 0xa3, 0x69, 0xbf, - 0x69, 0x6e, 0xeb, 0x34, 0x44, 0x0b, 0xff, 0x3c, 0xb9, 0xe6, 0x96, 0xee, + 0x69, 0x6e, 0xeb, 0x34, 0x44, 0x0b, 0xff, 0x3c, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xa8, 0xbf, 0xb4, 0x0e, 0xc0, 0xac, 0xe5, 0xfc, 0xb4, 0xce, - 0x0e, 0xc1, 0xca, 0x83, 0xdc, 0xc2, 0xdb, 0x73, 0xc4, 0x7e, 0x30, 0xd0, + 0x0e, 0xc1, 0xca, 0x83, 0xdc, 0xc2, 0xdb, 0x7d, 0xc4, 0x7e, 0x30, 0xd0, 0x61, 0x51, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0x8a, 0x17, 0xa3, 0xfc, 0x39, - 0x6e, 0x78, 0x7a, 0x0a, 0x1a, 0x5f, 0xee, 0x79, 0xa5, 0xbb, 0xac, 0xd1, + 0x6f, 0xb8, 0x7a, 0x0a, 0x1a, 0x5f, 0xef, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x19, 0x2f, 0xda, 0x5b, 0xba, 0xcd, 0x13, 0x2a, 0xfd, 0x2c, 0xf3, 0xac, - 0xe5, 0xfb, 0x9b, 0x1e, 0x5c, 0xf0, 0xf6, 0xfe, 0x34, 0xbf, 0x69, 0x6e, - 0xeb, 0x34, 0x54, 0x8b, 0x09, 0xcb, 0x28, 0x72, 0xdc, 0xf0, 0xf5, 0x9a, - 0xcd, 0x00, 0x21, 0x7f, 0xb9, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x74, 0xbf, - 0xdc, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0xc5, 0x5f, 0xfc, 0xc7, 0x97, 0x3c, + 0xe5, 0xfb, 0xeb, 0x1e, 0x5f, 0x70, 0xf6, 0xf9, 0x34, 0xbf, 0x69, 0x6e, + 0xeb, 0x34, 0x54, 0x8b, 0x09, 0xcb, 0x28, 0x72, 0xdf, 0x70, 0xf5, 0x9a, + 0xcd, 0x00, 0x21, 0x7f, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x74, 0xbf, + 0xdf, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0xc5, 0x5f, 0xfc, 0xc7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x9e, 0x97, 0x9b, 0x75, 0x9c, 0xbf, 0xbb, 0x09, - 0xa4, 0xe1, 0xce, 0x5f, 0xa1, 0x1a, 0x27, 0x01, 0xcb, 0x9b, 0xe7, 0x87, - 0xf2, 0xb1, 0xd7, 0x31, 0xbf, 0xff, 0xfc, 0x1c, 0x6f, 0x98, 0xe2, 0xaa, - 0xbf, 0xb6, 0x83, 0x34, 0x2f, 0x59, 0xf1, 0xcb, 0xff, 0xfb, 0x33, 0xa8, - 0xbe, 0xe7, 0x31, 0xcf, 0x75, 0x1b, 0x39, 0x7f, 0xfe, 0x98, 0x61, 0x9c, - 0xf3, 0x68, 0xd8, 0x5d, 0xd5, 0x39, 0x76, 0xfc, 0x72, 0xec, 0xd9, 0xcb, - 0xb7, 0xf9, 0xcb, 0xf0, 0xbb, 0x06, 0x0e, 0x5f, 0xc0, 0xdf, 0x5e, 0x5c, - 0xda, 0xb3, 0xea, 0x71, 0x76, 0xc5, 0x94, 0x18, 0xbd, 0x3c, 0x35, 0x9c, - 0xbb, 0x5e, 0x39, 0x7e, 0xcf, 0x6d, 0x18, 0x72, 0xff, 0xf4, 0x7d, 0xec, - 0x99, 0x35, 0xed, 0x81, 0xac, 0xe5, 0xe7, 0xfb, 0x9c, 0x22, 0xb5, 0xc8, + 0xa4, 0xe1, 0xce, 0x5f, 0xa1, 0x1a, 0x27, 0x01, 0xcb, 0x9b, 0xfb, 0x87, + 0xf2, 0xb1, 0xd7, 0x31, 0xbf, 0xff, 0xfc, 0x1c, 0x6f, 0xe8, 0xe2, 0xaa, + 0xbf, 0xb6, 0x83, 0x34, 0x2f, 0x59, 0xc9, 0xcb, 0xff, 0xfb, 0x33, 0xa8, + 0xbe, 0xe7, 0xd1, 0xcf, 0x75, 0x1b, 0x39, 0x7f, 0xfe, 0x98, 0x61, 0x9f, + 0x73, 0x68, 0xd8, 0x5d, 0xd5, 0x39, 0x76, 0xfc, 0x72, 0xec, 0xd9, 0xcb, + 0xb7, 0xf9, 0xcb, 0xf0, 0xbb, 0x06, 0x0e, 0x5f, 0xc0, 0xdf, 0x5e, 0x5f, + 0x5a, 0xb3, 0xea, 0x71, 0x76, 0xc5, 0x94, 0x18, 0xbd, 0x3c, 0x35, 0x9c, + 0xbb, 0x5e, 0x39, 0x7e, 0xcf, 0x6d, 0x18, 0x72, 0xff, 0xf4, 0x73, 0xec, + 0x99, 0x35, 0xed, 0x81, 0xac, 0xe5, 0xe7, 0xe7, 0xec, 0x22, 0xb5, 0xc8, 0x04, 0x5f, 0xc4, 0xf5, 0x8a, 0x89, 0x35, 0x0c, 0x2d, 0xc6, 0x29, 0x41, - 0x56, 0x6e, 0x2f, 0x9e, 0x94, 0xff, 0x5c, 0xd7, 0x1d, 0xa2, 0x19, 0x69, + 0x56, 0x6e, 0x2f, 0x9e, 0x94, 0xff, 0x5f, 0x57, 0x1d, 0xa2, 0x19, 0x69, 0x2d, 0xce, 0xfc, 0xd4, 0xa4, 0x03, 0x87, 0x39, 0x7e, 0x4e, 0x8b, 0xcc, - 0x72, 0xfd, 0x2c, 0x0f, 0x2c, 0x39, 0x5c, 0x21, 0xe8, 0x41, 0x3d, 0xcc, + 0x72, 0xfd, 0x2c, 0x0f, 0xcc, 0x39, 0x5c, 0x21, 0xe8, 0x41, 0x3d, 0xcc, 0xfc, 0xe5, 0xfb, 0x3c, 0x80, 0xd9, 0xcb, 0x9a, 0x96, 0xa0, 0x72, 0x9a, 0x93, 0xe1, 0x6a, 0x03, 0x1c, 0x28, 0x9e, 0xfd, 0xc2, 0xcd, 0x4e, 0xf5, 0xe3, 0x97, 0xf9, 0x41, 0xcd, 0x6a, 0x16, 0x72, 0x9a, 0x93, 0xe8, 0xe1, - 0x8d, 0x6f, 0xb4, 0xcf, 0x7c, 0x72, 0xfe, 0x6a, 0x5a, 0xae, 0x12, 0x24, + 0x8d, 0x6f, 0xb4, 0xcf, 0x72, 0x72, 0xfe, 0x6a, 0x5a, 0xae, 0x12, 0x24, 0xc3, 0x97, 0x97, 0x9d, 0x29, 0x79, 0x91, 0xb3, 0x97, 0xbf, 0xd4, 0x1c, - 0xbf, 0xb3, 0xf4, 0x99, 0x1b, 0x39, 0x7f, 0xe7, 0xdf, 0x2d, 0xef, 0x25, + 0xbf, 0xb3, 0xf4, 0x99, 0x1b, 0x39, 0x7f, 0xe7, 0xdf, 0xcd, 0xef, 0x25, 0x28, 0x39, 0x6d, 0x9c, 0xbf, 0xff, 0x0b, 0xaa, 0x9a, 0x89, 0x4b, 0x37, 0xff, 0xf0, 0x72, 0xff, 0x3f, 0x81, 0x98, 0x2a, 0x9c, 0xa0, 0xa6, 0x10, 0xa9, 0x7c, 0xc8, 0x1d, 0x11, 0xfd, 0x5a, 0xff, 0xfe, 0xd2, 0x70, 0x3b, - 0x39, 0xc6, 0xb4, 0x9c, 0x0b, 0x04, 0xe7, 0x2f, 0x93, 0xaa, 0x30, 0xe5, - 0xff, 0xe4, 0x57, 0x96, 0x0b, 0xfd, 0xb5, 0x55, 0x73, 0x94, 0xb3, 0xf1, - 0x12, 0x3b, 0xff, 0xcf, 0xb1, 0xcf, 0xf9, 0xf5, 0x16, 0xfa, 0x39, 0x70, + 0x3e, 0xc6, 0xb4, 0x9c, 0x0b, 0x04, 0xe7, 0x2f, 0x93, 0xaa, 0x30, 0xe5, + 0xff, 0xe4, 0x57, 0xe6, 0x0b, 0xf3, 0xb5, 0x55, 0x73, 0x94, 0xb3, 0xf1, + 0x12, 0x3b, 0xff, 0xcf, 0xb1, 0xcf, 0xfe, 0xf5, 0x16, 0xfa, 0x39, 0x70, 0xb6, 0x72, 0xfe, 0x0e, 0x2b, 0xec, 0x59, 0xcb, 0xee, 0xc3, 0x16, 0x72, 0xa0, 0xf9, 0xdc, 0x5f, 0xc5, 0xd7, 0x83, 0x9d, 0x39, 0x7a, 0x64, 0x6c, - 0xe5, 0x83, 0x23, 0x74, 0x83, 0x97, 0xff, 0x72, 0x88, 0x18, 0x67, 0x2e, - 0x5d, 0x68, 0x72, 0xa0, 0xfc, 0x44, 0x9a, 0xff, 0xdd, 0xc9, 0xba, 0x9d, - 0x8d, 0x41, 0xcb, 0x9f, 0xe3, 0x97, 0xf9, 0xf6, 0xfd, 0x00, 0xce, 0x72, + 0xe5, 0x83, 0x23, 0x74, 0x83, 0x97, 0xff, 0x7c, 0x88, 0x18, 0x67, 0xcf, + 0x9d, 0x68, 0x72, 0xa0, 0xfc, 0x44, 0x9a, 0xff, 0xdd, 0xc9, 0xba, 0x9d, + 0x8d, 0x41, 0xcb, 0x9f, 0x93, 0x97, 0xf9, 0xf6, 0xfd, 0x00, 0xce, 0x72, 0x84, 0xf2, 0x80, 0x2f, 0x53, 0xae, 0x6c, 0x48, 0x71, 0x23, 0x25, 0xd2, 0x73, 0x21, 0xab, 0xd2, 0x11, 0x85, 0x97, 0xa1, 0xb0, 0xa1, 0x07, 0x04, 0x22, 0x2f, 0x0b, 0xf8, 0xe5, 0xe1, 0x4d, 0x9c, 0xb3, 0x7c, 0x21, 0xb6, 0x81, 0xbb, 0xa3, 0xa7, 0x2f, 0xb5, 0xc5, 0xd8, 0x72, 0xfc, 0x39, 0xe8, - 0x6c, 0xe5, 0xff, 0xe4, 0xe5, 0xdc, 0x99, 0x3e, 0xdf, 0x71, 0x67, 0x2f, + 0x6c, 0xe5, 0xff, 0xe4, 0xf9, 0xdc, 0x99, 0x39, 0xdf, 0x71, 0x67, 0x2f, 0xcc, 0x17, 0xf6, 0xce, 0x5e, 0x8c, 0xd1, 0xcb, 0xff, 0xcb, 0x7d, 0x3f, - 0x93, 0x70, 0x31, 0xf9, 0xcb, 0x4b, 0xa7, 0xc6, 0xa0, 0xdd, 0x7c, 0x8b, + 0x93, 0x70, 0x31, 0xf9, 0xcb, 0x4b, 0xa7, 0xc6, 0xa0, 0xdd, 0x72, 0x8b, 0x3d, 0x42, 0x2a, 0xb1, 0x3b, 0x65, 0x96, 0x20, 0xb6, 0xc9, 0x3c, 0x4e, 0x08, 0xc0, 0x2f, 0x9d, 0x14, 0x61, 0xcb, 0xdb, 0xe0, 0xe0, 0x39, 0x7d, - 0xca, 0x5f, 0xb0, 0xe5, 0xed, 0x60, 0x4e, 0x5f, 0xe7, 0xf4, 0x4d, 0xb4, - 0x61, 0xca, 0x54, 0xf3, 0xfa, 0x39, 0x7f, 0xa2, 0x43, 0x9f, 0x7b, 0x0e, + 0xf2, 0x5f, 0xb0, 0xe5, 0xed, 0x60, 0x4e, 0x5f, 0xe7, 0xf4, 0x4d, 0xb4, + 0x61, 0xca, 0x54, 0xf3, 0xfa, 0x39, 0x7f, 0xa2, 0x43, 0x9c, 0xfb, 0x0e, 0x5f, 0xff, 0x27, 0x5d, 0x70, 0x21, 0x9a, 0x51, 0xa9, 0xce, 0x5f, 0xff, 0x7b, 0x61, 0xd6, 0x22, 0xbd, 0x6d, 0xc6, 0x73, 0x97, 0xc2, 0x1c, 0x54, - 0xe5, 0xee, 0x81, 0x87, 0x2a, 0x49, 0xf8, 0x61, 0x17, 0xc4, 0x68, 0xeb, + 0xe5, 0xee, 0x81, 0x87, 0x2a, 0x49, 0xf8, 0x61, 0x17, 0x24, 0x68, 0xeb, 0xa2, 0x3e, 0x99, 0x6d, 0x43, 0xca, 0x40, 0x22, 0xbf, 0xbd, 0xb9, 0xa0, 0x67, 0x39, 0x7e, 0x15, 0x53, 0x36, 0x72, 0xfc, 0xdb, 0xf9, 0xd6, 0x72, - 0xff, 0xec, 0x6d, 0xff, 0xc5, 0xf5, 0xff, 0xd9, 0xcb, 0xff, 0x6d, 0xfe, + 0xff, 0xec, 0x6d, 0xff, 0xc5, 0xf5, 0xff, 0xd9, 0xcb, 0xff, 0x6d, 0xf9, 0x81, 0x70, 0xe2, 0xa7, 0x29, 0x11, 0xa7, 0xd2, 0x71, 0x28, 0xf2, 0x35, - 0xd1, 0xd3, 0x96, 0x09, 0xca, 0x61, 0xa7, 0x11, 0x6b, 0xe1, 0x0f, 0x25, + 0xd1, 0xd3, 0x96, 0x09, 0xca, 0x61, 0xa7, 0x11, 0x6b, 0xe1, 0x0f, 0xc5, 0x4e, 0x5f, 0xd9, 0xb6, 0xdc, 0x67, 0x39, 0x58, 0x7e, 0x6e, 0x40, 0x24, 0xb7, 0xed, 0x03, 0x6e, 0xb3, 0x97, 0xca, 0xec, 0x30, 0x72, 0xa0, 0xf2, 0xc0, 0x51, 0x6d, 0x9c, 0xb6, 0x1c, 0xb3, 0x10, 0xd0, 0xf0, 0x08, 0xdf, 0xf6, 0x0b, 0xcb, 0x72, 0x6e, 0x73, 0x97, 0xd2, 0xda, 0x09, 0xcb, 0x44, - 0x8f, 0x6f, 0xe3, 0xab, 0xfc, 0xfa, 0x94, 0x2d, 0x16, 0x72, 0xa1, 0x5b, + 0x8f, 0x6f, 0x93, 0xab, 0xfc, 0xfa, 0x94, 0x2d, 0x16, 0x72, 0xa1, 0x5b, 0x76, 0x46, 0x04, 0x90, 0xd5, 0xeb, 0xbb, 0xa1, 0x0c, 0x21, 0x00, 0x51, - 0x7f, 0xf9, 0x57, 0xcf, 0xbd, 0xe8, 0xce, 0x28, 0xb3, 0x97, 0xf8, 0x73, + 0x7f, 0xf9, 0x57, 0xce, 0x7d, 0xe8, 0xce, 0x28, 0xb3, 0x97, 0xf8, 0x73, 0x7e, 0x77, 0x13, 0x94, 0xa9, 0xfe, 0x71, 0x4c, 0xbf, 0xff, 0xf2, 0x6b, 0x50, 0xa7, 0x90, 0x41, 0x2c, 0xd8, 0x40, 0xfa, 0x91, 0xcb, 0xff, 0xf8, - 0x71, 0x5c, 0x1e, 0x5b, 0xf7, 0x71, 0x8a, 0x47, 0xe7, 0x2a, 0x11, 0x95, + 0x71, 0x5c, 0x1f, 0x9b, 0xf7, 0x71, 0x8a, 0x47, 0xe7, 0x2a, 0x11, 0x95, 0x8d, 0x97, 0xf8, 0x0f, 0xb4, 0x99, 0x1b, 0x39, 0x48, 0x9a, 0x27, 0x61, - 0xde, 0x24, 0x37, 0xbb, 0x02, 0x72, 0xf7, 0xde, 0x61, 0xca, 0x59, 0xb9, + 0xde, 0x24, 0x37, 0xbb, 0x02, 0x72, 0xf7, 0x3e, 0x61, 0xca, 0x59, 0xb9, 0x71, 0xbb, 0xf4, 0xe1, 0xd2, 0x36, 0x72, 0xff, 0x28, 0xfc, 0x52, 0x64, 0x6c, 0xe5, 0xfe, 0x06, 0xa7, 0x64, 0x67, 0x8e, 0x5f, 0xf6, 0xe1, 0x81, 0xec, 0x0a, 0xce, 0x5c, 0x83, 0x87, 0xd8, 0xa9, 0xa5, 0x42, 0x33, 0xc3, 0x0a, 0x3b, 0xd2, 0x06, 0xce, 0x5f, 0xc1, 0x7d, 0x7e, 0xd3, 0x0e, 0x5e, 0xea, 0x9c, 0x4e, 0x5f, 0xf4, 0x30, 0x71, 0x7a, 0x4f, 0xce, 0x5f, 0x82, 0xfb, 0xde, 0x1c, 0xa9, 0x1f, 0xfe, 0xc8, 0x00, 0x71, 0x7f, 0xd1, 0x2c, - 0x4d, 0xec, 0x10, 0x72, 0xff, 0xde, 0x86, 0x7c, 0xb4, 0xfb, 0x34, 0x72, - 0xfd, 0xdc, 0xd2, 0x6c, 0xe5, 0xe1, 0x49, 0x7c, 0x7c, 0xfe, 0x40, 0xbf, + 0x4d, 0xec, 0x10, 0x72, 0xff, 0xde, 0x86, 0x72, 0xb4, 0xe7, 0x34, 0x72, + 0xfd, 0xdc, 0xd2, 0x6c, 0xe5, 0xe1, 0x49, 0x72, 0x7c, 0xfe, 0x40, 0xbf, 0xf3, 0xe7, 0xf0, 0x2e, 0x1c, 0x54, 0xe5, 0x4e, 0x98, 0x74, 0xa1, 0x3d, 0xf9, 0x9d, 0xf7, 0xbd, 0x8d, 0x67, 0x2f, 0xfa, 0x32, 0x5d, 0xc4, 0x96, - 0xce, 0x5c, 0xff, 0x6c, 0xf7, 0x3c, 0x4b, 0x73, 0x24, 0x72, 0xff, 0x9f, + 0xce, 0x5c, 0xfc, 0xec, 0xf7, 0x3c, 0x4b, 0x73, 0x24, 0x72, 0xff, 0x9f, 0x16, 0x1c, 0xd7, 0xe8, 0x72, 0xe4, 0xd0, 0x4f, 0x3f, 0xa2, 0xf7, 0xfd, - 0x12, 0xd8, 0xc7, 0xee, 0xc3, 0x97, 0xef, 0x46, 0x0a, 0xce, 0x5f, 0x7d, - 0xe8, 0x61, 0xca, 0x54, 0xf2, 0x7e, 0x26, 0xbf, 0xe9, 0x29, 0xe4, 0xea, - 0x0f, 0x8e, 0x5f, 0xfe, 0x8c, 0xfb, 0xdd, 0x8f, 0x0c, 0x7f, 0xb3, 0x97, + 0x12, 0xd8, 0xc7, 0xee, 0xc3, 0x97, 0xef, 0x46, 0x0a, 0xce, 0x5f, 0x73, + 0xe8, 0x61, 0xca, 0x54, 0xf2, 0x79, 0x26, 0xbf, 0xe9, 0x29, 0xe4, 0xea, + 0x0f, 0x8e, 0x5f, 0xfe, 0x8c, 0xe7, 0xdd, 0x8f, 0x0c, 0x7f, 0xb3, 0x97, 0x47, 0xe7, 0x2e, 0xeb, 0x0e, 0x52, 0xcd, 0x76, 0xc5, 0xe9, 0x11, 0xec, 0xe4, 0x9e, 0x39, 0x03, 0xc5, 0xff, 0xe1, 0x03, 0xc9, 0x80, 0xf7, 0x60, - 0x1c, 0x39, 0xcb, 0xd3, 0xa6, 0x8e, 0x5f, 0xf6, 0xd3, 0xef, 0x4d, 0x28, - 0xf8, 0xe5, 0xfb, 0x7e, 0xde, 0x78, 0xe5, 0x6c, 0xf9, 0x00, 0x79, 0x7f, + 0x1c, 0x39, 0xcb, 0xd3, 0xa6, 0x8e, 0x5f, 0xf6, 0xd3, 0x9f, 0x4d, 0x28, + 0xe4, 0xe5, 0xfb, 0x7e, 0xde, 0x78, 0xe5, 0x6c, 0xf9, 0x00, 0x79, 0x7f, 0x03, 0x87, 0x49, 0x91, 0xb3, 0x97, 0x67, 0x4e, 0x5e, 0x6d, 0xb6, 0xca, - 0x5f, 0xfe, 0xf2, 0x7b, 0x7d, 0x46, 0x8a, 0x6a, 0x24, 0x53, 0x99, 0xa0, + 0x5f, 0xfe, 0xf2, 0x7b, 0x7d, 0x46, 0x8a, 0x6a, 0x24, 0x53, 0xe9, 0xa0, 0xa5, 0x53, 0x6c, 0x48, 0x40, 0xb9, 0x17, 0x8d, 0x00, 0x6d, 0x7f, 0xff, 0xc9, 0xe9, 0x40, 0xe7, 0xba, 0x99, 0xe8, 0x62, 0x6a, 0x47, 0x2a, 0x4c, - 0x91, 0x30, 0xb6, 0xe1, 0x02, 0xe1, 0xf3, 0xf1, 0x3a, 0x0e, 0xcd, 0x0a, + 0x91, 0x30, 0xb6, 0xe1, 0x02, 0xe1, 0xf3, 0xc9, 0x3a, 0x0e, 0xcd, 0x0a, 0xfd, 0x46, 0x7a, 0xc8, 0x4a, 0x75, 0xf7, 0xf2, 0xd1, 0x8d, 0xdf, 0x67, - 0x7e, 0x8e, 0xef, 0x8a, 0x7d, 0xff, 0x7d, 0x2d, 0xef, 0x02, 0xfe, 0x39, + 0x7e, 0x8e, 0xef, 0x8a, 0x7d, 0xff, 0x73, 0x2d, 0xef, 0x02, 0xfe, 0x39, 0x6c, 0x39, 0x7d, 0xa1, 0x7e, 0x27, 0x2a, 0x0f, 0xb5, 0x53, 0xa4, 0x10, - 0xbd, 0xfe, 0xf0, 0xe5, 0x9c, 0xe5, 0xe8, 0xee, 0xce, 0x57, 0xc6, 0xb1, - 0x04, 0x2f, 0xfd, 0x0b, 0xe5, 0x83, 0x00, 0xe1, 0xf6, 0x72, 0xff, 0xfe, - 0x7f, 0x27, 0x5d, 0x9c, 0xb3, 0x71, 0x9a, 0xc1, 0x39, 0x7f, 0xf6, 0xdf, - 0xed, 0xef, 0x07, 0xf6, 0x98, 0x72, 0xff, 0xf2, 0x2f, 0x70, 0xd3, 0x3d, + 0xbd, 0xfe, 0xf0, 0xe5, 0x9c, 0xe5, 0xe8, 0xee, 0xce, 0x57, 0x26, 0xb1, + 0x04, 0x2f, 0xfd, 0x0b, 0xf9, 0x83, 0x00, 0xe1, 0xf6, 0x72, 0xff, 0xfe, + 0x7f, 0x27, 0x5d, 0x9f, 0x33, 0x71, 0x9a, 0xc1, 0x39, 0x7f, 0xf6, 0xdf, + 0x9d, 0xef, 0x07, 0xf6, 0x98, 0x72, 0xff, 0xf2, 0x2f, 0x70, 0xd3, 0x3d, 0x29, 0x66, 0xce, 0x56, 0x93, 0x50, 0x61, 0x08, 0xa2, 0x79, 0x67, 0x8a, - 0x3d, 0xf6, 0xbb, 0x82, 0x72, 0x90, 0xfb, 0x5d, 0x32, 0xfe, 0x1e, 0x4a, - 0x6e, 0x30, 0xe5, 0xf7, 0xa3, 0xe6, 0xce, 0x52, 0xd5, 0x3c, 0xf6, 0x50, + 0x3d, 0xf6, 0xbb, 0x82, 0x72, 0x90, 0xfb, 0x5d, 0x32, 0xfe, 0x1f, 0x8a, + 0x6e, 0x30, 0xe5, 0xf7, 0xa3, 0x96, 0xce, 0x52, 0xd5, 0x3c, 0xf6, 0x50, 0x37, 0xe4, 0x0d, 0x97, 0xdf, 0xff, 0xbc, 0x05, 0x3c, 0x31, 0xfb, 0xfb, 0xf5, 0x06, 0x47, 0x2e, 0x6f, 0xa7, 0x2f, 0xff, 0x40, 0xad, 0x4d, 0x3f, - 0xe9, 0xee, 0xc1, 0xcb, 0xf9, 0x9c, 0xbb, 0x9f, 0xb9, 0xcb, 0xf9, 0xbd, + 0xe9, 0xee, 0xc1, 0xcb, 0xf9, 0x9f, 0x3b, 0x9f, 0xb9, 0xcb, 0xf9, 0xbd, 0xe6, 0x0c, 0xe7, 0x2b, 0x0f, 0x79, 0x0c, 0x2f, 0xa3, 0x71, 0xc4, 0xe5, 0xff, 0xd0, 0x2f, 0xe9, 0x42, 0xae, 0xdf, 0x8e, 0x57, 0x4f, 0x9c, 0x04, - 0x77, 0xb9, 0x3a, 0xce, 0x54, 0x27, 0xc0, 0xb5, 0x9f, 0xc6, 0x37, 0x0a, + 0x77, 0xbe, 0x3a, 0xce, 0x54, 0x27, 0xc0, 0xb5, 0x9f, 0xc6, 0x37, 0x0a, 0x8f, 0x42, 0x1f, 0x80, 0x8a, 0xfe, 0x92, 0x8c, 0x62, 0x35, 0x9c, 0xbe, 0x62, 0x90, 0x27, 0x2f, 0x90, 0x38, 0xc3, 0x97, 0xce, 0xe3, 0xf9, 0xcb, 0x37, 0x07, 0x84, 0xa9, 0x0d, 0xc0, 0x61, 0xcb, 0xfc, 0xdb, 0xcd, 0x92, 0x86, 0xb3, 0x97, 0xee, 0x00, 0x4c, 0x93, 0x1c, 0xa4, 0x45, 0x27, 0x4a, - 0x76, 0x2e, 0x03, 0x7b, 0xff, 0x42, 0x33, 0xbf, 0x3b, 0x5f, 0xb6, 0x72, + 0x76, 0x2e, 0x03, 0x7b, 0xff, 0x42, 0x33, 0xbc, 0xbb, 0x5f, 0xb6, 0x72, 0xff, 0x43, 0xeb, 0xad, 0xb8, 0x4a, 0x5c, 0xdb, 0x65, 0x28, 0x27, 0x98, - 0xd9, 0x9d, 0xef, 0x23, 0x59, 0x4e, 0x66, 0x8e, 0xfe, 0xf9, 0x69, 0xbe, + 0xd9, 0x9d, 0xef, 0x23, 0x59, 0x4f, 0xa6, 0x8e, 0xfe, 0xe5, 0x69, 0xbe, 0xa1, 0xcb, 0xe0, 0x48, 0x1e, 0x39, 0x50, 0xaa, 0xa5, 0x0c, 0xa6, 0x8c, 0x21, 0x87, 0x9b, 0x85, 0x8f, 0x8c, 0x5a, 0x17, 0x5f, 0x08, 0x7a, 0xe7, 0x2f, 0x63, 0xb5, 0x9c, 0xac, 0x37, 0xfa, 0x21, 0xb9, 0xbd, 0x9c, 0xb6, - 0x1c, 0xb7, 0xd8, 0x6a, 0x3c, 0x31, 0x7d, 0xf4, 0xb8, 0x4f, 0x8e, 0x5f, + 0x1c, 0xb7, 0x38, 0x6a, 0x3c, 0x31, 0x7d, 0xcc, 0xb8, 0x4e, 0x4e, 0x5f, 0xfd, 0xbd, 0x84, 0x60, 0x3d, 0x8f, 0x6c, 0xe5, 0x42, 0x25, 0x70, 0x9c, 0x05, 0x57, 0xfb, 0xa8, 0xf2, 0xf2, 0x4e, 0x72, 0xff, 0xde, 0x4d, 0x3f, 0xfc, 0x1e, 0xce, 0x9c, 0xbf, 0xe4, 0x6c, 0x73, 0xc8, 0x0f, 0xce, 0x5f, 0x93, 0x41, 0x89, 0xce, 0x5f, 0xe7, 0xd7, 0xb6, 0x28, 0xa9, 0xcb, 0xff, - 0xdb, 0xc5, 0x70, 0x1a, 0x70, 0xc7, 0x60, 0xe5, 0x49, 0x38, 0x0f, 0x8b, + 0xdb, 0xc5, 0x70, 0x1a, 0x70, 0xc7, 0x60, 0xe5, 0x49, 0x38, 0x0e, 0x4b, 0x90, 0xcd, 0xad, 0x0b, 0xa7, 0x2e, 0x51, 0xb3, 0x3b, 0xff, 0xff, 0x3a, 0x7a, 0x3a, 0x39, 0xee, 0xa2, 0x92, 0x8e, 0x28, 0x3f, 0x9c, 0xbf, 0x2f, 0x19, 0x1b, 0x39, 0x78, 0x02, 0x13, 0x95, 0xd4, 0x57, 0xbb, 0x67, 0xe4, - 0xf7, 0xb1, 0x34, 0x72, 0xff, 0x49, 0x19, 0xdf, 0x9d, 0xac, 0xe5, 0xf3, - 0xea, 0x24, 0x72, 0xff, 0x9f, 0xee, 0x5f, 0x6f, 0x05, 0x53, 0x95, 0x3a, - 0x2c, 0x3e, 0x1b, 0x61, 0xbf, 0x88, 0x6f, 0xba, 0xd6, 0x8c, 0x39, 0x78, - 0x63, 0xf3, 0x97, 0xa1, 0x99, 0xc8, 0xf0, 0x76, 0x4b, 0x7f, 0xe8, 0xfb, + 0xf7, 0xb1, 0x34, 0x72, 0xff, 0x49, 0x19, 0xde, 0x5d, 0xac, 0xe5, 0xf3, + 0xea, 0x24, 0x72, 0xff, 0x9f, 0x9f, 0x9c, 0xef, 0x05, 0x53, 0x95, 0x3a, + 0x2c, 0x39, 0x1b, 0x61, 0xbf, 0x88, 0x6f, 0xba, 0xd6, 0x8c, 0x39, 0x78, + 0x63, 0xf3, 0x97, 0xa1, 0x99, 0xf0, 0xf0, 0x76, 0x4b, 0x7f, 0xe8, 0xe7, 0xb0, 0xc5, 0xf5, 0x26, 0x39, 0x50, 0x9e, 0xa6, 0x43, 0x81, 0x21, 0x01, 0xa3, 0x4b, 0xf8, 0x43, 0xbd, 0xa3, 0x0e, 0x5f, 0x96, 0xf3, 0xe3, 0x67, 0x2f, 0xd1, 0xa0, 0xe0, 0x9c, 0xac, 0x3f, 0xc1, 0x2d, 0xf1, 0x4d, 0xfa, 0x1a, 0x27, 0x40, 0x72, 0xff, 0xe8, 0xfe, 0x3a, 0xc1, 0x75, 0x7a, 0x87, - 0x2d, 0xc3, 0x1c, 0xbf, 0xbb, 0x02, 0xdb, 0xfc, 0x72, 0xff, 0xc3, 0x34, - 0x60, 0xcf, 0x9f, 0x78, 0xe5, 0x04, 0xfb, 0x5c, 0xba, 0xf2, 0xaa, 0x30, + 0x2d, 0xc3, 0x1c, 0xbf, 0xbb, 0x02, 0xdb, 0xf2, 0x72, 0xff, 0xc3, 0x34, + 0x60, 0xcf, 0x9c, 0xf8, 0xe5, 0x04, 0xfb, 0x5c, 0xba, 0xf2, 0xaa, 0x30, 0xe5, 0xff, 0xc8, 0x1e, 0xc2, 0xe3, 0xf7, 0x1f, 0xce, 0x5f, 0x9f, 0x73, 0xa6, 0x8e, 0x5f, 0x69, 0x01, 0x39, 0xe2, 0xf5, 0x5f, 0xfb, 0x13, 0x8e, - 0x0e, 0x05, 0xe4, 0x78, 0xbd, 0x57, 0xe7, 0x1f, 0xa5, 0xcc, 0x27, 0xf4, + 0x0e, 0x05, 0xe4, 0x78, 0xbd, 0x57, 0xe7, 0x1e, 0x65, 0xf4, 0x27, 0xf4, 0xd9, 0x85, 0x05, 0x1c, 0x8c, 0x85, 0x15, 0xf9, 0x5f, 0x3b, 0x89, 0xcb, 0xc2, 0x09, 0xce, 0x53, 0x9e, 0x27, 0x89, 0xe9, 0x11, 0x1a, 0x2d, 0x95, 0x0a, 0xcc, 0xc2, 0x5b, 0xa2, 0x96, 0x22, 0x3c, 0x20, 0xc4, 0x87, 0x63, 0xe0, 0x8e, 0xd6, 0xe6, 0xa5, 0xab, 0x39, 0x79, 0x23, 0x47, 0x2b, 0x86, - 0x37, 0x9d, 0x21, 0xbf, 0xfb, 0x48, 0xc8, 0x6b, 0x1c, 0x67, 0xd0, 0x72, + 0x37, 0x9d, 0x21, 0xbf, 0xfb, 0x48, 0xc8, 0x6b, 0x1c, 0x67, 0x30, 0x72, 0xa4, 0x7d, 0x93, 0x13, 0x5f, 0x20, 0xb8, 0x4e, 0x5e, 0x9d, 0x88, 0x72, 0x82, 0x6f, 0x44, 0x82, 0xfd, 0x2c, 0xe3, 0x12, 0x39, 0x7b, 0x35, 0x07, - 0x2b, 0xe4, 0x62, 0x23, 0x06, 0x88, 0x3a, 0x53, 0x70, 0xcc, 0x72, 0xfe, - 0xeb, 0xcd, 0xa8, 0x9c, 0xe5, 0xfc, 0x9f, 0x6f, 0xb8, 0xb3, 0x97, 0xff, + 0x2b, 0x94, 0x62, 0x23, 0x06, 0x88, 0x3a, 0x53, 0x70, 0xcc, 0x72, 0xfe, + 0xeb, 0xcd, 0xa8, 0x9c, 0xe5, 0xfc, 0x9c, 0xef, 0xb8, 0xb3, 0x97, 0xff, 0xd9, 0xed, 0xe4, 0xdd, 0x8e, 0x39, 0xde, 0xc1, 0xcb, 0xff, 0xff, 0xf2, - 0x67, 0xdb, 0x4c, 0x6f, 0x96, 0x7d, 0x2d, 0xa7, 0xb6, 0x9f, 0x04, 0x20, - 0x9c, 0xe5, 0xff, 0xf9, 0x04, 0x3c, 0x94, 0xf2, 0x6d, 0xd0, 0x41, 0x23, + 0x67, 0x3b, 0x4c, 0x6f, 0xe6, 0x73, 0x2d, 0xa7, 0xb6, 0x9c, 0x84, 0x20, + 0x9c, 0xe5, 0xff, 0xf9, 0x04, 0x3f, 0x14, 0xf2, 0x6d, 0xd0, 0x41, 0x23, 0x97, 0xcf, 0x3f, 0x50, 0xe5, 0x62, 0x78, 0xc8, 0x2f, 0x31, 0x78, 0x97, 0x79, 0x47, 0x8c, 0x22, 0x5a, 0x2b, 0x5e, 0x06, 0xa4, 0x72, 0xff, 0xcc, 0x70, 0xea, 0x3d, 0xdc, 0x09, 0xcb, 0xf9, 0xfd, 0xfa, 0x83, 0x23, 0x97, 0xfc, 0x17, 0x76, 0xff, 0x7f, 0x6c, 0xe5, 0xfe, 0x92, 0x90, 0x22, 0x06, - 0x1c, 0xae, 0x48, 0xf7, 0x81, 0xd9, 0xcf, 0x95, 0x2f, 0x73, 0xab, 0xfd, - 0x12, 0x4e, 0x6d, 0xb6, 0xd9, 0x4b, 0xb3, 0xa7, 0x2f, 0x2b, 0x81, 0x39, + 0x1c, 0xaf, 0x88, 0xf7, 0x81, 0xd9, 0xcf, 0x95, 0x2f, 0x73, 0xab, 0xfd, + 0x12, 0x4f, 0xad, 0xb6, 0xd9, 0x4b, 0xb3, 0xa7, 0x2f, 0x2b, 0x81, 0x39, 0x7f, 0x75, 0xf4, 0xb8, 0xf1, 0xcb, 0x9c, 0x27, 0x2f, 0xed, 0x3e, 0xfa, - 0xf2, 0x39, 0x6f, 0x8e, 0x5c, 0x8d, 0x9c, 0xb9, 0x4f, 0xce, 0x54, 0xc6, + 0xf2, 0x39, 0x6e, 0x4e, 0x5c, 0x8d, 0x9c, 0xb9, 0x4f, 0xce, 0x54, 0xc6, 0xc3, 0xf1, 0x7b, 0xd2, 0x70, 0x9c, 0xb9, 0xb6, 0xce, 0x54, 0x91, 0xbb, 0x82, 0xcb, 0x2d, 0x44, 0x2d, 0x91, 0xb6, 0x39, 0x7b, 0xca, 0x7e, 0x53, - 0x99, 0xeb, 0x5f, 0xec, 0x62, 0x06, 0x70, 0x6c, 0xe5, 0xff, 0xfd, 0xfb, - 0x4c, 0xd4, 0x79, 0x16, 0x81, 0x9e, 0x06, 0x0e, 0x5e, 0xcf, 0xbc, 0x72, + 0xe9, 0xeb, 0x5f, 0xec, 0x62, 0x06, 0x70, 0x6c, 0xe5, 0xff, 0xfd, 0xfb, + 0x4c, 0xd4, 0x79, 0x16, 0x81, 0x9e, 0x06, 0x0e, 0x5e, 0xce, 0x7c, 0x72, 0xd8, 0x27, 0xf3, 0xb5, 0xca, 0xea, 0x34, 0xf7, 0x0a, 0xdb, 0xfe, 0x40, 0xe3, 0x12, 0x64, 0x6c, 0xe5, 0xff, 0xe7, 0x0e, 0x60, 0xab, 0xbd, 0xe0, 0xfe, 0x72, 0xfb, 0xa0, 0x75, 0x61, 0x10, 0x4c, 0x39, 0xbc, 0x31, 0xd3, 0x97, 0xff, 0xf4, 0x9f, 0x7b, 0x8c, 0x9c, 0x12, 0x0e, 0x85, 0xdb, 0x39, 0x68, 0x0a, 0x2c, 0x55, 0x3a, 0x41, 0xba, 0xda, 0x72, 0x1e, 0x8d, 0x6e, 0xfe, 0x46, 0x2f, 0x05, 0x67, 0x2f, 0x9e, 0x7d, 0xf4, 0xe5, 0x68, 0xf3, - 0xf6, 0x59, 0x5c, 0x97, 0x30, 0xe4, 0x2c, 0x11, 0xdf, 0xa3, 0x60, 0x49, + 0xf6, 0x59, 0x5f, 0x17, 0x30, 0xe4, 0x2c, 0x11, 0xde, 0x63, 0x60, 0x49, 0x52, 0xbe, 0x79, 0xbf, 0x71, 0x53, 0xa9, 0xe3, 0x97, 0xfd, 0x9e, 0xec, - 0x6b, 0xd8, 0xb3, 0x97, 0xef, 0xb0, 0x41, 0x31, 0xcb, 0xd1, 0xa9, 0x8e, + 0x6b, 0xd8, 0xb3, 0x97, 0xee, 0x70, 0x41, 0x31, 0xcb, 0xd1, 0xa9, 0x8e, 0x54, 0x32, 0x6f, 0xf2, 0x50, 0x1a, 0x46, 0xc7, 0xd4, 0xc7, 0x9c, 0xfb, 0xfd, 0xa4, 0x4a, 0xc0, 0x70, 0xd0, 0xa6, 0xf6, 0xde, 0x63, 0x97, 0xff, - 0xb3, 0xec, 0xe3, 0x01, 0x1c, 0xf6, 0x7e, 0x72, 0xe5, 0x3f, 0x39, 0x5a, + 0xb3, 0x9c, 0xe3, 0x01, 0x1c, 0xf6, 0x7e, 0x72, 0xe5, 0x3f, 0x39, 0x5a, 0x3e, 0x4f, 0xd2, 0xef, 0xfe, 0x40, 0xbf, 0x93, 0x79, 0x2c, 0xe9, 0xcb, 0x9f, 0x80, 0xe5, 0xb3, 0xa7, 0xb7, 0xe4, 0x2b, 0xff, 0xbf, 0x50, 0x64, - 0x39, 0xef, 0x64, 0xe7, 0x2b, 0xe4, 0xdb, 0x35, 0x08, 0x11, 0x7e, 0xf1, - 0x3d, 0xe1, 0x5f, 0x01, 0xcb, 0xff, 0xfb, 0xed, 0x8b, 0xef, 0xb9, 0x2c, - 0xea, 0x6b, 0xae, 0x72, 0xfb, 0x3e, 0x9f, 0x89, 0xcb, 0xfe, 0x10, 0xe0, - 0x82, 0x59, 0xb3, 0x97, 0xe8, 0xfb, 0x60, 0xfc, 0xe5, 0xfe, 0x53, 0xc3, + 0x39, 0xef, 0x64, 0xe7, 0x2b, 0x94, 0xdb, 0x35, 0x08, 0x11, 0x7e, 0xf1, + 0x3d, 0xe1, 0x5f, 0x01, 0xcb, 0xff, 0xfb, 0x9d, 0x8b, 0xef, 0xb9, 0x2c, + 0xea, 0x6b, 0xae, 0x72, 0xfb, 0x39, 0x9f, 0x89, 0xcb, 0xfe, 0x10, 0xe0, + 0x82, 0x59, 0xb3, 0x97, 0xe8, 0xe7, 0x60, 0xfc, 0xe5, 0xfe, 0x53, 0xc3, 0x93, 0xa6, 0x8e, 0x5f, 0x79, 0x36, 0x87, 0x2b, 0x13, 0x55, 0x41, 0xfd, 0x2d, 0x39, 0x37, 0xe6, 0xe2, 0x54, 0x03, 0x4b, 0xff, 0xa7, 0x85, 0x3f, 0x04, 0xa4, 0xfd, 0x01, 0xcb, 0xfe, 0xea, 0x05, 0x38, 0x78, 0x14, 0x39, 0x7f, 0x9e, 0x58, 0x1d, 0x6f, 0x67, 0x2f, 0xa3, 0x14, 0x09, 0xcb, 0xff, 0xfa, 0x43, 0x19, 0xbc, 0x1f, 0x77, 0x02, 0x0f, 0x6c, 0xe5, 0xfe, 0x55, 0x3c, 0xfd, 0x6d, 0xac, 0xe5, 0xfd, 0x13, 0xb4, 0xcd, 0x41, 0xcb, 0xfd, - 0x93, 0x77, 0x36, 0xe2, 0x72, 0xff, 0xc1, 0xcf, 0xa5, 0xbf, 0x6d, 0xff, + 0x93, 0x77, 0x36, 0xe2, 0x72, 0xff, 0xc1, 0xce, 0x65, 0xbf, 0x6d, 0xff, 0x39, 0x5a, 0x3f, 0x30, 0x19, 0x5f, 0xe6, 0xc3, 0xdc, 0xe3, 0x9a, 0x39, - 0x7f, 0xf2, 0x33, 0x92, 0xfa, 0x9d, 0x5a, 0x6c, 0xe5, 0xfe, 0xc9, 0x60, - 0x38, 0x77, 0x13, 0x97, 0xff, 0x44, 0xbb, 0x1f, 0x7a, 0x3a, 0xed, 0x67, - 0x2a, 0x11, 0xf3, 0xa3, 0x6e, 0xa3, 0x09, 0xb5, 0xff, 0xfe, 0x41, 0xcf, - 0xbc, 0xab, 0xfb, 0xb1, 0xdc, 0xe2, 0xf2, 0x39, 0x41, 0x56, 0x80, 0xb3, - 0x3f, 0x88, 0x91, 0x66, 0x63, 0x8d, 0x42, 0x8b, 0xd1, 0x8d, 0xf1, 0x3b, + 0x7f, 0xf2, 0x33, 0xe2, 0xfa, 0x9d, 0x5a, 0x6c, 0xe5, 0xfe, 0xc9, 0x60, + 0x38, 0x77, 0x13, 0x97, 0xff, 0x44, 0xbb, 0x1c, 0xfa, 0x3a, 0xed, 0x67, + 0x2a, 0x11, 0xf3, 0xa3, 0x6e, 0xa3, 0x09, 0xb5, 0xff, 0xfe, 0x41, 0xce, + 0x7c, 0xab, 0xfb, 0xb1, 0xdc, 0xe2, 0xf2, 0x39, 0x41, 0x56, 0x80, 0xb3, + 0x3e, 0x48, 0x91, 0x66, 0x63, 0x8d, 0x42, 0x8b, 0xd1, 0x8d, 0xf1, 0x3b, 0xb8, 0x60, 0xe5, 0xff, 0x05, 0x35, 0x1c, 0x7f, 0xdc, 0x8e, 0x5d, 0x0c, 0x39, 0x50, 0x7a, 0x5d, 0x3c, 0xae, 0xa2, 0x23, 0xcc, 0xf7, 0xfd, 0xb7, 0xea, 0x05, 0x69, 0x39, 0xcb, 0xfc, 0xf2, 0xc0, 0xef, 0x70, 0x72, 0xa0, 0xfa, 0xf0, 0xe6, 0xa1, 0x74, 0xcb, 0x25, 0xbd, 0xbc, 0x61, 0x20, 0x84, 0x75, 0xe8, 0x1f, 0x1c, 0xbf, 0xfe, 0x8d, 0x67, 0x14, 0xf7, 0xe0, 0x1d, 0xa0, 0x4e, 0x5f, 0xe4, 0xea, 0x6a, 0x53, 0x41, 0xcb, 0xff, 0xf2, 0x01, - 0x6a, 0x7d, 0xfb, 0xed, 0xf4, 0x9f, 0x7e, 0x72, 0xf9, 0xf5, 0x12, 0x39, + 0x6a, 0x73, 0xfb, 0xed, 0xf4, 0x9c, 0xfe, 0x72, 0xf9, 0xf5, 0x12, 0x39, 0x7f, 0xff, 0x20, 0xba, 0x0f, 0xfa, 0x8e, 0xba, 0x7a, 0x3a, 0x72, 0x84, 0xfe, 0x3c, 0x43, 0x7e, 0x4f, 0x6c, 0x13, 0x9c, 0xbf, 0xfc, 0x29, 0xff, - 0xbe, 0x5a, 0x69, 0x48, 0x09, 0xcb, 0xfe, 0xea, 0x81, 0x07, 0xb7, 0xfc, + 0xb9, 0x5a, 0x69, 0x48, 0x09, 0xcb, 0xfe, 0xea, 0x81, 0x07, 0xb7, 0xfc, 0x1c, 0xa8, 0x44, 0x43, 0xa6, 0x50, 0x53, 0xc5, 0x48, 0x69, 0x30, 0x87, 0xd0, 0xb1, 0xbf, 0x68, 0x0b, 0xec, 0x1c, 0xbf, 0xb5, 0x34, 0x93, 0xdb, - 0x39, 0x61, 0x83, 0xd7, 0xc2, 0x8b, 0xfd, 0x33, 0xcc, 0xff, 0x4b, 0x67, - 0x2f, 0xe7, 0x9d, 0x26, 0x46, 0xce, 0x5f, 0xff, 0xe7, 0x6f, 0xd9, 0xde, - 0x41, 0xc9, 0xa4, 0xfa, 0x9f, 0xa0, 0x39, 0x58, 0x8c, 0xb7, 0x36, 0x12, + 0x39, 0x61, 0x83, 0xd7, 0xc2, 0x8b, 0xfd, 0x33, 0xcc, 0xfc, 0xcb, 0x67, + 0x2f, 0xe7, 0x9d, 0x26, 0x46, 0xce, 0x5f, 0xff, 0xe7, 0x6f, 0xd9, 0xdf, + 0x81, 0xc9, 0xa4, 0xfa, 0x9f, 0xa0, 0x39, 0x58, 0x8c, 0xb7, 0x36, 0x12, 0xfb, 0xf6, 0x0c, 0xf8, 0xd9, 0xcb, 0xf3, 0xb3, 0xa8, 0xd9, 0xca, 0x9c, 0xf4, 0x02, 0x51, 0x7f, 0xd1, 0x3a, 0x92, 0xe8, 0x1e, 0x73, 0x95, 0x87, 0xbf, 0xa2, 0x3b, 0x70, 0xc7, 0x2f, 0xd1, 0xad, 0x67, 0x4e, 0x5f, 0xc2, 0xea, 0xc3, 0x20, 0xe5, 0x70, 0x87, 0xd3, 0x21, 0x60, 0x13, 0xdf, 0x44, 0xea, 0xaa, 0x72, 0xff, 0xfc, 0x8b, 0x86, 0x6d, 0xf5, 0x8c, 0x02, 0xde, 0x47, 0x2e, 0x4e, 0x27, 0x2d, 0xd3, 0x95, 0x23, 0xfd, 0x6b, 0x54, 0x00, - 0xc5, 0xe0, 0xc3, 0x0e, 0x5f, 0xec, 0xff, 0x26, 0x8f, 0xb6, 0x72, 0xa0, - 0xf4, 0x70, 0x72, 0xfe, 0xeb, 0xca, 0x37, 0x23, 0x97, 0xfd, 0x9d, 0x4f, - 0xb7, 0xd0, 0x6c, 0xe5, 0xd8, 0x2b, 0x3e, 0x7f, 0xcb, 0x6f, 0xe1, 0x7f, + 0xc5, 0xe0, 0xc3, 0x0e, 0x5f, 0xec, 0xff, 0x26, 0x8e, 0x76, 0x72, 0xa0, + 0xf4, 0x70, 0x72, 0xfe, 0xeb, 0xca, 0x37, 0x23, 0x97, 0xfd, 0x9d, 0x4e, + 0x77, 0xd0, 0x6c, 0xe5, 0xd8, 0x2b, 0x3e, 0x7f, 0xcb, 0x6f, 0xe1, 0x7f, 0xc3, 0x82, 0x72, 0xfc, 0x8d, 0x33, 0x4a, 0x9c, 0xb9, 0x59, 0x1c, 0xbf, 0x75, 0x38, 0xa2, 0xce, 0x5d, 0x9d, 0x91, 0xe0, 0xac, 0x62, 0x98, 0x89, 0x86, 0x8d, 0x77, 0x9b, 0x6d, 0xb2, 0x97, 0xfe, 0xd0, 0x81, 0xd4, 0xc9, - 0xa1, 0x87, 0x39, 0x9a, 0x0b, 0xf7, 0x52, 0x64, 0x6c, 0xe5, 0x96, 0x72, + 0xa1, 0x87, 0x3e, 0x9a, 0x0b, 0xf7, 0x52, 0x64, 0x6c, 0xe5, 0x96, 0x72, 0xa1, 0x11, 0x78, 0xa3, 0xa2, 0x9b, 0xfd, 0x01, 0xc9, 0x40, 0xac, 0xe5, 0x43, 0x25, 0x62, 0x71, 0xb9, 0x28, 0xe4, 0x7f, 0x0d, 0x70, 0x9e, 0x9a, 0x1e, 0x1a, 0x86, 0xe3, 0x21, 0x15, 0xd3, 0x47, 0x85, 0x10, 0xc2, 0x0f, @@ -1687,21 +1687,21 @@ 0x9e, 0x6d, 0xc7, 0x8e, 0x52, 0x1e, 0x7b, 0x8e, 0x5f, 0x23, 0xe2, 0xce, 0x5f, 0xfb, 0x38, 0x8e, 0x6e, 0x61, 0x80, 0x9c, 0xbe, 0x58, 0x62, 0x73, 0x97, 0x7f, 0x07, 0x2f, 0x6d, 0x34, 0x72, 0xb0, 0xf5, 0xbf, 0x23, 0xf0, - 0xbd, 0xfe, 0x96, 0x0a, 0x07, 0x04, 0xe5, 0xef, 0x6f, 0x9c, 0x27, 0xcf, + 0xbd, 0xfe, 0x96, 0x0a, 0x07, 0x04, 0xe5, 0xef, 0x6f, 0xec, 0x27, 0xcf, 0x82, 0xd3, 0x1c, 0x75, 0x97, 0xf2, 0x01, 0x20, 0xdc, 0x25, 0x7c, 0x5f, 0x76, 0xe0, 0xe5, 0xe6, 0x06, 0x0e, 0x5f, 0xe1, 0xf3, 0xcd, 0xb8, 0xf1, 0xca, 0x43, 0xcf, 0x71, 0xcb, 0xe4, 0x7c, 0x59, 0xcb, 0xff, 0x67, 0x11, 0xcd, 0xcc, 0x30, 0x13, 0x97, 0xcb, 0x0c, 0x4e, 0x72, 0xfe, 0x9b, 0xf4, 0x6b, 0x79, 0x8e, 0x5d, 0xfc, 0x1c, 0xbd, 0xb4, 0xd1, 0xca, 0xc4, 0x44, 0xac, 0x8f, 0xf3, 0x3f, 0x0b, 0xdf, 0xe9, 0x60, 0xa0, 0x70, 0x4e, 0x5f, - 0xc2, 0xe1, 0xc5, 0x79, 0xc2, 0xe5, 0x48, 0x45, 0xb0, 0x41, 0x72, 0x87, + 0xc2, 0xe1, 0xc5, 0x7e, 0xc2, 0xe5, 0x48, 0x45, 0xb0, 0x41, 0x72, 0x87, 0xe6, 0x84, 0x57, 0x59, 0x7f, 0x20, 0x12, 0x0d, 0xc3, 0x23, 0xc7, 0xb7, - 0xff, 0x6a, 0x3e, 0xd8, 0xc3, 0x33, 0xef, 0x1c, 0xbf, 0xff, 0x38, 0x73, + 0xff, 0x6a, 0x39, 0xd8, 0xc3, 0x33, 0x9f, 0x1c, 0xbf, 0xff, 0x38, 0x73, 0x05, 0x55, 0x06, 0x06, 0x74, 0xd1, 0xcb, 0xcf, 0xa9, 0xcf, 0x20, 0x92, - 0xfa, 0x59, 0xf4, 0x8f, 0x20, 0x92, 0xf6, 0xd0, 0x27, 0x90, 0x49, 0x73, + 0xfa, 0x59, 0xcc, 0x8f, 0x20, 0x92, 0xf6, 0xd0, 0x27, 0x90, 0x49, 0x73, 0x6d, 0x9e, 0x41, 0x25, 0x2d, 0x15, 0x33, 0x15, 0x78, 0xc1, 0xb2, 0x9b, - 0x9f, 0xc5, 0x90, 0x48, 0xe6, 0x6f, 0xef, 0xec, 0xee, 0x60, 0xaa, 0x72, - 0xf3, 0x8f, 0xfc, 0x97, 0xdb, 0xe2, 0x73, 0x2b, 0x50, 0xc2, 0x62, 0x28, + 0x9f, 0xc5, 0x90, 0x48, 0xfa, 0x6f, 0xef, 0xec, 0xee, 0x60, 0xaa, 0x72, + 0xf3, 0x8f, 0xff, 0x17, 0xdb, 0xe2, 0x73, 0x2b, 0x50, 0xc2, 0x62, 0x28, 0xc6, 0x79, 0xe3, 0x6b, 0xe6, 0x98, 0xfd, 0x39, 0x6c, 0x6b, 0x45, 0x0f, 0xef, 0xd6, 0x91, 0xcb, 0xfa, 0x40, 0x9f, 0xc9, 0x39, 0x4b, 0xe7, 0x0f, 0x70, 0xe5, 0xe0, 0xa3, 0x0e, 0x5f, 0xfb, 0xb1, 0xe4, 0x18, 0x64, 0x6c, @@ -1709,32 +1709,32 @@ 0xff, 0x40, 0xc8, 0x63, 0xf7, 0x61, 0xcb, 0xf4, 0xd1, 0xd0, 0x68, 0xe5, 0xa0, 0xe5, 0xfe, 0x49, 0x01, 0xf7, 0xd4, 0x39, 0x7f, 0x67, 0x17, 0x66, 0x74, 0xe5, 0xa4, 0x52, 0xf3, 0xea, 0x72, 0x94, 0x52, 0xa0, 0xdc, 0xac, - 0x45, 0x83, 0xb7, 0xa3, 0xf5, 0x94, 0xe6, 0x6b, 0x69, 0x88, 0xc3, 0x18, + 0x45, 0x83, 0xb7, 0xa3, 0xf5, 0x94, 0xfa, 0x6b, 0x69, 0x88, 0xc3, 0x18, 0x4a, 0x54, 0x26, 0x39, 0x90, 0xf5, 0xbf, 0x6b, 0xf6, 0x26, 0xce, 0x5f, 0xca, 0x0c, 0xb7, 0xd0, 0x9c, 0xc3, 0x53, 0x7c, 0x07, 0xd4, 0x8e, 0x59, - 0x87, 0x2e, 0xc9, 0x04, 0xd9, 0xcc, 0x45, 0x7f, 0xf6, 0x7d, 0xed, 0xa0, + 0x87, 0x2e, 0xc9, 0x04, 0xd9, 0xcc, 0x45, 0x7f, 0xf6, 0x73, 0xed, 0xa0, 0xc7, 0xee, 0xc3, 0x97, 0xd9, 0x32, 0x30, 0xe5, 0x4e, 0x7c, 0xcd, 0xa2, - 0x5f, 0xa2, 0x69, 0x47, 0xe5, 0x2f, 0xff, 0xdd, 0xc4, 0x96, 0xf9, 0x7b, + 0x5f, 0xa2, 0x69, 0x47, 0xe5, 0x2f, 0xff, 0xdd, 0xc4, 0x96, 0xfe, 0x7b, 0xb8, 0x10, 0x7b, 0x67, 0x29, 0x68, 0x81, 0xf1, 0x4d, 0x90, 0xe5, 0xff, 0x4e, 0x09, 0x07, 0xa0, 0x71, 0x39, 0x7f, 0x24, 0x32, 0x7c, 0x6c, 0xe5, 0xfb, 0x27, 0x66, 0x30, 0xe5, 0xed, 0xa6, 0x8e, 0x50, 0x9e, 0x27, 0x8a, - 0x2f, 0xe1, 0x7f, 0xff, 0x06, 0xce, 0x5f, 0xc8, 0xaa, 0x90, 0xce, 0x61, + 0x2f, 0xe1, 0x7f, 0xff, 0x06, 0xce, 0x5f, 0xc8, 0xaa, 0x90, 0xcf, 0xa1, 0x4c, 0x33, 0x04, 0x34, 0x75, 0xb7, 0x2f, 0x10, 0xd6, 0x2a, 0x44, 0x48, 0x52, 0x8c, 0x65, 0xf7, 0xf7, 0x7b, 0x93, 0xfb, 0x67, 0x2f, 0x64, 0xe0, - 0x39, 0x58, 0x79, 0x82, 0x5f, 0x7f, 0xd9, 0xee, 0x43, 0x9f, 0xa9, 0xf1, + 0x39, 0x58, 0x79, 0x82, 0x5f, 0x7f, 0xd9, 0xef, 0x83, 0x9f, 0xa9, 0xc9, 0xca, 0x86, 0x7e, 0xa4, 0xa9, 0x11, 0xe1, 0x2c, 0xc8, 0x74, 0xaa, 0x52, 0x86, 0xfa, 0x29, 0xec, 0x65, 0x9f, 0xa8, 0x0b, 0x8e, 0xe5, 0x6b, 0xfa, 0x10, 0xcd, 0x08, 0x2f, 0xff, 0xd3, 0xeb, 0x58, 0x17, 0x67, 0x5f, 0xc3, 0x13, 0x1c, 0xbf, 0xff, 0xfc, 0x0d, 0x02, 0x61, 0x7f, 0xf7, 0xbc, 0x57, - 0x01, 0xa7, 0x0c, 0x76, 0x0e, 0x5f, 0xf7, 0x36, 0x38, 0x7b, 0x02, 0x03, + 0x01, 0xa7, 0x0c, 0x76, 0x0e, 0x5f, 0xf7, 0xd6, 0x38, 0x7b, 0x02, 0x03, 0x97, 0xd0, 0xd6, 0x18, 0x39, 0x7d, 0xc1, 0xd0, 0x28, 0x72, 0xf3, 0x6d, - 0xb6, 0x52, 0xe9, 0x41, 0x4e, 0x66, 0x82, 0xf7, 0x78, 0x66, 0xce, 0x54, - 0x27, 0x7f, 0x3a, 0xb6, 0x3c, 0xac, 0xeb, 0xe2, 0x4d, 0x23, 0xf1, 0x28, + 0xb6, 0x52, 0xe9, 0x41, 0x4f, 0xa6, 0x82, 0xf7, 0x78, 0x66, 0xce, 0x54, + 0x27, 0x7f, 0x3a, 0xb6, 0x3c, 0xac, 0xeb, 0x92, 0x4d, 0x23, 0xf1, 0x28, 0xbf, 0xfe, 0x4f, 0x4d, 0x9a, 0xd3, 0xcd, 0x9a, 0xcf, 0x1c, 0xbf, 0x95, 0x8d, 0x6b, 0x3a, 0x72, 0xfe, 0x9e, 0x69, 0x70, 0xda, 0x9c, 0xe5, 0xff, - 0xef, 0xd8, 0xf2, 0xe5, 0x01, 0x9d, 0x91, 0xa3, 0x97, 0xc9, 0x03, 0xe3, + 0xef, 0xd8, 0xf2, 0xf9, 0x01, 0x9d, 0x91, 0xa3, 0x97, 0xc9, 0x03, 0xe3, 0x97, 0xa7, 0x71, 0x39, 0x5a, 0x44, 0x57, 0x53, 0xbc, 0x41, 0x7f, 0xe5, - 0x41, 0xb9, 0x26, 0xa7, 0x07, 0xe7, 0x2e, 0x1c, 0x39, 0x79, 0xfe, 0x6c, + 0x41, 0xb9, 0x26, 0xa7, 0x07, 0xe7, 0x2e, 0x1c, 0x39, 0x79, 0xf9, 0x6c, 0xe5, 0x2a, 0x7e, 0xc8, 0x87, 0xd1, 0x5b, 0xf4, 0xfa, 0x48, 0x61, 0xcb, 0xff, 0xe8, 0x53, 0xc3, 0x1f, 0xbf, 0xbf, 0x50, 0x64, 0x72, 0x9a, 0xa5, 0x42, 0x19, 0x0c, 0x14, 0x85, 0x33, 0x97, 0xf8, 0xa2, 0xf9, 0x40, 0xf5, @@ -1750,24 +1750,24 @@ 0x8f, 0xf9, 0xe5, 0x4e, 0x54, 0x2a, 0xcf, 0x9c, 0xca, 0x43, 0xee, 0x36, 0x25, 0x3b, 0x39, 0xf4, 0x6f, 0xbc, 0x50, 0x5a, 0x0a, 0xdf, 0x0f, 0xa1, 0xa1, 0xcb, 0xee, 0x81, 0x90, 0x72, 0xe7, 0xd9, 0xcb, 0x81, 0xc3, 0x9c, - 0xa6, 0xa8, 0xfd, 0xdc, 0x8c, 0x48, 0x80, 0x2d, 0x73, 0xf3, 0x6a, 0x9f, + 0xa6, 0xa8, 0xfd, 0xdc, 0x8c, 0x48, 0x80, 0x2d, 0x73, 0xfd, 0x6a, 0x9f, 0xa3, 0x47, 0x84, 0x84, 0x0b, 0x57, 0x08, 0x7e, 0x1a, 0x15, 0x1c, 0x2e, 0x58, 0xd4, 0x09, 0x38, 0x58, 0xf6, 0x27, 0x3d, 0x27, 0x95, 0x2f, 0x29, - 0x49, 0x81, 0x97, 0xd9, 0x94, 0xb4, 0x45, 0x63, 0x60, 0x5c, 0xaa, 0x7f, - 0xa5, 0x14, 0x24, 0xb0, 0xe6, 0xb8, 0x58, 0xcd, 0x29, 0x77, 0x52, 0xba, + 0x49, 0x81, 0x97, 0xd9, 0x94, 0xb4, 0x45, 0x63, 0x60, 0x5c, 0xaa, 0x7e, + 0x65, 0x14, 0x24, 0xb0, 0xe6, 0xb8, 0x58, 0xcd, 0x29, 0x77, 0x52, 0xba, 0x99, 0x2f, 0xd3, 0xb4, 0xba, 0x67, 0x94, 0x03, 0xfc, 0x73, 0x1c, 0x3b, 0x10, 0xce, 0xbd, 0x6e, 0x93, 0x4f, 0xea, 0xc3, 0x9c, 0x12, 0xa5, 0x78, 0xb3, 0xb6, 0xa0, 0xd2, 0x51, 0xf2, 0x92, 0xfc, 0xf8, 0x21, 0xff, 0x7e, 0x66, 0x23, 0xfe, 0x72, 0xf9, 0x6e, 0xeb, 0x34, 0x51, 0x4b, 0xff, 0xf3, 0xff, 0x0b, 0xea, 0x6f, 0xa9, 0xee, 0xe0, 0x9c, 0xad, 0x22, 0x08, 0x4b, - 0xaf, 0x3c, 0xb9, 0xc2, 0x32, 0xf2, 0x15, 0x37, 0xff, 0xe0, 0xa4, 0xc3, - 0x1e, 0xdf, 0xbe, 0x5a, 0x0c, 0xe7, 0x2d, 0xcd, 0x88, 0x90, 0xd9, 0xcd, - 0xfe, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x17, 0x42, 0xff, 0xee, 0x6f, 0x2e, - 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x25, 0xaf, 0xda, 0x5b, 0xba, 0xcd, 0x17, - 0x92, 0xe7, 0xe2, 0x72, 0xdc, 0xf0, 0xf3, 0x1a, 0x1a, 0x54, 0x3f, 0xab, + 0xaf, 0x3c, 0xbe, 0xc2, 0x32, 0xf2, 0x15, 0x37, 0xff, 0xe0, 0xa4, 0xc3, + 0x1e, 0xdf, 0xb9, 0x5a, 0x0c, 0xe7, 0x2d, 0xf5, 0x88, 0x90, 0xd9, 0xcd, + 0xfe, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x17, 0x42, 0xff, 0xef, 0xaf, 0x2f, + 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x25, 0xaf, 0xda, 0x5b, 0xba, 0xcd, 0x17, + 0x92, 0xe7, 0xe2, 0x72, 0xdf, 0x70, 0xf3, 0x1a, 0x1a, 0x54, 0x3f, 0xab, 0xac, 0xf0, 0x8b, 0x91, 0x56, 0x42, 0x71, 0x70, 0x99, 0x98, 0xe5, 0x88, 0x3d, 0x9c, 0xb7, 0x1b, 0xe9, 0x10, 0xdc, 0xe0, 0x9f, 0x8a, 0xc0, 0x83, - 0xc6, 0x14, 0x17, 0xff, 0xb9, 0xb1, 0xe5, 0xcf, 0x34, 0xb7, 0x75, 0x9a, + 0xc6, 0x14, 0x17, 0xff, 0xbe, 0xb1, 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x25, 0x95, 0xb8, 0x63, 0x96, 0xe9, 0xca, 0x6a, 0x8d, 0x38, 0x05, 0xaf, 0xf2, 0x07, 0xb8, 0x82, 0xa9, 0xcb, 0xee, 0xbf, 0x80, 0x72, 0xfb, 0xb0, 0xd6, 0xc3, 0x97, 0xfe, 0xce, 0xa4, 0x87, 0x30, 0x1c, 0x39, 0xcb, 0xc0, @@ -1775,346 +1775,346 @@ 0xfc, 0x1f, 0x01, 0xe5, 0xb3, 0x97, 0xc8, 0xd7, 0x13, 0x9c, 0xbd, 0xe7, 0x61, 0xcb, 0xf0, 0x3c, 0x9d, 0x83, 0x97, 0xfe, 0xec, 0x75, 0x15, 0xf6, 0xdf, 0xf3, 0x97, 0xfc, 0xf2, 0xd8, 0x3d, 0x1e, 0xd9, 0xcb, 0xf8, 0x7d, - 0xa8, 0x75, 0x9c, 0xb9, 0xf6, 0x72, 0xff, 0xfc, 0xef, 0x27, 0xef, 0x2c, + 0xa8, 0x75, 0x9c, 0xb9, 0xf6, 0x72, 0xff, 0xfc, 0xef, 0x27, 0xef, 0xcc, 0x9c, 0x1e, 0x4e, 0xc1, 0xca, 0x9c, 0xfb, 0x26, 0x16, 0xbc, 0xee, 0xb3, - 0x44, 0x66, 0xbf, 0xff, 0xfb, 0x3d, 0xbf, 0x79, 0x3b, 0xf4, 0xb6, 0x20, + 0x44, 0x66, 0xbf, 0xff, 0xfb, 0x3d, 0xbf, 0x79, 0x3b, 0xcc, 0xb6, 0x20, 0xc5, 0x55, 0x47, 0x91, 0xca, 0x5a, 0x27, 0x34, 0x51, 0x7f, 0x24, 0x32, - 0x7c, 0x6c, 0xe5, 0xc3, 0x23, 0x96, 0x61, 0xcb, 0xf2, 0x6b, 0xaf, 0xcf, + 0x7c, 0x6c, 0xe5, 0xc3, 0x23, 0x96, 0x61, 0xcb, 0xf2, 0x6b, 0xaf, 0xf7, 0x47, 0xaa, 0xc2, 0xe5, 0x05, 0xaf, 0xe7, 0x92, 0x69, 0xf4, 0x72, 0xff, - 0xed, 0xa0, 0x37, 0x82, 0x09, 0x66, 0xce, 0x5e, 0xdc, 0x7c, 0x72, 0xa7, + 0xed, 0xa0, 0x37, 0x82, 0x09, 0x66, 0xce, 0x5e, 0xdc, 0x72, 0x72, 0xa7, 0x56, 0x95, 0x22, 0x70, 0xa0, 0x61, 0xca, 0x42, 0x63, 0x50, 0xc0, 0x63, 0xc0, 0xa7, 0x6c, 0xb3, 0xc8, 0x77, 0xfd, 0xa7, 0x6f, 0xa9, 0x1a, 0x83, - 0x97, 0xfd, 0x2d, 0xe4, 0x72, 0x8d, 0xb0, 0xe5, 0xf7, 0xdd, 0x8d, 0x9c, + 0x97, 0xfd, 0x2d, 0xe4, 0x7c, 0x8d, 0xb0, 0xe5, 0xf7, 0x3d, 0x8d, 0x9c, 0xbd, 0x1e, 0xd9, 0xcb, 0xff, 0x62, 0xbb, 0x8c, 0x10, 0xf6, 0x0e, 0x56, 0xcf, 0x64, 0x03, 0x95, 0x88, 0x9e, 0xdb, 0xe5, 0xff, 0xde, 0x4d, 0x3f, - 0xfc, 0xbe, 0x94, 0x30, 0xe5, 0xf8, 0x62, 0x5b, 0x73, 0x94, 0x87, 0xdd, - 0xc5, 0x22, 0xdd, 0x39, 0x7f, 0xff, 0xf7, 0x91, 0x9a, 0x4c, 0xf8, 0x41, - 0xe8, 0xef, 0x2e, 0x29, 0xe9, 0xa0, 0xe5, 0xb3, 0x11, 0x0f, 0xe1, 0x1b, + 0xff, 0x39, 0x94, 0x30, 0xe5, 0xf8, 0x62, 0x5b, 0x73, 0x94, 0x87, 0xdd, + 0xc5, 0x22, 0xdd, 0x39, 0x7f, 0xff, 0xf7, 0x91, 0x9a, 0x4c, 0xe4, 0x41, + 0xe8, 0xef, 0xce, 0x29, 0xe9, 0xa0, 0xe5, 0xb3, 0x11, 0x0f, 0xe1, 0x1b, 0xfc, 0xf2, 0xde, 0xdc, 0x64, 0x72, 0xf2, 0xdc, 0x27, 0x2f, 0xfd, 0xe7, - 0x1f, 0xf9, 0x29, 0x9f, 0x36, 0x72, 0xfb, 0xde, 0x86, 0x1c, 0xac, 0x3e, + 0x1f, 0xfe, 0x29, 0x9c, 0xb6, 0x72, 0xfb, 0xde, 0x86, 0x1c, 0xac, 0x3e, 0x65, 0x51, 0x2f, 0xff, 0x7a, 0x16, 0x9e, 0x46, 0x4d, 0xb4, 0x13, 0x97, 0xf9, 0x99, 0xaf, 0xc4, 0x1f, 0x9c, 0xb4, 0x8e, 0x52, 0x22, 0x3d, 0xd2, 0x54, 0x35, 0xbf, 0x7f, 0x1e, 0x80, 0x9c, 0xa8, 0x4e, 0x29, 0x21, 0x04, - 0xf0, 0xb1, 0x01, 0x7d, 0xff, 0xf0, 0x3d, 0xbf, 0xa5, 0x03, 0xfe, 0xf9, + 0xf0, 0xb1, 0x01, 0x7d, 0xff, 0xf0, 0x3d, 0xbe, 0x65, 0x03, 0xfe, 0xfe, 0x00, 0x4e, 0x5e, 0x8f, 0x41, 0xca, 0x09, 0xf7, 0xf1, 0x54, 0xbd, 0xdc, 0x13, 0x94, 0x86, 0xfc, 0x04, 0x97, 0x76, 0x63, 0x97, 0xd9, 0x36, 0x4c, - 0x72, 0xfb, 0x34, 0x18, 0x39, 0x77, 0xdb, 0xe4, 0x78, 0x82, 0x47, 0x48, + 0x72, 0xfb, 0x34, 0x18, 0x39, 0x77, 0x3b, 0xf8, 0x78, 0x82, 0x47, 0x48, 0x88, 0xc7, 0x5c, 0xbf, 0xef, 0x6f, 0x35, 0xf8, 0x83, 0xf3, 0x97, 0xff, 0xb5, 0x1e, 0xdf, 0x61, 0x3d, 0xb8, 0x9c, 0xe5, 0xf7, 0x9f, 0xb0, 0x72, 0xfb, 0xdd, 0x03, 0x43, 0x97, 0xfb, 0x23, 0x4f, 0x24, 0xe9, 0xcb, 0xfc, 0x8d, 0xee, 0x3a, 0xed, 0x67, 0x2b, 0x47, 0xcf, 0xe3, 0x1a, 0x0a, 0x63, - 0x3f, 0x25, 0x21, 0x0b, 0x21, 0x19, 0x7f, 0xf9, 0x3a, 0x06, 0xb0, 0xf4, - 0x1b, 0xfa, 0x4e, 0x72, 0xa1, 0x3e, 0x6c, 0x8d, 0x51, 0xd0, 0xef, 0x29, + 0x3c, 0xa5, 0x21, 0x0b, 0x21, 0x19, 0x7f, 0xf9, 0x3a, 0x06, 0xb0, 0xf4, + 0x1b, 0xe6, 0x4e, 0x72, 0xa1, 0x3e, 0x6c, 0x8d, 0x51, 0xd0, 0xef, 0x29, 0x9c, 0x31, 0xcb, 0xff, 0xc0, 0xfd, 0x88, 0x39, 0xf8, 0xe3, 0xcc, 0x72, - 0xff, 0x27, 0x52, 0x06, 0x60, 0x1c, 0xbf, 0xc9, 0xac, 0xc1, 0xfb, 0xc7, + 0xff, 0x27, 0x52, 0x06, 0x60, 0x1c, 0xbf, 0xc9, 0xac, 0xc1, 0xe7, 0xc7, 0x2a, 0x0f, 0x91, 0xcc, 0xaf, 0xfc, 0x00, 0xeb, 0x01, 0xd8, 0x66, 0x1c, - 0xac, 0x4c, 0xbb, 0x44, 0x5d, 0x85, 0x76, 0xc8, 0x2f, 0xff, 0xbe, 0x92, + 0xac, 0x4c, 0xbb, 0x44, 0x5d, 0x85, 0x76, 0xc8, 0x2f, 0xff, 0xb9, 0x92, 0x68, 0x3d, 0x06, 0xb1, 0x7d, 0xc3, 0x97, 0x23, 0x67, 0x2e, 0xe0, 0xc3, 0x95, 0xb3, 0x61, 0xe1, 0x7b, 0xfb, 0x71, 0xed, 0xf5, 0x0e, 0x5f, 0x87, 0x19, 0xac, 0x39, 0x7d, 0xae, 0x38, 0x13, 0x95, 0x87, 0xee, 0xc2, 0xd0, - 0x13, 0x5e, 0x0e, 0x78, 0xe5, 0xfe, 0xc1, 0xe5, 0xd8, 0xc6, 0xb3, 0x97, - 0xfe, 0x4f, 0x6f, 0x03, 0x30, 0xc0, 0x4e, 0x5f, 0x7e, 0x9f, 0x48, 0xe5, + 0x13, 0x5e, 0x0e, 0x78, 0xe5, 0xfe, 0xc1, 0xf9, 0xd8, 0xc6, 0xb3, 0x97, + 0xfe, 0x4f, 0x6f, 0x03, 0x30, 0xc0, 0x4e, 0x5f, 0x7e, 0x9c, 0xc8, 0xe5, 0xfe, 0x81, 0xf2, 0x4e, 0x30, 0x72, 0xff, 0xf2, 0x69, 0x27, 0x81, 0xce, 0xe8, 0x1c, 0x4e, 0x50, 0x53, 0x30, 0x60, 0xe7, 0x4d, 0xbf, 0x3e, 0x12, 0x4f, 0x18, 0xdf, 0xfe, 0x81, 0x5b, 0xf9, 0xd5, 0x52, 0x78, 0x9c, 0xe5, - 0xff, 0x90, 0x20, 0xf6, 0xdf, 0xce, 0xa9, 0xcb, 0xfc, 0x98, 0xdf, 0xd2, - 0xdf, 0x25, 0x51, 0x16, 0xe9, 0x94, 0xd5, 0xb6, 0x56, 0xf1, 0x0f, 0xc9, - 0xd3, 0x64, 0x5c, 0x12, 0x5c, 0x96, 0xcc, 0xac, 0x25, 0x7e, 0x38, 0x48, + 0xff, 0x90, 0x20, 0xf6, 0xdf, 0xce, 0xa9, 0xcb, 0xfc, 0x98, 0xdf, 0x32, + 0xdf, 0xc5, 0x51, 0x16, 0xe9, 0x94, 0xd5, 0xb6, 0x56, 0xf1, 0x0f, 0xc9, + 0xd3, 0x64, 0x5c, 0x12, 0x5c, 0x96, 0xcc, 0xac, 0x25, 0x79, 0x38, 0x48, 0x6c, 0x4d, 0x09, 0x0d, 0x42, 0xa9, 0x84, 0xfd, 0x8e, 0xf1, 0xe1, 0xe7, 0xfc, 0x2b, 0x06, 0x50, 0x3e, 0xe3, 0x62, 0xf2, 0x17, 0x18, 0x40, 0xb4, 0x84, 0xc2, 0x91, 0xaf, 0x70, 0x43, 0x8e, 0xfe, 0x64, 0xa2, 0x36, 0x87, - 0x2e, 0x7f, 0xce, 0x54, 0x1e, 0x1b, 0x96, 0x5f, 0x9c, 0x2e, 0xff, 0x1c, - 0xbb, 0xdc, 0xfa, 0x78, 0xee, 0x41, 0x7f, 0xff, 0xf0, 0x3e, 0x97, 0x37, - 0x1f, 0x63, 0x36, 0x1e, 0xc6, 0x82, 0xee, 0xd9, 0xca, 0xe6, 0xaa, 0xe7, - 0x25, 0x0a, 0x89, 0x7d, 0xff, 0xee, 0x6c, 0x79, 0x73, 0xcd, 0x2d, 0xdd, - 0x66, 0x89, 0xa5, 0x7f, 0xfb, 0x9b, 0x1e, 0x5c, 0xf3, 0x4b, 0x77, 0x59, - 0xa2, 0x71, 0x5f, 0xa5, 0x9e, 0x94, 0x8e, 0x5f, 0xee, 0x31, 0xde, 0x43, - 0x12, 0x39, 0x7f, 0xe7, 0x97, 0x3c, 0xd2, 0xdd, 0xd6, 0x68, 0xa0, 0x57, - 0xff, 0x92, 0x18, 0xe1, 0xd4, 0x7b, 0xb8, 0x13, 0x97, 0xdb, 0x1f, 0xa4, - 0x72, 0xdc, 0xfe, 0x4c, 0x55, 0x0a, 0x18, 0x6d, 0xd4, 0xcf, 0x24, 0x5f, + 0x2e, 0x7f, 0xce, 0x54, 0x1e, 0x1b, 0x96, 0x5f, 0x9c, 0x2e, 0xfc, 0x9c, + 0xbb, 0xdf, 0x7a, 0x78, 0xee, 0x41, 0x7f, 0xff, 0xf0, 0x39, 0x97, 0xd7, + 0x1f, 0x63, 0x36, 0x1e, 0xc6, 0x82, 0xee, 0xd9, 0xca, 0xfa, 0xaa, 0xe7, + 0x25, 0x0a, 0x89, 0x7d, 0xff, 0xef, 0xac, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, + 0x66, 0x89, 0xa5, 0x7f, 0xfb, 0xeb, 0x1e, 0x5f, 0x73, 0x4b, 0x77, 0x59, + 0xa2, 0x71, 0x5f, 0xa5, 0x9e, 0x94, 0x8e, 0x5f, 0xee, 0x31, 0xdf, 0x83, + 0x12, 0x39, 0x7f, 0xe7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0xa0, 0x57, + 0xff, 0x92, 0x18, 0xe1, 0xd4, 0x7b, 0xb8, 0x13, 0x97, 0xdb, 0x1e, 0x64, + 0x72, 0xdf, 0x79, 0x4c, 0x55, 0x0a, 0x18, 0x6d, 0xd4, 0xcf, 0x24, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x2e, 0x05, 0xfc, 0x39, 0xe5, 0xa6, 0xce, 0x5d, 0x08, 0x72, 0xfb, 0xa0, 0x79, 0x1c, 0xbf, 0xc3, 0x28, 0x40, 0xe3, 0x0e, - 0x56, 0x23, 0x21, 0x86, 0x9d, 0x2c, 0xf0, 0xa8, 0x08, 0xaf, 0xd2, 0xe6, - 0xaf, 0x08, 0xa9, 0xca, 0xe6, 0x7f, 0x70, 0x93, 0x73, 0xfe, 0x72, 0xfd, + 0x56, 0x23, 0x21, 0x86, 0x9d, 0x2c, 0xf0, 0xa8, 0x08, 0xaf, 0xd2, 0xfa, + 0xaf, 0x08, 0xa9, 0xca, 0xfa, 0x7f, 0x70, 0x93, 0x73, 0xfe, 0x72, 0xfd, 0x34, 0xa0, 0x64, 0x72, 0x8e, 0x56, 0x1b, 0x31, 0x28, 0xbe, 0x8f, 0xf1, - 0xb3, 0x97, 0x27, 0x3d, 0x22, 0x30, 0x52, 0x94, 0x1f, 0xbf, 0xe9, 0x73, - 0xcd, 0x2d, 0xdd, 0x66, 0x89, 0x25, 0x6e, 0x7d, 0x44, 0x23, 0x9e, 0xdc, + 0xb3, 0x97, 0x27, 0xdd, 0x22, 0x30, 0x52, 0x94, 0x1f, 0xbf, 0xe9, 0x7d, + 0xcd, 0x2d, 0xdd, 0x66, 0x89, 0x25, 0x6f, 0xbd, 0x44, 0x23, 0x9e, 0xdc, 0xdf, 0xe7, 0x2f, 0xf3, 0xf8, 0x72, 0x77, 0x13, 0x97, 0x2a, 0xd9, 0xcb, - 0xfa, 0x4f, 0xa9, 0xc3, 0x07, 0x2f, 0xec, 0x17, 0xfa, 0x5b, 0x39, 0x7f, + 0xfa, 0x4f, 0xa9, 0xc3, 0x07, 0x2f, 0xec, 0x17, 0xe6, 0x5b, 0x39, 0x7f, 0xfe, 0x00, 0xba, 0xbe, 0x56, 0x06, 0x59, 0xd4, 0x61, 0xcb, 0xfa, 0x19, - 0xac, 0x0f, 0x8e, 0x5f, 0xb8, 0x3b, 0x02, 0xa9, 0xcb, 0x9f, 0x98, 0x53, - 0x6b, 0x54, 0x67, 0xe3, 0x19, 0x86, 0x74, 0x5c, 0xc2, 0xdd, 0xaa, 0xf8, + 0xac, 0x0f, 0x8e, 0x5f, 0xb8, 0x3b, 0x02, 0xa9, 0xcb, 0x9f, 0xe8, 0x53, + 0x6b, 0x54, 0x67, 0x93, 0x19, 0x86, 0x74, 0x5c, 0xc2, 0xdd, 0xaa, 0xf8, 0xb6, 0xa7, 0x6f, 0x34, 0xe5, 0x5a, 0xf8, 0xac, 0xe6, 0x65, 0xaf, 0xe3, - 0x6f, 0xdc, 0x72, 0xde, 0x8c, 0xcf, 0x8c, 0x72, 0xb7, 0xfe, 0x55, 0xf9, - 0xe6, 0x96, 0xee, 0xb3, 0x45, 0xa8, 0xbf, 0xf3, 0xcb, 0x9e, 0x69, 0x6e, - 0xeb, 0x34, 0x4a, 0xab, 0x91, 0xb3, 0x94, 0x72, 0xdc, 0xd5, 0x45, 0xdb, + 0x6f, 0xdc, 0x72, 0xde, 0x8c, 0xcf, 0x8c, 0x72, 0xb7, 0xfe, 0x55, 0xfe, + 0xe6, 0x96, 0xee, 0xb3, 0x45, 0xa8, 0xbf, 0xf3, 0xcb, 0xee, 0x69, 0x6e, + 0xeb, 0x34, 0x4a, 0xab, 0x91, 0xb3, 0x94, 0x72, 0xdf, 0x55, 0x45, 0xdb, 0x13, 0x7c, 0x99, 0xc0, 0x2f, 0x7f, 0x66, 0x96, 0xee, 0xb3, 0x44, 0x52, 0xbf, 0xf3, 0xbb, 0x33, 0x5f, 0x88, 0x3f, 0x39, 0x7f, 0xe8, 0xf6, 0xf3, 0x5f, 0x88, 0x3f, 0x39, 0x7c, 0x9b, 0x87, 0x39, 0x7f, 0x85, 0xff, 0xdf, - 0xb1, 0x67, 0x2e, 0x67, 0x3e, 0xa3, 0x48, 0x4f, 0xf6, 0x81, 0xe2, 0x0a, - 0xe6, 0x9a, 0xab, 0xc6, 0x17, 0x7f, 0xb9, 0xe6, 0x96, 0xee, 0xb3, 0x44, + 0xb1, 0x67, 0x2e, 0x67, 0xde, 0xa3, 0x48, 0x4f, 0xf6, 0x81, 0xe2, 0x0a, + 0xfa, 0x9a, 0xab, 0xc6, 0x17, 0x7f, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0x68, 0xb8, 0x1d, 0x39, 0x7f, 0xe0, 0xe3, 0x13, 0x59, 0xb9, 0xa0, 0xe5, 0xff, 0xff, 0x38, 0x37, 0xdc, 0x0a, 0x8a, 0x6d, 0x14, 0xf2, 0x6e, 0x65, 0x0e, 0x5f, 0xfe, 0x99, 0x13, 0xb3, 0x67, 0xa3, 0xd0, 0x13, 0x97, 0x91, 0xdb, 0x29, 0x48, 0x98, 0x83, 0x59, 0xf4, 0xcd, 0x8c, 0x4a, 0xbe, 0x5b, 0xba, 0xcd, 0x14, 0xfa, 0xef, 0x41, 0xca, 0xd1, 0xe2, 0x78, 0xba, 0xff, - 0x27, 0x93, 0xdd, 0x07, 0x8e, 0x5f, 0xf4, 0xd1, 0xee, 0xbc, 0xdc, 0xb0, + 0x27, 0x93, 0xdd, 0x07, 0x8e, 0x5f, 0xf4, 0xd1, 0xee, 0xbc, 0xdf, 0x30, 0xe5, 0x68, 0xfb, 0xfc, 0x67, 0x78, 0x1d, 0x01, 0xcb, 0xff, 0xc8, 0xc1, 0x07, 0x53, 0x59, 0xb9, 0xa0, 0xe5, 0xff, 0xc0, 0xf6, 0x81, 0x36, 0xd6, 0xf3, 0x6c, 0xe5, 0xff, 0xd9, 0x30, 0x06, 0x7d, 0xad, 0xe6, 0xd9, 0xcb, - 0xe0, 0x75, 0x34, 0x72, 0xdc, 0xda, 0xb5, 0x6e, 0xd1, 0x19, 0x3e, 0x42, + 0xe0, 0x75, 0x34, 0x72, 0xdf, 0x5a, 0xb5, 0x6e, 0xd1, 0x19, 0x3e, 0x42, 0x15, 0x21, 0x23, 0xd2, 0x27, 0x1d, 0x14, 0x9f, 0x24, 0x34, 0x47, 0xbf, - 0xfd, 0xcd, 0x8f, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x35, 0x2f, 0xec, - 0xd2, 0xdd, 0xd6, 0x68, 0xae, 0xd7, 0xff, 0xb3, 0x81, 0x3c, 0x92, 0xe4, - 0x31, 0xed, 0x9c, 0xa3, 0x97, 0x37, 0xcf, 0xa7, 0xb0, 0xda, 0x6d, 0x73, + 0xfd, 0xf5, 0x8f, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x35, 0x2f, 0xec, + 0xd2, 0xdd, 0xd6, 0x68, 0xae, 0xd7, 0xff, 0xb3, 0x81, 0x3c, 0x92, 0xf8, + 0x31, 0xed, 0x9c, 0xa3, 0x97, 0x37, 0xf7, 0xa7, 0xb0, 0xda, 0x6d, 0x7d, 0x46, 0x1a, 0x42, 0x46, 0xef, 0xd0, 0xe5, 0xed, 0xc3, 0x0e, 0x5c, 0xc1, 0x39, 0x7c, 0xb7, 0x75, 0x9a, 0x2b, 0xe5, 0xe6, 0xdb, 0x6c, 0xa5, 0x84, - 0xa7, 0x33, 0x41, 0x5a, 0x3f, 0x06, 0x27, 0x5e, 0x94, 0x7c, 0x72, 0xf4, + 0xa7, 0xd3, 0x41, 0x5a, 0x3f, 0x06, 0x27, 0x5e, 0x94, 0x72, 0x72, 0xf4, 0xd9, 0xd3, 0x97, 0xfe, 0xce, 0xb6, 0xfe, 0xdc, 0x64, 0xe7, 0x2d, 0xe3, 0x97, 0xfc, 0x9a, 0xc9, 0xd2, 0x58, 0x13, 0x95, 0xa3, 0xc9, 0x71, 0x1b, - 0xf7, 0xdc, 0x1d, 0x02, 0x87, 0x2d, 0xa3, 0x94, 0x72, 0x90, 0xbc, 0xd0, - 0x8d, 0xd3, 0xaa, 0x72, 0xba, 0x6e, 0x1c, 0x7e, 0xdc, 0xda, 0x8a, 0xa6, + 0xf7, 0x3c, 0x1d, 0x02, 0x87, 0x2d, 0xa3, 0x94, 0x72, 0x90, 0xbc, 0xd0, + 0x8d, 0xd3, 0xaa, 0x72, 0xba, 0x6e, 0x1c, 0x7e, 0xdf, 0x5a, 0x8a, 0xa6, 0x08, 0x17, 0x9c, 0x73, 0x21, 0x0d, 0x31, 0x13, 0x8e, 0x88, 0xee, 0xe1, - 0x10, 0x02, 0x16, 0x90, 0x82, 0xbf, 0xfd, 0xcd, 0x8f, 0x2e, 0x79, 0xa5, - 0xbb, 0xac, 0xd1, 0x3d, 0xaf, 0xa3, 0x81, 0xfe, 0x39, 0x79, 0x07, 0xf3, + 0x10, 0x02, 0x16, 0x90, 0x82, 0xbf, 0xfd, 0xf5, 0x8f, 0x2f, 0xb9, 0xa5, + 0xbb, 0xac, 0xd1, 0x3d, 0xaf, 0xa3, 0x81, 0xf9, 0x39, 0x79, 0x07, 0xf3, 0x95, 0xd3, 0xc1, 0xe2, 0x4b, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0xb8, 0x56, - 0xe7, 0x07, 0xb1, 0x84, 0x97, 0xff, 0x73, 0x79, 0x73, 0xcd, 0x2d, 0xdd, + 0xfb, 0x07, 0xb1, 0x84, 0x97, 0xff, 0x7d, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x89, 0x3d, 0x50, 0xcb, 0xd9, 0x9e, 0x39, 0xe9, 0x15, 0xab, 0x2e, 0xdd, 0x70, 0x9a, 0x9a, 0x31, 0xdd, 0x4a, 0x89, 0xec, 0x2a, 0xb7, 0x0f, - 0x3e, 0x25, 0x17, 0xfb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x45, 0x4b, 0xf6, - 0x96, 0xee, 0xb3, 0x45, 0x32, 0xbf, 0x93, 0xb8, 0xff, 0x7e, 0x72, 0xdc, - 0xf0, 0xf8, 0x9a, 0x1a, 0x5f, 0xfe, 0xe6, 0xc7, 0x97, 0x3c, 0xd2, 0xdd, - 0xd6, 0x68, 0x99, 0xd7, 0xff, 0xb9, 0xb1, 0xe5, 0xcf, 0x34, 0xb7, 0x75, + 0x3e, 0x25, 0x17, 0xfb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x45, 0x4b, 0xf6, + 0x96, 0xee, 0xb3, 0x45, 0x32, 0xbf, 0x93, 0xb8, 0xfc, 0xfe, 0x72, 0xdf, + 0x70, 0xf8, 0x9a, 0x1a, 0x5f, 0xfe, 0xfa, 0xc7, 0x97, 0xdc, 0xd2, 0xdd, + 0xd6, 0x68, 0x99, 0xd7, 0xff, 0xbe, 0xb1, 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x28, 0xd5, 0x4e, 0x9c, 0x10, 0x61, 0x46, 0xa9, 0x5f, 0x96, 0xaf, - 0xfc, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x11, 0xd2, 0xff, 0xed, 0x4f, - 0xcf, 0x63, 0x9e, 0xdc, 0x30, 0xe5, 0xff, 0xfe, 0xd4, 0xb9, 0xe0, 0x83, - 0xc0, 0x57, 0xdf, 0x2d, 0x35, 0xb3, 0x95, 0xcd, 0x1f, 0x30, 0x98, 0x88, + 0xfc, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x11, 0xd2, 0xff, 0xed, 0x4f, + 0xf7, 0x63, 0x9e, 0xdc, 0x30, 0xe5, 0xff, 0xfe, 0xd4, 0xbe, 0xe0, 0x83, + 0xc0, 0x57, 0xdc, 0xad, 0x35, 0xb3, 0x95, 0xf5, 0x1f, 0x30, 0x98, 0x88, 0xf7, 0x03, 0xa7, 0x2f, 0x96, 0xb0, 0x2c, 0xe5, 0xfb, 0x04, 0x39, 0x39, 0xcb, 0xfd, 0x10, 0xbc, 0xd6, 0xb0, 0xe5, 0x21, 0xec, 0x09, 0x3d, 0xfb, 0x34, 0xb0, 0x2a, 0x72, 0xff, 0xc3, 0x8a, 0xbc, 0xdb, 0xec, 0x04, 0xe5, - 0xe9, 0x9f, 0xc7, 0x2f, 0x96, 0xee, 0xb3, 0x45, 0x34, 0xbf, 0x67, 0xcd, - 0xbf, 0x4e, 0x5f, 0xfd, 0xbc, 0x10, 0xc7, 0x26, 0xa3, 0xc7, 0xf4, 0x39, + 0xe9, 0x9f, 0xc7, 0x2f, 0x96, 0xee, 0xb3, 0x45, 0x34, 0xbf, 0x67, 0x2d, + 0xbf, 0x4e, 0x5f, 0xfd, 0xbc, 0x10, 0xc7, 0xc6, 0xa3, 0xc7, 0xf4, 0x39, 0x41, 0x4c, 0xa9, 0x0a, 0x66, 0x3f, 0xd0, 0xe8, 0x97, 0x6c, 0xa6, 0xff, 0xff, 0xb0, 0x7d, 0xb4, 0x5e, 0x0e, 0xd7, 0xd4, 0xea, 0xd4, 0x9c, 0xe5, - 0xff, 0x6d, 0xfe, 0xc9, 0xa3, 0xbb, 0x39, 0x77, 0x50, 0x51, 0x43, 0xe6, + 0xff, 0x6d, 0xf9, 0xc9, 0xa3, 0xbb, 0x39, 0x77, 0x50, 0x51, 0x43, 0xe6, 0x7b, 0xff, 0xa5, 0xd4, 0x19, 0xf6, 0x08, 0xd4, 0xc7, 0x2f, 0x49, 0x92, 0x39, 0x7b, 0xff, 0x21, 0xcb, 0xfd, 0xb5, 0xa6, 0xb4, 0x93, 0x9c, 0xa7, 0x3d, 0x1d, 0x8e, 0xdf, 0xff, 0xf6, 0x4f, 0x38, 0x35, 0x36, 0xe7, 0x89, - 0xb7, 0xdc, 0x0a, 0x71, 0x39, 0x7f, 0x80, 0xe2, 0xbe, 0x53, 0xec, 0xe5, + 0xb7, 0xdc, 0x0a, 0x71, 0x39, 0x7f, 0x80, 0xe2, 0xbf, 0x93, 0xec, 0xe5, 0xfd, 0x03, 0xe6, 0x99, 0xe3, 0x97, 0xf9, 0xff, 0x7f, 0x7b, 0x3a, 0x72, 0xa4, 0x7c, 0x2d, 0x97, 0x5d, 0xd0, 0x1c, 0xac, 0x37, 0x5f, 0x91, 0xdf, 0xee, 0xc2, 0x7e, 0xfe, 0x01, 0xcb, 0xff, 0x08, 0x3d, 0xdc, 0x9a, 0x51, - 0xf1, 0xcb, 0x4c, 0x72, 0xfd, 0x9d, 0x71, 0x09, 0xca, 0x9c, 0xdc, 0x7e, + 0xc9, 0xcb, 0x4c, 0x72, 0xfd, 0x9d, 0x71, 0x09, 0xca, 0x9c, 0xdc, 0x7e, 0x25, 0x74, 0x2a, 0x72, 0xfe, 0x7f, 0xf7, 0xc2, 0xb8, 0x57, 0x0a, 0x39, 0x7f, 0x24, 0x32, 0x7c, 0x6c, 0xe5, 0xff, 0xf6, 0x7b, 0xb9, 0x2d, 0x38, - 0xfb, 0xaf, 0x23, 0x97, 0x47, 0xe7, 0x2f, 0xf3, 0xfd, 0x0b, 0x45, 0xf3, + 0xfb, 0xaf, 0x23, 0x97, 0x47, 0xe7, 0x2f, 0xf3, 0xf3, 0x0b, 0x45, 0xfd, 0xd2, 0x24, 0xc4, 0xb9, 0x44, 0xea, 0xc4, 0xf8, 0x11, 0xe3, 0xa4, 0x62, 0x2f, 0xb8, 0x6a, 0x5f, 0xbf, 0xec, 0x4b, 0x67, 0x2f, 0x36, 0xf3, 0x9c, 0xbf, 0xe8, 0xfd, 0xfd, 0xfa, 0x83, 0x23, 0x95, 0xd3, 0xd9, 0x11, 0xea, - 0x84, 0x51, 0xfa, 0x10, 0x56, 0xe6, 0xd5, 0xb2, 0x18, 0x20, 0x5c, 0x2f, - 0x79, 0x1a, 0x52, 0xe1, 0xf1, 0xf1, 0x6a, 0x23, 0x69, 0xbb, 0xa4, 0x3f, + 0x84, 0x51, 0xfa, 0x10, 0x56, 0xfa, 0xd5, 0xb2, 0x18, 0x20, 0x5c, 0x2f, + 0x79, 0x1a, 0x52, 0xe1, 0xf1, 0xc9, 0x6a, 0x23, 0x69, 0xbb, 0xa4, 0x3f, 0xb7, 0x0c, 0x34, 0x76, 0x43, 0xe9, 0x42, 0x6a, 0x43, 0xc2, 0xfd, 0xa5, - 0xbb, 0xac, 0xd1, 0x55, 0x2f, 0xfc, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, - 0x13, 0x6a, 0xdc, 0xf1, 0x10, 0x0c, 0x34, 0xbf, 0xdc, 0xf3, 0x4b, 0x77, + 0xbb, 0xac, 0xd1, 0x55, 0x2f, 0xfc, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, + 0x13, 0x6a, 0xdf, 0x71, 0x10, 0x0c, 0x34, 0xbf, 0xdf, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0xbf, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x2c, 0x65, 0xdc, 0x12, - 0x39, 0x6e, 0x78, 0x79, 0xd3, 0x1a, 0x5f, 0xb6, 0xbe, 0xc2, 0xa7, 0x2f, + 0x39, 0x6f, 0xb8, 0x79, 0xd3, 0x1a, 0x5f, 0xb6, 0xbe, 0xc2, 0xa7, 0x2f, 0xf0, 0x82, 0x59, 0xb7, 0xf1, 0xcb, 0xf9, 0xaa, 0x0b, 0x56, 0xd5, 0x8a, 0xa7, 0x2f, 0xf8, 0x41, 0x3c, 0xd2, 0x8d, 0x4e, 0x72, 0xed, 0x78, 0xe5, 0xf3, 0xcb, 0x02, 0x72, 0xfe, 0xf6, 0x68, 0x38, 0x27, 0x2d, 0x81, 0x3c, 0xdf, 0x10, 0xde, 0x56, 0x58, 0x72, 0xfe, 0xcd, 0x7b, 0xb9, 0x39, 0xcb, - 0x73, 0xc4, 0xe0, 0x98, 0x65, 0xd3, 0xe7, 0x3c, 0x16, 0x4d, 0x93, 0xa8, - 0x3b, 0x64, 0xe6, 0xa8, 0x5b, 0x51, 0xd5, 0xdf, 0xb4, 0xb7, 0x75, 0x9a, - 0x2d, 0x55, 0xff, 0x9e, 0x5c, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0x82, 0x5f, - 0xa1, 0xb6, 0x99, 0xa3, 0x96, 0xe7, 0x88, 0xaa, 0x61, 0xa2, 0x89, 0x97, - 0xfe, 0x76, 0xfd, 0x9d, 0xe6, 0xfa, 0xf1, 0xcb, 0xfd, 0x03, 0xfc, 0x35, + 0x7d, 0xc4, 0xe0, 0x98, 0x65, 0xd3, 0xe7, 0x3c, 0x16, 0x4d, 0x93, 0xa8, + 0x3b, 0x64, 0xfa, 0xa8, 0x5b, 0x51, 0xd5, 0xdf, 0xb4, 0xb7, 0x75, 0x9a, + 0x2d, 0x55, 0xff, 0x9e, 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x82, 0x5f, + 0xa1, 0xb6, 0x99, 0xa3, 0x96, 0xfb, 0x88, 0xaa, 0x61, 0xa2, 0x89, 0x97, + 0xfe, 0x76, 0xfd, 0x9d, 0xfa, 0xfa, 0xf1, 0xcb, 0xfd, 0x03, 0xfc, 0x35, 0xbb, 0x0e, 0x5f, 0xfe, 0x9a, 0x38, 0xbe, 0xb7, 0xb4, 0xd6, 0x2a, 0x72, 0xff, 0xa1, 0x26, 0x8e, 0x2f, 0xad, 0x9c, 0xbb, 0x50, 0x72, 0xa4, 0x8d, 0x24, 0x35, 0xea, 0x6f, 0x01, 0xd5, 0xf2, 0xdd, 0xd6, 0x68, 0xb8, 0x97, - 0xf0, 0x1f, 0xe0, 0xe6, 0x8e, 0x56, 0x8f, 0x73, 0x65, 0xd7, 0xec, 0x62, + 0xf0, 0x1f, 0x90, 0xe6, 0x8e, 0x56, 0x8f, 0x73, 0x65, 0xd7, 0xec, 0x62, 0x70, 0x04, 0xe5, 0xd0, 0xc3, 0x94, 0xd6, 0x78, 0x1a, 0x2a, 0xbe, 0x7e, 0x04, 0x9c, 0xe5, 0xfb, 0xa0, 0x57, 0x04, 0xe5, 0xf8, 0x38, 0xd7, 0x1d, 0x39, 0x7b, 0x81, 0x16, 0x72, 0x82, 0x7e, 0x3a, 0x28, 0xe0, 0x2a, 0xbf, 0xcc, 0x79, 0x6d, 0x03, 0x87, 0x2f, 0xa1, 0x58, 0xd9, 0xcb, 0xf0, 0xf8, 0x5d, 0x53, 0x94, 0x72, 0xdb, 0xc3, 0x64, 0xd0, 0x9e, 0xfe, 0x63, 0xf1, - 0x8d, 0x70, 0x1c, 0xbf, 0xf2, 0x07, 0x38, 0xb3, 0x25, 0xf4, 0x8e, 0x54, + 0x8d, 0x70, 0x1c, 0xbf, 0xf2, 0x07, 0x38, 0xb3, 0x25, 0xcc, 0x8e, 0x54, 0x1f, 0x9e, 0x19, 0x5f, 0xd9, 0xa7, 0xf0, 0x20, 0xe5, 0xff, 0xf3, 0x8c, 0x27, 0x06, 0xd3, 0x79, 0xdc, 0x68, 0x72, 0x82, 0x7f, 0xbc, 0x4b, 0x2f, 0xfe, 0x41, 0x04, 0xb3, 0x7b, 0x40, 0xe1, 0xca, 0x98, 0xf9, 0xbc, 0x49, - 0x6e, 0x70, 0xb8, 0x63, 0x90, 0x9b, 0xd3, 0x17, 0x49, 0x5e, 0x12, 0xdf, + 0x6f, 0xb0, 0xb8, 0x63, 0x90, 0x9b, 0xd3, 0x17, 0x49, 0x5e, 0x12, 0xdf, 0x99, 0x09, 0x96, 0xd5, 0x3d, 0x09, 0xb5, 0x23, 0x03, 0xbf, 0xcd, 0x50, 0xb5, 0x7e, 0x68, 0xd5, 0x84, 0xe5, 0xfb, 0x86, 0xe1, 0x7f, 0xd5, 0x83, - 0x97, 0xfe, 0x4f, 0xb8, 0x56, 0xf5, 0xcb, 0x97, 0x5a, 0x1c, 0xbe, 0xec, + 0x97, 0xfe, 0x4e, 0x78, 0x56, 0xf5, 0xf3, 0xe7, 0x5a, 0x1c, 0xbe, 0xec, 0x79, 0x67, 0x29, 0xa8, 0x1f, 0x78, 0x53, 0x6f, 0xff, 0x70, 0xa5, 0x5b, - 0x6b, 0x9c, 0x3c, 0x37, 0x2e, 0x5d, 0x68, 0x72, 0xfd, 0xa5, 0xbb, 0xac, - 0xd1, 0x74, 0xaf, 0xd0, 0x2e, 0x18, 0x39, 0x7f, 0x4a, 0x3e, 0x7d, 0xc8, + 0x6b, 0x9c, 0x3c, 0x37, 0xcf, 0x9d, 0x68, 0x72, 0xfd, 0xa5, 0xbb, 0xac, + 0xd1, 0x74, 0xaf, 0xd0, 0x2e, 0x18, 0x39, 0x7f, 0x4a, 0x39, 0x7d, 0xc8, 0xe5, 0xe8, 0xf7, 0x01, 0xcb, 0xec, 0x0e, 0x04, 0xe5, 0xff, 0x3f, 0x18, - 0xf6, 0xc0, 0xbe, 0x1c, 0xe5, 0xf6, 0xe7, 0x75, 0x0e, 0x5b, 0x9b, 0x52, + 0xf6, 0xc0, 0xbe, 0x1c, 0xe5, 0xf6, 0xe7, 0x75, 0x0e, 0x5b, 0xeb, 0x52, 0xaa, 0x87, 0x85, 0x22, 0xc4, 0x29, 0x64, 0x51, 0x8c, 0x88, 0x69, 0x31, 0x2f, 0x4b, 0x9c, 0x7c, 0x48, 0x7c, 0x81, 0x7f, 0xfd, 0x83, 0xe4, 0x67, 0x61, 0x05, 0xf4, 0xa9, 0xcb, 0xff, 0x33, 0x60, 0xf4, 0x93, 0x8f, 0x50, 0xe5, 0xfd, 0x99, 0xb5, 0xfa, 0x0e, 0x5f, 0xd3, 0xc7, 0x9d, 0x50, 0x1c, - 0xa3, 0x97, 0xff, 0x46, 0xbf, 0xe5, 0xbe, 0xc3, 0x1c, 0x4e, 0x5f, 0xe8, + 0xa3, 0x97, 0xff, 0x46, 0xbf, 0xf9, 0xbe, 0xc3, 0x1c, 0x4e, 0x5f, 0xe8, 0xd2, 0x9d, 0xee, 0x7e, 0x72, 0xa4, 0x7f, 0x7d, 0x46, 0xbf, 0xa4, 0xf2, 0x71, 0x59, 0xcb, 0xff, 0xd9, 0xe8, 0x6d, 0x49, 0xf7, 0x8c, 0x86, 0xb3, - 0x96, 0xe6, 0xd5, 0x26, 0x47, 0x90, 0x86, 0x98, 0x88, 0x4b, 0x2b, 0x49, - 0xd0, 0xb2, 0x35, 0x2b, 0xec, 0x6d, 0xaa, 0x61, 0xcb, 0xf8, 0x63, 0xe6, - 0x3f, 0x8e, 0x5f, 0xfe, 0x6d, 0xc3, 0xd8, 0xfb, 0xd1, 0xd7, 0x6b, 0x39, + 0x96, 0xfa, 0xd5, 0x26, 0x47, 0x90, 0x86, 0x98, 0x88, 0x4b, 0x2b, 0x49, + 0xd0, 0xb2, 0x35, 0x2b, 0xec, 0x6d, 0xaa, 0x61, 0xcb, 0xf8, 0x63, 0x96, + 0x3f, 0x8e, 0x5f, 0xfe, 0x6d, 0xc3, 0xd8, 0xe7, 0xd1, 0xd7, 0x6b, 0x39, 0x64, 0xd1, 0xfd, 0xf4, 0xb6, 0xff, 0xff, 0x81, 0xa9, 0x6f, 0xae, 0x9a, - 0xd6, 0x81, 0xf2, 0x69, 0xf6, 0x72, 0xff, 0xc2, 0xed, 0xfb, 0x3a, 0xf3, + 0xd6, 0x81, 0xca, 0x69, 0xf6, 0x72, 0xff, 0xc2, 0xed, 0xfb, 0x3a, 0xf3, 0x39, 0xcb, 0xff, 0xfb, 0xa2, 0x07, 0x6b, 0xc9, 0x77, 0x15, 0xc0, 0xcc, 0x03, 0x97, 0x2f, 0x0e, 0x54, 0x1f, 0xaa, 0xab, 0xf7, 0xf9, 0xfd, 0xb8, 0xea, 0x93, 0x1c, 0xbd, 0x28, 0x61, 0xcb, 0xca, 0xee, 0x47, 0x2f, 0xf6, 0xb4, 0xf2, 0x9f, 0x1b, 0x39, 0x74, 0xc0, 0x39, 0x69, 0x61, 0xe6, 0xb6, 0x6b, 0x7f, 0xf6, 0x06, 0x25, 0x1a, 0x85, 0x1c, 0x4e, 0x5f, 0xfb, 0x8e, - 0x49, 0x81, 0x4e, 0x30, 0x13, 0x94, 0xc4, 0x42, 0x3a, 0x15, 0xcf, 0xce, + 0x49, 0x81, 0x4e, 0x30, 0x13, 0x94, 0xc4, 0x42, 0x3a, 0x15, 0xcf, 0xf6, 0x75, 0x58, 0xf3, 0x34, 0x6a, 0x16, 0x7d, 0x22, 0x73, 0x5d, 0x8e, 0x79, 0xad, 0x48, 0x56, 0x57, 0x55, 0xbd, 0x0c, 0xae, 0xeb, 0xfd, 0x2c, 0xf7, 0x61, 0x41, 0x39, 0x7f, 0xef, 0x22, 0xd0, 0x2e, 0x2a, 0xc1, 0xcb, 0xfe, - 0x8f, 0xba, 0xfb, 0xf4, 0x36, 0x72, 0xa0, 0xfd, 0xf4, 0x7b, 0x70, 0x3a, + 0x8e, 0x7a, 0xfb, 0xf4, 0x36, 0x72, 0xa0, 0xfd, 0xf4, 0x7b, 0x70, 0x3a, 0x72, 0xfc, 0x39, 0xd7, 0xf1, 0xcb, 0xfa, 0x4f, 0x9c, 0x60, 0x27, 0x2b, 0x84, 0x3d, 0x46, 0xa2, 0x4d, 0x7c, 0x80, 0x94, 0x1c, 0xbe, 0x41, 0x8f, - 0xce, 0x5f, 0x9e, 0x69, 0x27, 0x8e, 0x5f, 0xfa, 0x03, 0xa8, 0x92, 0x7d, + 0xce, 0x5f, 0x9e, 0x69, 0x27, 0x8e, 0x5f, 0xfa, 0x03, 0xa8, 0x92, 0x73, 0xec, 0x39, 0x52, 0x45, 0x42, 0xc8, 0x7f, 0x21, 0xf1, 0x45, 0xff, 0xa3, - 0x5b, 0xea, 0x2d, 0x60, 0x9c, 0xe5, 0xff, 0xff, 0x40, 0x7b, 0x9f, 0x78, + 0x5b, 0xea, 0x2d, 0x60, 0x9c, 0xe5, 0xff, 0xff, 0x40, 0x7b, 0x9c, 0xf8, 0x5f, 0xbf, 0xbe, 0xf6, 0xfa, 0x59, 0xcb, 0xfd, 0x99, 0x8a, 0xaa, 0xf2, 0x39, 0x4a, 0xa2, 0x6b, 0xcc, 0xf7, 0xec, 0xda, 0xfd, 0x07, 0x2f, 0xff, - 0x23, 0x7b, 0x5f, 0x53, 0xef, 0x6b, 0x50, 0x72, 0xff, 0xff, 0x9d, 0xb5, - 0x33, 0x42, 0xff, 0x49, 0x71, 0xed, 0xe7, 0xde, 0x39, 0x58, 0x8d, 0xcd, + 0x23, 0x7b, 0x5f, 0x53, 0x9f, 0x6b, 0x50, 0x72, 0xff, 0xff, 0x9d, 0xb5, + 0x33, 0x42, 0xfc, 0xc9, 0x71, 0xed, 0xe7, 0x3e, 0x39, 0x58, 0x8d, 0xcd, 0x13, 0xba, 0x65, 0xfb, 0x8a, 0x6b, 0x02, 0x72, 0xff, 0xfb, 0x7d, 0x4d, 0xfb, 0xb8, 0x14, 0xde, 0x09, 0xcb, 0xdd, 0x81, 0xc3, 0xf7, 0x01, 0x4d, 0xf9, 0xfb, 0x21, 0x59, 0xcb, 0xfd, 0x0c, 0xc4, 0x64, 0x35, 0x9c, 0xbf, - 0xd2, 0x66, 0xd0, 0x7e, 0x91, 0xca, 0x59, 0xf4, 0x4c, 0x69, 0x7f, 0xfb, - 0x35, 0xa7, 0x96, 0xc7, 0x18, 0xa7, 0xc7, 0x2f, 0x3b, 0xac, 0xd1, 0x26, + 0xd2, 0x66, 0xd0, 0x79, 0x91, 0xca, 0x59, 0xf4, 0x4c, 0x69, 0x7f, 0xfb, + 0x35, 0xa7, 0x96, 0xc7, 0x18, 0xa7, 0x27, 0x2f, 0x3b, 0xac, 0xd1, 0x26, 0x2f, 0x70, 0x26, 0xce, 0x52, 0xcf, 0x1f, 0x80, 0xa2, 0xfc, 0xbe, 0x15, - 0xc3, 0x35, 0x5c, 0x21, 0xcb, 0xff, 0xdf, 0x4b, 0x79, 0xc5, 0xd9, 0x8a, - 0xc6, 0xce, 0x5f, 0xec, 0xfb, 0xde, 0x79, 0x6c, 0xe5, 0x42, 0x2f, 0xf0, + 0xc3, 0x35, 0x5c, 0x21, 0xcb, 0xff, 0xdc, 0xcb, 0x79, 0xc5, 0xd9, 0x8a, + 0xc6, 0xce, 0x5f, 0xec, 0xe7, 0xde, 0x79, 0x6c, 0xe5, 0x42, 0x2f, 0xf0, 0xfb, 0x49, 0xb7, 0xf8, 0x5f, 0xdb, 0x58, 0x04, 0xe5, 0xff, 0xf7, 0xe9, - 0xfb, 0x78, 0x9c, 0x47, 0x3d, 0xd4, 0x39, 0x7f, 0x9f, 0xed, 0xbb, 0xcb, + 0xfb, 0x78, 0x9c, 0x47, 0x3d, 0xd4, 0x39, 0x7f, 0x9f, 0x9d, 0xbb, 0xcb, 0x67, 0x2d, 0xac, 0x44, 0x2f, 0x54, 0xab, 0x11, 0xbe, 0x90, 0xb7, 0xbf, - 0xff, 0xc0, 0x7f, 0xb0, 0x61, 0xb5, 0x3c, 0x31, 0xfe, 0x7d, 0xe3, 0x95, + 0xff, 0xc0, 0x7e, 0x70, 0x61, 0xb5, 0x3c, 0x31, 0xfe, 0x73, 0xe3, 0x95, 0x25, 0x7d, 0xe1, 0x31, 0xc8, 0x47, 0xac, 0x8f, 0x50, 0x92, 0x64, 0x39, 0x3b, 0x18, 0x6e, 0xc9, 0xaf, 0xe0, 0xff, 0xc2, 0x6f, 0xf6, 0x87, 0x2f, - 0x6d, 0x02, 0x72, 0xfe, 0x18, 0xf9, 0x8f, 0xe3, 0x97, 0xfd, 0x0b, 0xf0, + 0x6d, 0x02, 0x72, 0xfe, 0x18, 0xe5, 0x8f, 0xe3, 0x97, 0xfd, 0x0b, 0xf0, 0x3b, 0xa8, 0x6c, 0xe5, 0xff, 0x26, 0x36, 0xbe, 0xc2, 0x34, 0x39, 0x7f, 0x96, 0x9a, 0xdc, 0xd0, 0xe7, 0x2f, 0xfe, 0x06, 0xfa, 0xf2, 0xeb, 0xca, - 0x04, 0xe5, 0x7c, 0x7e, 0xda, 0x33, 0xbb, 0xa9, 0x32, 0x6a, 0xda, 0x1c, + 0x04, 0xe5, 0x72, 0x7e, 0xda, 0x33, 0xbb, 0xa9, 0x32, 0x6a, 0xda, 0x1c, 0x61, 0x6f, 0x0e, 0x75, 0xe8, 0x58, 0x5f, 0x79, 0x18, 0xe7, 0x2c, 0xa9, 0xcb, 0xfb, 0xbb, 0x8f, 0x40, 0x4e, 0x56, 0x1b, 0xf4, 0x12, 0xac, 0x3f, 0xff, 0x30, 0x5f, 0xf4, 0x77, 0xc9, 0x3b, 0x21, 0x67, 0x2f, 0xff, 0xce, - 0xbd, 0x47, 0x47, 0x3d, 0x9c, 0xdb, 0x6d, 0xb2, 0x95, 0x24, 0x59, 0xec, - 0x87, 0xc7, 0x37, 0xf2, 0xd6, 0x05, 0x8c, 0x1c, 0xbf, 0xfb, 0xe9, 0x0c, + 0xbd, 0x47, 0x47, 0x3d, 0x9f, 0x5b, 0x6d, 0xb2, 0x95, 0x24, 0x59, 0xec, + 0x87, 0xc7, 0x37, 0xf2, 0xd6, 0x05, 0x8c, 0x1c, 0xbf, 0xfb, 0x99, 0x0c, 0x4b, 0x51, 0xe7, 0xf1, 0xcb, 0xa2, 0x47, 0x2b, 0x0f, 0x68, 0x51, 0x2f, 0xfc, 0xfe, 0x8d, 0x6f, 0xb0, 0x3e, 0x39, 0x7e, 0xc9, 0x23, 0xf1, 0x39, 0x42, 0x7c, 0xbb, 0x3d, 0xa9, 0x22, 0x98, 0x10, 0x85, 0xbc, 0xc7, 0xe9, - 0xcb, 0xff, 0xc3, 0x12, 0xd6, 0x81, 0xf2, 0x69, 0xf6, 0x72, 0xff, 0xfb, + 0xcb, 0xff, 0xc3, 0x12, 0xd6, 0x81, 0xca, 0x69, 0xf6, 0x72, 0xff, 0xfb, 0x78, 0xa8, 0xe7, 0xb7, 0x92, 0x17, 0x6c, 0xe5, 0x93, 0xa8, 0x99, 0xf2, 0x55, 0x22, 0x37, 0x78, 0xc2, 0xd6, 0xfb, 0x82, 0x3b, 0xb3, 0x97, 0xfa, 0x7f, 0x0c, 0x03, 0xdb, 0x39, 0x7f, 0x99, 0xec, 0x9a, 0x4e, 0x27, 0x2b, 0x0f, 0x9d, 0x0d, 0x2a, 0x11, 0xab, 0x85, 0x3a, 0x84, 0x65, 0xef, 0xff, - 0x83, 0x97, 0xe1, 0x04, 0xff, 0x35, 0x9c, 0xad, 0x9e, 0x5f, 0x87, 0xaf, + 0x83, 0x97, 0xe1, 0x04, 0xfc, 0xb5, 0x9c, 0xad, 0x9e, 0x5f, 0x87, 0xaf, 0xff, 0x44, 0xe3, 0x99, 0x3f, 0x95, 0x81, 0x91, 0xcb, 0xff, 0x38, 0xcf, 0xd7, 0x62, 0x6d, 0x0e, 0x53, 0xa2, 0xa4, 0x48, 0x9b, 0x4a, 0xbc, 0xdb, - 0x6d, 0x94, 0xbe, 0x9d, 0x89, 0xb2, 0x9c, 0xcd, 0x05, 0xd0, 0x13, 0x96, + 0x6d, 0x94, 0xbe, 0x9d, 0x89, 0xb2, 0x9f, 0x4d, 0x05, 0xd0, 0x13, 0x96, 0xd3, 0x9e, 0x58, 0x9a, 0xdf, 0xa3, 0x05, 0xd8, 0x72, 0xff, 0xcf, 0x2e, - 0xa7, 0xdf, 0xe9, 0xc2, 0x72, 0xe0, 0xb6, 0x72, 0xff, 0xfd, 0x9c, 0x60, - 0x7c, 0xc8, 0xc1, 0x0e, 0x7d, 0xe3, 0x97, 0x9c, 0x57, 0x39, 0xf6, 0xe8, + 0xa7, 0x3f, 0xe9, 0xc2, 0x72, 0xe0, 0xb6, 0x72, 0xff, 0xfd, 0x9c, 0x60, + 0x7c, 0xc8, 0xc1, 0x0e, 0x73, 0xe3, 0x97, 0x9c, 0x57, 0x39, 0xf6, 0xe8, 0x62, 0xbf, 0x4c, 0x14, 0x49, 0x41, 0x0a, 0xdb, 0xfd, 0x28, 0xd4, 0xf1, 0xa9, 0xce, 0x5f, 0xdb, 0xda, 0x60, 0xfe, 0x72, 0xf6, 0xb1, 0xac, 0xe5, 0xff, 0x36, 0xa4, 0xfb, 0xc6, 0x43, 0x59, 0xcb, 0xff, 0xc8, 0xbc, 0x10, - 0xe9, 0xd7, 0x9f, 0x78, 0xe5, 0x42, 0x22, 0x36, 0x7f, 0x5a, 0x47, 0xb3, + 0xe9, 0xd7, 0x9c, 0xf8, 0xe5, 0x42, 0x22, 0x36, 0x7f, 0x5a, 0x47, 0xb3, 0x0b, 0x7d, 0x0a, 0x7a, 0x84, 0xd8, 0x32, 0x32, 0xbb, 0xff, 0xe4, 0x98, - 0x63, 0xdb, 0xf7, 0xcb, 0x41, 0x9c, 0xe5, 0xff, 0xff, 0xe4, 0x1f, 0xd4, + 0x63, 0xdb, 0xf7, 0x2b, 0x41, 0x9c, 0xe5, 0xff, 0xff, 0xe4, 0x1f, 0xd4, 0x1c, 0xd6, 0xb1, 0xbc, 0x6b, 0xc1, 0x8f, 0xd8, 0xf2, 0x39, 0x7f, 0xff, - 0x7b, 0x60, 0x0f, 0x53, 0x26, 0x74, 0x6b, 0x4f, 0xa4, 0x72, 0xff, 0xfe, - 0x1c, 0xfd, 0xc7, 0xfd, 0x6b, 0x1b, 0xcf, 0xdf, 0xe3, 0x94, 0x28, 0xbc, + 0x7b, 0x60, 0x0f, 0x53, 0x26, 0x74, 0x6b, 0x4e, 0x64, 0x72, 0xff, 0xfe, + 0x1c, 0xfd, 0xc7, 0xfd, 0x6b, 0x1b, 0xcf, 0xdf, 0x93, 0x94, 0x28, 0xbc, 0xf2, 0xfd, 0xf9, 0x3d, 0x3e, 0x36, 0x72, 0xff, 0xa1, 0x7d, 0x10, 0x7a, 0x36, 0x72, 0xff, 0xe4, 0xe0, 0x85, 0xc3, 0x30, 0x2e, 0xc3, 0x97, 0xff, 0xa2, 0x5b, 0xc8, 0x0a, 0x0b, 0xe9, 0x53, 0x97, 0xff, 0xef, 0x77, 0x25, - 0xc9, 0x7d, 0x4f, 0x7c, 0xb4, 0xd1, 0xca, 0x92, 0xa9, 0xf4, 0x8c, 0xdb, + 0xf1, 0x7d, 0x4f, 0x72, 0xb4, 0xd1, 0xca, 0x92, 0xa9, 0xf4, 0x8c, 0xdb, 0x44, 0x4c, 0x29, 0xe9, 0xc7, 0xe8, 0xa2, 0x91, 0x7f, 0xff, 0xba, 0x82, 0x1d, 0x62, 0xfb, 0x1d, 0xcd, 0x6a, 0x15, 0x39, 0x7f, 0xe5, 0xac, 0x0d, 0x7b, 0x46, 0xf3, 0x47, 0x2f, 0xff, 0xfc, 0x9e, 0x06, 0x9f, 0x6b, 0xea, 0x4c, 0x2e, 0xdf, 0xb3, 0xac, 0x39, 0x48, 0x8b, 0x07, 0x43, 0xbf, 0xe6, - 0x46, 0xb8, 0xe6, 0xa2, 0x63, 0x97, 0xfe, 0xd2, 0xd9, 0x1f, 0x6f, 0x38, - 0xe1, 0xcb, 0x9d, 0xac, 0xe5, 0xff, 0xfd, 0x30, 0xc0, 0x73, 0xef, 0x64, + 0x46, 0xb8, 0xe6, 0xa2, 0x63, 0x97, 0xfe, 0xd2, 0xd9, 0x1c, 0xef, 0x38, + 0xe1, 0xcb, 0x9d, 0xac, 0xe5, 0xff, 0xfd, 0x30, 0xc0, 0x73, 0x9f, 0x64, 0xa0, 0x67, 0x66, 0x1c, 0xbf, 0xbf, 0x69, 0x81, 0xc6, 0x1c, 0xae, 0xa2, - 0x2c, 0x56, 0xef, 0xe1, 0xe4, 0xd3, 0x35, 0x07, 0x2a, 0x13, 0x37, 0x9d, - 0x07, 0x21, 0x48, 0xe4, 0x57, 0xf9, 0xff, 0xe5, 0x81, 0x79, 0x1c, 0xb2, + 0x2c, 0x56, 0xef, 0xe1, 0xf8, 0xd3, 0x35, 0x07, 0x2a, 0x13, 0x37, 0x9d, + 0x07, 0x21, 0x48, 0xe4, 0x57, 0xf9, 0xff, 0xf9, 0x81, 0x79, 0x1c, 0xb2, 0xa7, 0x2f, 0xfe, 0xc5, 0xf6, 0x3b, 0x9a, 0xd4, 0x2a, 0x72, 0xfd, 0x9a, 0xd4, 0x2a, 0x72, 0xf8, 0x53, 0xfd, 0xc1, 0xff, 0x68, 0x4b, 0xa8, 0x97, 0xfe, 0xce, 0xbf, 0xec, 0x79, 0x3e, 0xce, 0x56, 0x26, 0x6c, 0x90, 0xb3, 0xea, 0x2d, 0xff, 0xe7, 0x9f, 0xa9, 0x03, 0x93, 0x26, 0x90, 0xe5, 0x05, 0x7f, 0xc7, 0x25, 0x78, 0x4c, 0xd7, 0xd8, 0xc4, 0x3f, 0x21, 0xdc, 0x6e, 0x5e, 0x8d, 0xdd, 0xb3, 0x4b, 0xf0, 0xe7, 0x5f, 0xc7, 0x2f, 0xfd, 0x28, - 0x19, 0xd4, 0xd0, 0x82, 0x47, 0x2f, 0xe1, 0x70, 0xff, 0xf7, 0xe7, 0x29, + 0x19, 0xd4, 0xd0, 0x82, 0x47, 0x2f, 0xe1, 0x70, 0xff, 0xcf, 0xe7, 0x29, 0xad, 0x12, 0xd3, 0x13, 0x6d, 0x02, 0xfb, 0xd3, 0xe0, 0x4e, 0x5f, 0xf2, 0x2a, 0xa6, 0xbf, 0x62, 0x6c, 0xe5, 0x4c, 0x7b, 0xed, 0x08, 0xef, 0x36, 0xdb, 0x67, 0x2f, 0xff, 0xd8, 0xcf, 0x0c, 0x7f, 0x81, 0xde, 0x32, 0x16, - 0x53, 0x99, 0xa0, 0xbf, 0xf6, 0x7d, 0xc8, 0x73, 0x8e, 0x93, 0x67, 0x2f, + 0x53, 0xe9, 0xa0, 0xbf, 0xf6, 0x73, 0xf0, 0x73, 0x8e, 0x93, 0x67, 0x2f, 0xe5, 0xf5, 0x20, 0x56, 0x72, 0xa0, 0xfb, 0xb1, 0x0a, 0xff, 0x6a, 0x3c, 0x8b, 0x40, 0x9c, 0xbf, 0x4a, 0x6c, 0xc5, 0x9c, 0xb6, 0x8e, 0x53, 0x52, 0x7d, 0x70, 0x64, 0xa1, 0x45, 0x62, 0xa6, 0xb4, 0x84, 0x9f, 0x51, 0x46, 0x1a, 0x9b, 0x84, 0x5d, 0xef, 0x4b, 0xa7, 0x2c, 0x87, 0x2f, 0xee, 0xc7, - 0x25, 0xa4, 0xe7, 0x2f, 0xff, 0x4d, 0xd7, 0x66, 0x69, 0x55, 0x40, 0x3e, + 0xc5, 0xa4, 0xe7, 0x2f, 0xff, 0x4d, 0xd7, 0x66, 0x69, 0x55, 0x40, 0x3e, 0x39, 0x7f, 0x69, 0xf4, 0x31, 0x23, 0x97, 0xff, 0xcf, 0xee, 0xe7, 0x1e, - 0xa7, 0x2d, 0xed, 0x18, 0x72, 0xff, 0xc9, 0x24, 0xd7, 0xd0, 0x31, 0xb3, + 0xa7, 0xcd, 0xed, 0x18, 0x72, 0xff, 0xc9, 0x24, 0xd7, 0x30, 0x31, 0xb3, 0x95, 0xc2, 0xe9, 0xa4, 0x84, 0x43, 0x0c, 0x34, 0x9a, 0x25, 0x9e, 0x53, - 0xba, 0x5c, 0xda, 0xb7, 0x42, 0x23, 0xc3, 0x35, 0xc4, 0x35, 0x67, 0x3e, + 0xba, 0x5f, 0x5a, 0xb7, 0x42, 0x23, 0xc3, 0x35, 0xc4, 0x35, 0x67, 0x3e, 0x94, 0x36, 0x83, 0x18, 0x06, 0x4e, 0x4a, 0x2b, 0x08, 0x75, 0xc7, 0x1d, - 0xf4, 0x72, 0x68, 0x61, 0x34, 0x65, 0xba, 0x8f, 0x6b, 0xb1, 0x93, 0xbc, + 0xcc, 0x72, 0x68, 0x61, 0x34, 0x65, 0xba, 0x8f, 0x6b, 0xb1, 0x93, 0xbc, 0x26, 0xbf, 0x8c, 0xac, 0x63, 0x96, 0xdd, 0x20, 0x67, 0xd2, 0xe4, 0x1a, 0x2c, 0x29, 0x1b, 0x35, 0xff, 0xed, 0x63, 0x61, 0xee, 0x4c, 0x39, 0xa9, 0x1c, 0xbd, 0xac, 0x6b, 0x39, 0x7f, 0xe8, 0x6d, 0x49, 0xf7, 0x8c, 0x86, 0xb3, 0x95, 0xa4, 0x57, 0x31, 0x2f, 0xc3, 0xf7, 0xff, 0xce, 0xc8, 0xd2, 0xf4, 0x05, 0x74, 0x07, 0xd9, 0xca, 0xc4, 0x40, 0x80, 0xc2, 0xff, 0x69, 0x60, 0x70, 0xb2, 0x0e, 0x5f, 0xfd, 0x1a, 0x53, 0xc9, 0xee, 0xe0, 0x50, - 0xe5, 0xfe, 0x1f, 0xbf, 0xcd, 0xbb, 0x59, 0xcb, 0xfe, 0x18, 0x9d, 0x4e, + 0xe5, 0xfe, 0x1e, 0x7f, 0xcd, 0xbb, 0x59, 0xcb, 0xfe, 0x18, 0x9d, 0x4e, 0xf5, 0xda, 0xce, 0x56, 0x1f, 0xa7, 0x4d, 0xef, 0xff, 0xf9, 0x05, 0x3f, 0xde, 0xb1, 0x7d, 0x8e, 0xe6, 0xb5, 0x0a, 0x9c, 0xa8, 0x4d, 0xca, 0x73, 0x3c, 0x85, 0xc7, 0x88, 0x6f, 0x35, 0x16, 0xa6, 0x47, 0x2f, 0x3e, 0xa7, - 0x39, 0x73, 0x6d, 0x9c, 0xbc, 0xeb, 0xe6, 0xb3, 0x6c, 0xd8, 0xed, 0xfd, - 0x1a, 0x79, 0x27, 0x4e, 0x5f, 0xb1, 0x9d, 0x70, 0x9c, 0xb7, 0x38, 0x75, + 0x39, 0x73, 0x6d, 0x9c, 0xbc, 0xeb, 0xfa, 0xb3, 0x6c, 0xd8, 0xed, 0xfd, + 0x1a, 0x79, 0x27, 0x4e, 0x5f, 0xb1, 0x9d, 0x70, 0x9c, 0xb7, 0xd8, 0x75, 0xc6, 0x32, 0x4d, 0x0a, 0x0e, 0x47, 0x9a, 0xa9, 0x52, 0xe7, 0x07, 0x66, 0x2b, 0xd4, 0x2a, 0x9e, 0xd0, 0x99, 0x0c, 0xac, 0xcd, 0xc7, 0x29, 0xe4, 0x2e, 0x2b, 0xcd, 0x9a, 0xf0, 0x16, 0x54, 0x9f, 0x19, 0xf8, 0x34, 0x89, - 0x0f, 0xa3, 0x6b, 0xd1, 0x53, 0x21, 0x1f, 0xd9, 0x48, 0x1f, 0xc3, 0x70, + 0x0e, 0x63, 0x6b, 0xd1, 0x53, 0x21, 0x1f, 0xd9, 0x48, 0x1f, 0xc3, 0x70, 0x4e, 0x37, 0x3a, 0x89, 0xe9, 0x69, 0x40, 0xb5, 0xdb, 0xf7, 0xf6, 0xe2, - 0x69, 0x24, 0xc7, 0x2f, 0xfb, 0xd0, 0x29, 0xfe, 0x7d, 0xe3, 0x97, 0xcd, + 0x69, 0x24, 0xc7, 0x2f, 0xfb, 0xd0, 0x29, 0xfe, 0x73, 0xe3, 0x97, 0xcd, 0x1c, 0x7f, 0x39, 0x74, 0x4f, 0x87, 0xba, 0xa1, 0xcd, 0x6d, 0x17, 0x4a, - 0x42, 0x32, 0xff, 0x91, 0x68, 0x1e, 0x7d, 0x8f, 0xce, 0x57, 0x33, 0xe4, - 0xf1, 0x4d, 0xff, 0x9d, 0x7c, 0xc1, 0xfa, 0x4b, 0x24, 0x72, 0xfd, 0xa5, - 0xbb, 0xac, 0xd1, 0x1a, 0xaf, 0x2b, 0xf6, 0xce, 0x5b, 0x9c, 0xe8, 0x94, - 0xc4, 0x1f, 0x1a, 0x5f, 0xff, 0xee, 0x30, 0x3e, 0xe6, 0xfc, 0x5c, 0x38, + 0x42, 0x32, 0xff, 0x91, 0x68, 0x1f, 0xbd, 0x8f, 0xce, 0x57, 0xd3, 0xe4, + 0xf1, 0x4d, 0xff, 0x9d, 0x7f, 0x41, 0xfa, 0x4b, 0x24, 0x72, 0xfd, 0xa5, + 0xbb, 0xac, 0xd1, 0x1a, 0xaf, 0x2b, 0xce, 0xce, 0x5b, 0xec, 0xe8, 0x94, + 0xc4, 0x1f, 0x1a, 0x5f, 0xff, 0xee, 0x30, 0x3e, 0xfa, 0xfc, 0x5c, 0x38, 0x17, 0x63, 0x84, 0xe5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0xa5, 0x5c, 0xeb, - 0x34, 0x43, 0x4b, 0x73, 0xc3, 0xd7, 0x73, 0x4b, 0xf6, 0x96, 0xee, 0xb3, + 0x34, 0x43, 0x4b, 0x7d, 0xc3, 0xd7, 0x73, 0x4b, 0xf6, 0x96, 0xee, 0xb3, 0x44, 0x7c, 0xbf, 0xf8, 0x1a, 0xfd, 0x7d, 0x49, 0x86, 0x3f, 0x39, 0x7f, - 0xfc, 0x2f, 0xe9, 0x42, 0xbc, 0xa3, 0xdb, 0x8f, 0xce, 0x5e, 0x79, 0x73, + 0xfc, 0x2f, 0xe9, 0x42, 0xbf, 0x23, 0xdb, 0x8f, 0xce, 0x5e, 0x79, 0x7d, 0xc4, 0x66, 0xec, 0xd1, 0x44, 0x7b, 0xff, 0x3c, 0xf1, 0xd4, 0xd2, 0x43, - 0x0e, 0x5f, 0xe8, 0xd6, 0x0f, 0xb3, 0xa7, 0x2f, 0x33, 0x39, 0xb4, 0x3e, - 0xe5, 0x0f, 0x6b, 0x9a, 0x3a, 0x62, 0x16, 0x37, 0xff, 0xfd, 0x20, 0x69, - 0x57, 0xde, 0x06, 0x3e, 0xda, 0x9e, 0x55, 0x15, 0x39, 0x79, 0xb5, 0x56, - 0x72, 0xfd, 0xf7, 0xd2, 0xcf, 0x1c, 0xad, 0x9e, 0x48, 0x07, 0xef, 0xff, - 0x70, 0xa5, 0x5b, 0x6b, 0x9c, 0x3c, 0x37, 0x2e, 0x5d, 0x68, 0x72, 0xfd, + 0x0e, 0x5f, 0xe8, 0xd6, 0x0f, 0xb3, 0xa7, 0x2f, 0x33, 0x3e, 0xb4, 0x3e, + 0xe5, 0x0f, 0x6b, 0xea, 0x3a, 0x62, 0x16, 0x37, 0xff, 0xfd, 0x20, 0x69, + 0x57, 0xde, 0x06, 0x39, 0xda, 0x9e, 0x55, 0x15, 0x39, 0x79, 0xb5, 0x56, + 0x72, 0xfd, 0xcf, 0x32, 0xcf, 0x1c, 0xad, 0x9e, 0x48, 0x07, 0xef, 0xff, + 0x70, 0xa5, 0x5b, 0x6b, 0x9c, 0x3c, 0x37, 0xcf, 0x9d, 0x68, 0x72, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x63, 0xaf, 0xf6, 0x20, 0xcf, 0xec, 0xe9, 0xcb, 0x9f, 0x67, 0x2f, 0xe9, 0xd4, 0xd6, 0xb3, 0x47, 0x2a, 0x47, 0x8c, 0xe2, 0xd7, 0xfc, 0x2e, 0xaf, 0x52, 0x06, 0x73, 0x97, 0xff, 0xf0, 0x05, 0xd5, - 0xe5, 0xe5, 0x60, 0x65, 0x9d, 0x46, 0x1c, 0xbf, 0xff, 0x7f, 0x29, 0xf8, - 0x54, 0x35, 0x73, 0xaf, 0x5c, 0xb9, 0x75, 0xa1, 0xcb, 0x92, 0x47, 0x2f, + 0xf9, 0xe5, 0x60, 0x65, 0x9d, 0x46, 0x1c, 0xbf, 0xff, 0x7f, 0x29, 0xf8, + 0x54, 0x35, 0x73, 0xaf, 0x5f, 0x3e, 0x75, 0xa1, 0xcb, 0x92, 0x47, 0x2f, 0xf7, 0x87, 0x38, 0xf5, 0xe4, 0x72, 0x82, 0x79, 0x58, 0x2d, 0x7e, 0x4f, 0x79, 0x3c, 0x72, 0xff, 0xfc, 0x01, 0x75, 0x7c, 0xac, 0x0c, 0xb3, 0xa8, 0xc3, 0x97, 0xda, 0xd6, 0x34, 0x39, 0x58, 0x8a, 0x06, 0x13, 0xba, 0xad, - 0xfb, 0x35, 0x99, 0x31, 0xcb, 0x73, 0x85, 0xc6, 0x99, 0xe1, 0x6b, 0x22, + 0xfb, 0x35, 0x99, 0x31, 0xcb, 0x7d, 0x85, 0xc6, 0x99, 0xe1, 0x6b, 0x22, 0x2c, 0x64, 0x54, 0xd1, 0x1e, 0x26, 0x21, 0x61, 0xc7, 0x57, 0x46, 0x16, 0xdb, 0x86, 0x0a, 0x85, 0xd7, 0xca, 0xa6, 0xa6, 0x39, 0x7b, 0x85, 0x31, 0x53, 0x97, 0xf7, 0x08, 0x39, 0xd7, 0xf1, 0xcb, 0xfc, 0xff, 0xed, 0xfd, 0xe7, 0x39, 0x73, 0x16, 0x72, 0x84, 0xf2, 0xbc, 0x67, 0x7f, 0xec, 0x6f, - 0x58, 0x2f, 0xf4, 0xb6, 0x72, 0xfd, 0xd7, 0x64, 0x09, 0xcb, 0xed, 0xf5, - 0x1b, 0x39, 0x7e, 0x86, 0xfd, 0x9d, 0x39, 0x7a, 0x14, 0xc3, 0x95, 0xc9, - 0x11, 0xb8, 0x4c, 0x24, 0x7b, 0x28, 0xbf, 0xfd, 0x9c, 0x18, 0xbf, 0x7d, + 0x58, 0x2f, 0xcc, 0xb6, 0x72, 0xfd, 0xd7, 0x64, 0x09, 0xcb, 0xed, 0xf5, + 0x1b, 0x39, 0x7e, 0x86, 0xfd, 0x9d, 0x39, 0x7a, 0x14, 0xc3, 0x95, 0xf1, + 0x11, 0xb8, 0x4c, 0x24, 0x7b, 0x28, 0xbf, 0xfd, 0x9c, 0x18, 0xbf, 0x73, 0x2c, 0x1f, 0xdc, 0xe5, 0xf7, 0xec, 0x4d, 0x1c, 0xbd, 0x8e, 0x27, 0x2f, 0x76, 0x26, 0x39, 0x72, 0x79, 0x0d, 0xbb, 0x8d, 0x5f, 0xff, 0xf4, 0x68, - 0x70, 0x39, 0xde, 0xa2, 0xfa, 0x9e, 0xdb, 0xfc, 0x72, 0xff, 0xfd, 0x93, - 0x67, 0x00, 0xe7, 0x11, 0xcf, 0xd9, 0x12, 0x39, 0x7f, 0xcf, 0xf0, 0xe7, + 0x70, 0x39, 0xde, 0xa2, 0xfa, 0x9e, 0xdb, 0xf2, 0x72, 0xff, 0xfd, 0x93, + 0x67, 0x00, 0xe7, 0x11, 0xcf, 0xd9, 0x12, 0x39, 0x7f, 0xcf, 0xc8, 0xe7, 0xb7, 0x8d, 0x9c, 0xa5, 0xa7, 0x90, 0x89, 0xad, 0x6b, 0x5d, 0x2a, 0x16, 0x50, 0x2c, 0xdf, 0xba, 0x9a, 0x04, 0x8e, 0x5f, 0xd1, 0xaf, 0xda, 0x03, 0xc7, 0x2f, 0xfa, 0x07, 0xdc, 0x33, 0xf8, 0x10, 0x72, 0xff, 0xf4, 0x76, @@ -2128,74 +2128,74 @@ 0xbf, 0xff, 0x77, 0x1b, 0xf3, 0x23, 0x3d, 0xdc, 0xc1, 0x59, 0xcb, 0xff, 0xf2, 0x7a, 0x59, 0xad, 0x3c, 0x94, 0x17, 0xf6, 0xce, 0x54, 0x2b, 0xf8, 0x91, 0x40, 0x4c, 0x56, 0x78, 0x89, 0x1a, 0x8c, 0x2f, 0xa9, 0x42, 0xf3, - 0xb7, 0x8f, 0x16, 0x71, 0x54, 0xbb, 0x18, 0x72, 0xff, 0xe7, 0xfb, 0x8f, + 0xb7, 0x8f, 0x16, 0x71, 0x54, 0xbb, 0x18, 0x72, 0xff, 0xe7, 0xe7, 0x8f, 0x5a, 0xd3, 0xc3, 0x0c, 0x39, 0x5a, 0x3d, 0xf7, 0x16, 0xbf, 0xff, 0x27, - 0xb6, 0xff, 0x6f, 0x79, 0xd4, 0xd8, 0x27, 0x39, 0x7f, 0xfc, 0x09, 0xf4, + 0xb6, 0xfc, 0xef, 0x79, 0xd4, 0xd8, 0x27, 0x39, 0x7f, 0xfc, 0x09, 0xf4, 0x9e, 0x9c, 0x1a, 0x96, 0xda, 0xd0, 0xe5, 0x75, 0x15, 0xa2, 0xaf, 0x7f, - 0x6d, 0xd4, 0xcf, 0xbc, 0x72, 0xff, 0x20, 0x71, 0x9c, 0xb0, 0x27, 0x2f, + 0x6d, 0xd4, 0xce, 0x7c, 0x72, 0xff, 0x20, 0x71, 0x9f, 0x30, 0x27, 0x2f, 0xff, 0x81, 0xad, 0x40, 0xe2, 0xa9, 0xde, 0xe2, 0x87, 0x2d, 0xc3, 0x9c, 0xad, 0x1f, 0x30, 0x14, 0x2f, 0xf3, 0x00, 0x3e, 0xd8, 0x34, 0x72, 0xa4, - 0x8f, 0x0d, 0x42, 0x69, 0xa1, 0x15, 0xfc, 0x3f, 0x4b, 0xc0, 0x09, 0xcb, + 0x8f, 0x0d, 0x42, 0x69, 0xa1, 0x15, 0xfc, 0x3c, 0xcb, 0xc0, 0x09, 0xcb, 0xf3, 0x5e, 0x0b, 0x10, 0xe5, 0x41, 0xec, 0x39, 0x7d, 0xff, 0xce, 0xdf, 0xb3, 0xbb, 0x9b, 0x32, 0x73, 0x97, 0xe9, 0xbb, 0x9f, 0xb9, 0xca, 0xea, 0x23, 0xc4, 0x83, 0x8a, 0x35, 0xff, 0xfe, 0xcc, 0xf6, 0xe2, 0x6e, 0xc7, 0x11, 0xc0, 0xf6, 0x36, 0x72, 0xfc, 0x2b, 0x7d, 0xa1, 0xcb, 0xff, 0xfb, - 0x43, 0x11, 0xf7, 0x2d, 0xf8, 0x60, 0x3d, 0x8f, 0x1c, 0xb9, 0x3a, 0x72, + 0x43, 0x11, 0xcf, 0xcd, 0xf8, 0x60, 0x3d, 0x8f, 0x1c, 0xb9, 0x3a, 0x72, 0xfa, 0x42, 0xea, 0x1c, 0xbf, 0xc1, 0x7f, 0xf5, 0xa7, 0xfc, 0xe5, 0xf6, 0x96, 0xd6, 0xd9, 0xcb, 0xe5, 0x78, 0x47, 0x6c, 0xe5, 0x61, 0xe8, 0x39, 0x3d, 0x22, 0x29, 0x46, 0x10, 0xb5, 0x09, 0xc2, 0xe1, 0x33, 0x5a, 0xe3, 0x8b, 0x02, 0x18, 0xf7, 0x9d, 0xad, 0x0e, 0x5f, 0xf9, 0x4f, 0x2a, 0x8a, - 0xc6, 0x0c, 0x1c, 0xbf, 0x29, 0xe1, 0x8f, 0xce, 0x57, 0xc8, 0x86, 0xd0, - 0xf7, 0x13, 0xfb, 0xf4, 0x7b, 0x3b, 0x07, 0x2f, 0xfd, 0x9f, 0x4b, 0x69, + 0xc6, 0x0c, 0x1c, 0xbf, 0x29, 0xe1, 0x8f, 0xce, 0x57, 0x28, 0x86, 0xd0, + 0xf7, 0x13, 0xfb, 0xf4, 0x7b, 0x3b, 0x07, 0x2f, 0xfd, 0x9c, 0xcb, 0x69, 0xe7, 0x1c, 0x39, 0x7f, 0xb1, 0x9d, 0xc9, 0x9e, 0x63, 0x97, 0xfe, 0xea, - 0x07, 0x12, 0x7e, 0xc4, 0x72, 0x3f, 0x1f, 0x1e, 0xdf, 0xff, 0xfd, 0x08, - 0x39, 0xe8, 0x63, 0x60, 0x79, 0xf9, 0x67, 0x53, 0x5d, 0x73, 0x97, 0xfe, - 0xcf, 0xa5, 0xb9, 0xb4, 0xfe, 0xd9, 0xcb, 0xf0, 0xc2, 0xe4, 0xc3, 0x97, + 0x07, 0x12, 0x7e, 0xc4, 0x7c, 0x3f, 0x1f, 0x1e, 0xdf, 0xff, 0xfd, 0x08, + 0x39, 0xe8, 0x63, 0x60, 0x79, 0xfe, 0x67, 0x53, 0x5d, 0x73, 0x97, 0xfe, + 0xce, 0x65, 0xb9, 0xb4, 0xfe, 0xd9, 0xcb, 0xf0, 0xc2, 0xe4, 0xc3, 0x97, 0xff, 0x6f, 0x26, 0xec, 0x71, 0xce, 0xf6, 0x0e, 0x50, 0x4f, 0xb7, 0xc4, - 0xf7, 0xf9, 0xff, 0xdb, 0x1f, 0xef, 0x1c, 0xac, 0x3d, 0x77, 0x22, 0xbf, + 0xf7, 0xf9, 0xff, 0xdb, 0x1f, 0x9f, 0x1c, 0xac, 0x3d, 0x77, 0x22, 0xbf, 0xd1, 0x13, 0x67, 0x14, 0xd1, 0xcb, 0xe4, 0xd6, 0x09, 0xca, 0x13, 0xd4, 0xd9, 0xa5, 0x4e, 0xab, 0xe5, 0x70, 0x97, 0xd2, 0xb7, 0xee, 0x43, 0x18, - 0x2f, 0x9d, 0x2f, 0xdc, 0xa6, 0x92, 0x4c, 0x72, 0xa1, 0x5d, 0xee, 0x4b, - 0x2c, 0x46, 0x5b, 0xff, 0xba, 0x9c, 0xb0, 0x71, 0x34, 0xfc, 0x4e, 0x5f, + 0x2f, 0x9d, 0x2f, 0xdf, 0x26, 0x92, 0x4c, 0x72, 0xa1, 0x5d, 0xee, 0x4b, + 0x2c, 0x46, 0x5b, 0xff, 0xba, 0x9f, 0x30, 0x71, 0x34, 0xfc, 0x4e, 0x5f, 0xfc, 0x82, 0xe1, 0x1c, 0x0f, 0x63, 0x67, 0x2f, 0x29, 0x1a, 0x39, 0x7f, 0xff, 0xbb, 0x03, 0x9f, 0xef, 0x03, 0xd8, 0x9d, 0x80, 0x10, 0x9c, 0xbf, 0x27, 0xbd, 0x12, 0x39, 0x4a, 0xa6, 0x56, 0xb4, 0x5d, 0x20, 0xf8, 0x77, 0x8b, 0x0d, 0xff, 0xfd, 0x13, 0x60, 0x7b, 0x1c, 0x7b, 0x9e, 0x18, 0x86, - 0x1c, 0xbf, 0xbe, 0xda, 0x93, 0x80, 0x4e, 0x5f, 0xf4, 0x2f, 0xa9, 0x33, + 0x1c, 0xbf, 0xb9, 0xda, 0x93, 0x80, 0x4e, 0x5f, 0xf4, 0x2f, 0xa9, 0x33, 0xbc, 0xe7, 0x29, 0x88, 0xc5, 0x75, 0xbf, 0xcc, 0x6f, 0xf4, 0xa3, 0x53, 0xc6, 0xa7, 0x39, 0x7f, 0xe4, 0xe2, 0xe3, 0xff, 0x73, 0xf7, 0x39, 0x7f, 0x0c, 0xef, 0xd4, 0x13, 0x97, 0xfc, 0x80, 0x19, 0x6a, 0x30, 0x27, 0x2f, 0xff, 0xfb, 0xb9, 0x25, 0xf5, 0x3b, 0x19, 0xa9, 0x78, 0x61, 0x9b, 0x39, - 0x7c, 0x08, 0xf8, 0x27, 0x28, 0x29, 0x95, 0xba, 0x06, 0xcb, 0x3c, 0x6e, + 0x7c, 0x08, 0xe4, 0x27, 0x28, 0x29, 0x95, 0xba, 0x06, 0xcb, 0x3c, 0x6e, 0xdb, 0x2d, 0xf7, 0x04, 0x6a, 0x73, 0x95, 0x09, 0xe8, 0xe4, 0x6c, 0x0e, 0x97, 0x7f, 0xb4, 0xb9, 0xb1, 0x3a, 0x03, 0x97, 0xfe, 0x4e, 0x23, 0x9b, 0xf2, 0xa8, 0xb3, 0x97, 0xfb, 0xdd, 0x6b, 0x4e, 0xbc, 0xc7, 0x2f, 0xe8, - 0x58, 0xbf, 0xde, 0x39, 0x52, 0x45, 0x23, 0x5a, 0x03, 0x0d, 0xef, 0xd1, - 0xe9, 0xf1, 0xb3, 0x97, 0xfe, 0xf9, 0x62, 0xf3, 0xbc, 0x93, 0xa7, 0x2b, + 0x58, 0xbf, 0x3e, 0x39, 0x52, 0x45, 0x23, 0x5a, 0x03, 0x0d, 0xef, 0xd1, + 0xe9, 0xf1, 0xb3, 0x97, 0xfe, 0xe5, 0x62, 0xf3, 0xbc, 0x93, 0xa7, 0x2b, 0x47, 0xd0, 0x02, 0x9b, 0xce, 0x3f, 0x9c, 0xbf, 0xff, 0xfe, 0x40, 0x6b, 0xb9, 0x34, 0xcf, 0xa9, 0xbd, 0xd0, 0x7f, 0xbc, 0x4e, 0x21, 0x83, 0x97, 0xef, 0x75, 0xc5, 0x53, 0x97, 0xfc, 0x20, 0x9c, 0x3d, 0xc1, 0x83, 0x96, 0xc0, 0xa3, 0x8f, 0x21, 0x06, 0xb2, 0x8b, 0xff, 0xbf, 0x5f, 0xe3, 0x9e, - 0xdb, 0xb8, 0x9c, 0xbc, 0xc7, 0xf8, 0xe5, 0x68, 0xf8, 0x7f, 0x44, 0xa8, + 0xdb, 0xb8, 0x9c, 0xbc, 0xc7, 0xe4, 0xe5, 0x68, 0xf8, 0x7f, 0x44, 0xa8, 0x56, 0xa3, 0x90, 0xd8, 0x48, 0x4d, 0xb9, 0x10, 0xc3, 0xfc, 0x10, 0x9a, 0xbf, 0xd9, 0xd9, 0x93, 0xa8, 0xc3, 0x97, 0xfa, 0x59, 0xad, 0x8c, 0x4e, 0x72, 0xf3, 0x4c, 0x9c, 0xe5, 0xff, 0x40, 0xc2, 0xf4, 0x90, 0xc3, 0x97, 0xb3, 0xae, 0x72, 0xfd, 0x30, 0x40, 0x01, 0x39, 0x41, 0x3c, 0x47, 0x1b, 0xbc, 0xd6, 0x8c, 0x39, 0x7f, 0xfe, 0x77, 0xff, 0x71, 0xff, 0xb1, 0x03, 0x83, 0x31, 0xce, 0x97, 0xf7, 0xf3, 0x78, 0xb5, 0xe3, 0x67, 0x2f, 0x42, - 0xf8, 0x9c, 0xac, 0x3c, 0xdf, 0x17, 0xdf, 0xf7, 0xcc, 0xcc, 0x1f, 0x34, + 0xf8, 0x9c, 0xac, 0x3c, 0xdf, 0x17, 0xdf, 0xf7, 0x2c, 0xcc, 0x1f, 0x34, 0xc3, 0x97, 0x95, 0x90, 0x0e, 0x5f, 0xbb, 0x1a, 0x9d, 0x87, 0x2f, 0xf0, - 0x1c, 0x7b, 0x8f, 0x31, 0xcb, 0x7d, 0x31, 0xed, 0xb6, 0x53, 0x48, 0x8a, - 0x47, 0x79, 0xac, 0x4c, 0x81, 0xc8, 0x46, 0x1b, 0xd5, 0x8a, 0xd0, 0xfe, + 0x1c, 0x7b, 0x8f, 0x31, 0xcb, 0x73, 0x31, 0xed, 0xb6, 0x53, 0x48, 0x8a, + 0x47, 0x79, 0xac, 0x4c, 0x81, 0xc8, 0x46, 0x1b, 0xd5, 0x8a, 0xd0, 0xf9, 0x33, 0x43, 0x3e, 0x8f, 0xbb, 0xd0, 0xa0, 0x6e, 0x3d, 0x1b, 0xc3, 0x9f, 0x9c, 0xb4, 0x1c, 0xaf, 0xcd, 0x67, 0x87, 0x2e, 0x7f, 0x1c, 0xad, 0x1b, - 0x8e, 0x91, 0x5f, 0x32, 0x35, 0xb3, 0x97, 0xfd, 0xac, 0xee, 0x4f, 0xc9, + 0x8e, 0x91, 0x5f, 0x32, 0x35, 0xb3, 0x97, 0xfd, 0xac, 0xee, 0x4f, 0xf1, 0x36, 0x72, 0xb0, 0xff, 0x90, 0x84, 0x04, 0x57, 0xf2, 0x08, 0x25, 0x9b, - 0x39, 0x7f, 0xec, 0xf4, 0x7d, 0xfb, 0xf7, 0xa8, 0x72, 0xcc, 0x39, 0x7f, - 0x20, 0x82, 0x59, 0xbe, 0x47, 0xa1, 0xc4, 0xfe, 0x95, 0x46, 0x1f, 0x9f, - 0x2d, 0xcd, 0xa9, 0x74, 0x1b, 0xed, 0x59, 0x27, 0x0c, 0x49, 0x0f, 0x73, + 0x39, 0x7f, 0xec, 0xf4, 0x73, 0xfb, 0xf7, 0xa8, 0x72, 0xcc, 0x39, 0x7f, + 0x20, 0x82, 0x59, 0xbf, 0x87, 0xa1, 0xc4, 0xfe, 0x95, 0x46, 0x1f, 0x9f, + 0x2d, 0xf5, 0xa9, 0x74, 0x1b, 0xed, 0x59, 0x27, 0x0c, 0x49, 0x0f, 0x73, 0x90, 0xca, 0x19, 0x81, 0x94, 0x0b, 0x93, 0x8a, 0x2a, 0xc3, 0xf9, 0x70, - 0xce, 0xf8, 0x89, 0x23, 0x1f, 0x9a, 0x31, 0xed, 0x18, 0xb2, 0x3e, 0x6e, + 0xce, 0xe4, 0x89, 0x23, 0x1f, 0x9a, 0x31, 0xed, 0x18, 0xb2, 0x3e, 0x6e, 0xce, 0x49, 0xbc, 0x6c, 0x3f, 0xc6, 0x26, 0x32, 0x80, 0x77, 0x2e, 0x17, 0xd2, 0xea, 0xda, 0x46, 0x96, 0xa4, 0x3c, 0x2f, 0xee, 0x04, 0x08, 0xc4, 0xc7, 0x2f, 0x43, 0x89, 0xcb, 0xec, 0xeb, 0xf8, 0xe5, 0xb8, 0x4c, 0x3e, @@ -2203,60 +2203,60 @@ 0x01, 0xf4, 0x76, 0x15, 0x04, 0x70, 0x1c, 0xbe, 0xcd, 0xfe, 0x87, 0x2f, 0xda, 0x5b, 0xba, 0xcd, 0x16, 0xb2, 0xff, 0x31, 0x18, 0xf3, 0x67, 0x4e, 0x5f, 0xd9, 0xc1, 0xb7, 0x15, 0x9c, 0xbd, 0xa8, 0x61, 0xcb, 0xfb, 0xb9, - 0xb8, 0x9f, 0x80, 0xe5, 0xff, 0x4b, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x50, + 0xb8, 0x9f, 0x80, 0xe5, 0xff, 0x4b, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x50, 0x6a, 0xc3, 0xf8, 0x73, 0x1b, 0xec, 0x9a, 0x3c, 0x72, 0xff, 0xa2, 0x51, 0xa9, 0xe3, 0x53, 0x9c, 0xbe, 0x57, 0xd9, 0xd3, 0x97, 0xf9, 0x22, 0x6f, 0xdc, 0x66, 0x39, 0x7f, 0xfd, 0xb4, 0x9d, 0xf6, 0xe2, 0xfe, 0xec, 0x4c, 0x72, 0xff, 0xce, 0x3f, 0xe7, 0xa0, 0x53, 0xf3, 0x95, 0xe4, 0x46, 0x34, - 0x4f, 0xb7, 0x3e, 0x19, 0x5c, 0x1c, 0x1c, 0x49, 0xef, 0x08, 0x90, 0xd2, + 0x4f, 0xb7, 0xde, 0x19, 0x5c, 0x1c, 0x1c, 0x49, 0xef, 0x08, 0x90, 0xd2, 0x63, 0x3d, 0x17, 0xb2, 0x12, 0x9d, 0x20, 0x12, 0x2d, 0x9d, 0x78, 0x8d, - 0x48, 0x60, 0x5f, 0xfe, 0xe6, 0xc7, 0x97, 0x3c, 0xd2, 0xdd, 0xd6, 0x68, - 0xa2, 0xd7, 0xfb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x5d, 0x4a, 0x87, 0x61, + 0x48, 0x60, 0x5f, 0xfe, 0xfa, 0xc7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, + 0xa2, 0xd7, 0xfb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x5d, 0x4a, 0x87, 0x61, 0x87, 0x28, 0x5c, 0x61, 0xc2, 0xe1, 0x76, 0x91, 0xef, 0x32, 0x72, 0x4b, 0xb6, 0x86, 0x7b, 0xf9, 0xda, 0x6d, 0xc3, 0x27, 0xcb, 0x57, 0xed, 0x2d, 0xdd, 0x66, 0x88, 0x85, 0x7b, 0xa8, 0x27, 0x2e, 0xc0, 0x9c, 0xb2, 0xce, 0x52, 0xcf, 0x0b, 0xa3, 0x62, 0x2d, 0x7d, 0x9c, 0x53, 0x47, 0x2f, 0x93, - 0x59, 0xf1, 0xca, 0xc4, 0x74, 0xfc, 0xec, 0xd6, 0x5c, 0xd0, 0x8e, 0xff, - 0x7b, 0x9c, 0xc3, 0x1f, 0xec, 0xe5, 0x73, 0x3f, 0x9c, 0x42, 0xb3, 0x43, + 0x59, 0xc9, 0xca, 0xc4, 0x74, 0xf2, 0xec, 0xd6, 0x5c, 0xd0, 0x8e, 0xff, + 0x7b, 0xec, 0xc3, 0x1f, 0xec, 0xe5, 0x7d, 0x3f, 0x9c, 0x42, 0xb3, 0x43, 0x97, 0xd1, 0xd8, 0x61, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x1b, 0x29, 0x67, - 0x9f, 0xa2, 0x1b, 0x73, 0x0a, 0x21, 0x31, 0x8a, 0xff, 0x73, 0xcd, 0x2d, + 0x9f, 0xa2, 0x1b, 0x7d, 0x0a, 0x21, 0x31, 0x8a, 0xff, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x6d, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0xa8, 0x17, 0xb3, - 0xe6, 0xce, 0x5b, 0x9e, 0x1e, 0x97, 0x4d, 0x2f, 0xf7, 0x3c, 0xd2, 0xdd, + 0x96, 0xce, 0x5b, 0xee, 0x1e, 0x97, 0x4d, 0x2f, 0xf7, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0xa9, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x8a, 0xc1, 0x7e, 0x46, 0xc2, 0x0d, 0x1c, 0xbd, 0xfa, 0x92, 0x39, 0x76, 0xc4, 0xe5, 0xcc, 0xd9, - 0xcb, 0xf9, 0x1a, 0x3c, 0x23, 0x43, 0x97, 0xfb, 0x9e, 0x69, 0x6e, 0xeb, + 0xcb, 0xf9, 0x1a, 0x3c, 0x23, 0x43, 0x97, 0xfb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x47, 0xeb, 0xc3, 0x01, 0x39, 0x50, 0x88, 0xb9, 0x17, 0xa2, 0x0d, - 0xa0, 0xe5, 0xd1, 0x39, 0xca, 0x91, 0xa7, 0xc1, 0x0b, 0xfb, 0xe9, 0x3c, + 0xa0, 0xe5, 0xd1, 0x39, 0xca, 0x91, 0xa7, 0xc1, 0x0b, 0xfb, 0x99, 0x3c, 0x90, 0x4e, 0x5e, 0x81, 0x98, 0xe5, 0x61, 0xe4, 0xaa, 0x5b, 0x73, 0xf8, - 0xe5, 0xde, 0xf1, 0xcb, 0x73, 0xc5, 0x48, 0x2b, 0x34, 0xf8, 0xa5, 0x07, + 0xe5, 0xde, 0xf1, 0xcb, 0x7d, 0xc5, 0x48, 0x2b, 0x34, 0xe4, 0xa5, 0x07, 0xd8, 0x2c, 0xf0, 0xa2, 0x15, 0x5f, 0x34, 0xb4, 0x22, 0xe0, 0x16, 0xbf, - 0xfd, 0xcd, 0x8f, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x37, 0xaf, 0xfe, - 0x63, 0xcb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x4f, 0xcb, 0xdc, 0x2e, 0xf2, + 0xfd, 0xf5, 0x8f, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x37, 0xaf, 0xfe, + 0x63, 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x4f, 0xcb, 0xdc, 0x2e, 0xf2, 0x39, 0x79, 0x6a, 0x30, 0xe5, 0xfb, 0x51, 0xd0, 0x41, 0xcb, 0xf7, 0x73, 0xd0, 0x13, 0x95, 0xc2, 0x1f, 0x62, 0x0f, 0x39, 0x3d, 0xc2, 0xb3, 0x97, 0xdb, 0x99, 0x9b, 0x39, 0x72, 0xd6, 0x72, 0xff, 0x2f, 0xa9, 0xec, 0xc6, 0x1c, 0xbb, 0x8a, 0xcf, 0x18, 0x12, 0xa1, 0x15, 0x28, 0x2d, 0xf9, 0x26, - 0xc5, 0xfc, 0x65, 0x7e, 0x6a, 0xb8, 0x46, 0x99, 0xf1, 0xcb, 0xf9, 0xa9, + 0xc5, 0xfc, 0x65, 0x7e, 0x6a, 0xb8, 0x46, 0x99, 0xc9, 0xcb, 0xf9, 0xa9, 0x79, 0xfa, 0x8d, 0x67, 0x2f, 0xcd, 0x5a, 0xaa, 0xe3, 0x59, 0xcb, 0xfb, 0xc8, 0x2d, 0xe0, 0x9c, 0xbb, 0x8a, 0xcf, 0x18, 0x0a, 0xdd, 0x39, 0x4d, 0x4a, 0x60, 0x1c, 0x21, 0xaf, 0x0b, 0x1b, 0x61, 0x97, 0x8b, 0x00, 0x4d, 0x7b, 0x4f, 0x87, 0x2f, 0x9c, 0x38, 0xc3, 0x94, 0xd5, 0x9b, 0xc6, 0xa2, 0x37, 0x7d, 0xc3, 0x4e, 0xcd, 0x9c, 0xbf, 0xff, 0x0b, 0xfa, 0x05, 0x68, 0xc0, 0x81, 0xf5, 0x23, 0x97, 0xe6, 0xfd, 0xe8, 0x61, 0xca, 0x6a, 0xcf, - 0xf2, 0x75, 0x3b, 0xfe, 0x7e, 0xa7, 0x1e, 0x6d, 0xb6, 0xd9, 0x4b, 0xfd, + 0xf2, 0x75, 0x3b, 0xfe, 0x7e, 0xa7, 0x1f, 0xad, 0xb6, 0xd9, 0x4b, 0xfd, 0xd7, 0xf7, 0x9d, 0xdb, 0x39, 0x5c, 0x32, 0x68, 0x0d, 0x46, 0x14, 0xad, 0x40, 0xa3, 0x85, 0x90, 0x2f, 0xff, 0xf3, 0x55, 0xc2, 0x6f, 0x50, 0x9e, 0xee, 0x05, 0x37, 0x83, 0xf9, 0xcb, 0xf9, 0xae, 0x34, 0xef, 0x23, 0x97, 0xee, 0xa3, 0xff, 0xc2, 0xc7, 0x29, 0xa9, 0x46, 0x47, 0x0a, 0x6a, 0xf1, - 0x7d, 0xff, 0xcd, 0x5b, 0x56, 0xd4, 0xcc, 0x30, 0x1c, 0xfb, 0xc7, 0x2f, + 0x7d, 0xff, 0xcd, 0x5b, 0x56, 0xd4, 0xcc, 0x30, 0x1c, 0xe7, 0xc7, 0x2f, 0x87, 0x13, 0xf3, 0x97, 0xdc, 0x2f, 0xfa, 0xb0, 0x72, 0xb8, 0x43, 0xcc, - 0xe1, 0x88, 0x6f, 0xfd, 0x11, 0x11, 0x11, 0x1f, 0x6c, 0xe5, 0xe9, 0xa3, - 0xc7, 0x2e, 0x88, 0x83, 0xd8, 0x98, 0xee, 0xf2, 0x7d, 0x87, 0x2f, 0xda, + 0xe1, 0x88, 0x6f, 0xfd, 0x11, 0x11, 0x11, 0x1c, 0xec, 0xe5, 0xe9, 0xa3, + 0xc7, 0x2e, 0x88, 0x83, 0xd8, 0x98, 0xee, 0xf2, 0x73, 0x87, 0x2f, 0xda, 0x49, 0xdd, 0x85, 0x2e, 0x6d, 0xb2, 0x95, 0x87, 0x82, 0xd9, 0x45, 0x80, - 0x53, 0x99, 0xa2, 0xbd, 0xdc, 0x59, 0xca, 0x84, 0x75, 0x7e, 0x59, 0xb7, - 0xf5, 0x08, 0xef, 0xc0, 0x69, 0x00, 0xf8, 0xe5, 0xf3, 0x8c, 0x70, 0x1c, + 0x53, 0xe9, 0xa2, 0xbd, 0xdc, 0x59, 0xca, 0x84, 0x75, 0x7e, 0x59, 0xb7, + 0xf5, 0x08, 0xef, 0xc0, 0x69, 0x00, 0xe4, 0xe5, 0xf3, 0x8c, 0x70, 0x1c, 0xac, 0x3c, 0xe7, 0x2b, 0xbf, 0xf8, 0x71, 0x91, 0xbd, 0xe4, 0x9a, 0x61, - 0xcb, 0xff, 0x3f, 0x97, 0xd4, 0x11, 0x8f, 0x8e, 0x52, 0x22, 0x07, 0xa8, + 0xcb, 0xff, 0x3f, 0x97, 0xd4, 0x11, 0x8e, 0x4e, 0x52, 0x22, 0x07, 0xa8, 0x97, 0xfb, 0x02, 0x9c, 0x77, 0xfa, 0xce, 0x5f, 0xff, 0xfb, 0x38, 0xa7, 0xa5, 0x9f, 0xec, 0x73, 0xfd, 0x44, 0xef, 0xa5, 0x9c, 0xba, 0x24, 0xe8, 0xa5, 0xd9, 0xb5, 0xfd, 0xed, 0xe6, 0x4f, 0x07, 0x2b, 0xa7, 0xb4, 0x25, @@ -2265,35 +2265,35 @@ 0x78, 0xe5, 0xee, 0xc0, 0x9c, 0xb4, 0x21, 0xe7, 0xf8, 0xd2, 0xa1, 0x32, 0xc5, 0x90, 0xa1, 0x1f, 0x61, 0x85, 0x78, 0x52, 0x0e, 0x5f, 0xa1, 0x46, 0x75, 0x0e, 0x56, 0x8f, 0x08, 0x46, 0xaf, 0xcf, 0x3c, 0x3a, 0xce, 0x5f, - 0xca, 0x72, 0x8d, 0xc3, 0x0e, 0x57, 0x4f, 0x5d, 0xc9, 0xef, 0xe9, 0x6f, + 0xca, 0x7c, 0x8d, 0xc3, 0x0e, 0x57, 0x4f, 0x5d, 0xc9, 0xef, 0xe9, 0x6f, 0xd8, 0x2a, 0x9c, 0xbf, 0xfa, 0x17, 0x9a, 0xce, 0xa6, 0xba, 0xe7, 0x2f, 0x36, 0xed, 0x9c, 0xbf, 0xfa, 0x35, 0x25, 0xf5, 0x26, 0x17, 0x6c, 0xe5, 0xff, 0xda, 0x79, 0xc3, 0xd8, 0xdf, 0x81, 0xd3, 0x95, 0xb4, 0x45, 0xf9, 0x16, 0xcc, 0xd2, 0x61, 0xdd, 0x42, 0xdc, 0x2a, 0x6f, 0xf2, 0x29, 0x0d, - 0x87, 0x18, 0x72, 0xb0, 0xfc, 0x3a, 0x79, 0x7f, 0xd1, 0xd8, 0xfa, 0x52, + 0x87, 0x18, 0x72, 0xb0, 0xfc, 0x3a, 0x79, 0x7f, 0xd1, 0xd8, 0xe6, 0x52, 0x89, 0xce, 0x5f, 0x2f, 0xa9, 0xa3, 0x95, 0xa3, 0xdc, 0x73, 0xab, 0xff, - 0xff, 0xc2, 0xea, 0xa6, 0xa2, 0x5c, 0xba, 0x8c, 0x0c, 0x72, 0x68, 0x0e, - 0xa6, 0x8e, 0x5f, 0x3c, 0x93, 0xe3, 0x97, 0xfc, 0x9e, 0xcd, 0x68, 0x13, + 0xff, 0xc2, 0xea, 0xa6, 0xa2, 0x5f, 0x3a, 0x8c, 0x0c, 0x7c, 0x68, 0x0e, + 0xa6, 0x8e, 0x5f, 0x3c, 0x93, 0x93, 0x97, 0xfc, 0x9e, 0xcd, 0x68, 0x13, 0xf1, 0x39, 0x7f, 0xdb, 0xcf, 0x07, 0x33, 0xfd, 0x9c, 0xae, 0x9f, 0xaf, - 0x8f, 0x2f, 0xf9, 0x3d, 0x9a, 0xd0, 0x27, 0xe2, 0x72, 0xf6, 0xc0, 0x3c, - 0x8f, 0x7b, 0xa4, 0x54, 0x15, 0x48, 0xba, 0x7d, 0xe9, 0x08, 0xbe, 0xee, + 0x8f, 0x2f, 0xf9, 0x3d, 0x9a, 0xd0, 0x27, 0xe2, 0x72, 0xf6, 0xc0, 0x3f, + 0x0f, 0x7b, 0xa4, 0x54, 0x15, 0x48, 0xba, 0x7d, 0xe9, 0x08, 0xbe, 0xee, 0x1e, 0xb7, 0xcc, 0x40, 0xc1, 0xcb, 0xf9, 0x3b, 0xad, 0x24, 0xe7, 0x2a, 0x0f, 0x3f, 0xa4, 0x37, 0x37, 0xe3, 0x97, 0xff, 0x22, 0x76, 0x6c, 0xf4, - 0x7a, 0x02, 0x72, 0xd0, 0x72, 0xff, 0xfa, 0x3e, 0x93, 0x8f, 0xfc, 0xbf, + 0x7a, 0x02, 0x72, 0xd0, 0x72, 0xff, 0xfa, 0x39, 0x93, 0x8f, 0xff, 0x3f, 0x4d, 0x22, 0xa7, 0x2a, 0x11, 0x7f, 0x30, 0xc3, 0x44, 0x3e, 0x01, 0x0b, 0xef, 0x6f, 0xa8, 0x72, 0xfa, 0x76, 0x24, 0x8e, 0x5f, 0x47, 0xea, 0x30, 0xe5, 0xf0, 0x81, 0xe4, 0x72, 0x96, 0x78, 0xbb, 0x24, 0xbf, 0xdd, 0x86, - 0x73, 0xff, 0xf8, 0x39, 0x50, 0x8c, 0x1c, 0x68, 0x42, 0x2b, 0xfa, 0x64, + 0x7d, 0xff, 0xf8, 0x39, 0x50, 0x8c, 0x1c, 0x68, 0x42, 0x2b, 0xfa, 0x64, 0xef, 0xb1, 0x67, 0x2b, 0x13, 0x3e, 0xd4, 0x38, 0xdc, 0xb6, 0xff, 0x05, - 0x48, 0x6b, 0xe8, 0x36, 0x72, 0xfd, 0xc0, 0x8c, 0xcf, 0x1c, 0xaf, 0x8f, + 0x48, 0x6b, 0xe8, 0x36, 0x72, 0xfd, 0xc0, 0x8c, 0xcf, 0x1c, 0xae, 0x4f, 0x89, 0x87, 0x17, 0xb7, 0x0d, 0x9c, 0xb9, 0xfa, 0x72, 0xf2, 0xb1, 0xe3, 0x97, 0xff, 0xe0, 0xf6, 0x34, 0x9f, 0xc2, 0x91, 0x30, 0xc3, 0x0e, 0x5f, 0xe5, 0x60, 0x7d, 0xb7, 0xe9, 0xca, 0x44, 0x44, 0xba, 0xb5, 0xf8, 0x71, 0xc6, 0x73, 0x95, 0x09, 0xa1, 0xe1, 0x1a, 0x0e, 0xb8, 0xb0, 0xc2, 0x9b, 0x64, 0x37, 0xfb, 0xb1, 0x3e, 0xa3, 0x02, 0x72, 0xff, 0xf8, 0x73, 0x8a, - 0xdf, 0x53, 0xbf, 0x9f, 0xef, 0xce, 0x54, 0x22, 0x19, 0xcc, 0xef, 0xf0, - 0xbc, 0xff, 0x4a, 0x38, 0x0e, 0x5f, 0xed, 0xf5, 0xd4, 0xec, 0x48, 0xe5, - 0x4e, 0x7d, 0x7f, 0x1b, 0xde, 0xcc, 0x98, 0xe5, 0xff, 0xfa, 0x6e, 0xc3, + 0xdf, 0x53, 0xbf, 0x9f, 0x9f, 0xce, 0x54, 0x22, 0x19, 0xcc, 0xef, 0xf0, + 0xbc, 0xfc, 0xca, 0x38, 0x0e, 0x5f, 0xed, 0xf5, 0xd4, 0xec, 0x48, 0xe5, + 0x4e, 0x7d, 0x7c, 0x9b, 0xde, 0xcc, 0x98, 0xe5, 0xff, 0xfa, 0x6e, 0xc3, 0x13, 0x49, 0xc1, 0x0a, 0x4f, 0x8d, 0x9c, 0xbf, 0xf2, 0x6a, 0x36, 0xa0, 0x8c, 0x68, 0xe5, 0xff, 0x44, 0x85, 0xfd, 0x24, 0xe2, 0x72, 0xf2, 0x91, 0xf9, 0xca, 0xe9, 0xeb, 0xec, 0xe6, 0xcd, 0x67, 0x2f, 0x7a, 0x58, 0x72, @@ -2305,29 +2305,29 @@ 0xe9, 0xca, 0x9c, 0xf1, 0x38, 0x97, 0x5e, 0xf2, 0x4c, 0x72, 0xa1, 0x15, 0x38, 0xcf, 0xb2, 0x5b, 0xfe, 0xd2, 0x6f, 0xae, 0xc8, 0x6b, 0x39, 0x7e, 0x86, 0xb4, 0x6d, 0x67, 0x2a, 0x1b, 0x30, 0xe9, 0xe1, 0x19, 0x28, 0x50, - 0x86, 0x52, 0x6e, 0x42, 0x0d, 0x6f, 0x1f, 0x10, 0xa4, 0xbf, 0x16, 0xb8, + 0x86, 0x52, 0x6e, 0x42, 0x0d, 0x6f, 0x1c, 0x90, 0xa4, 0xbf, 0x16, 0xb8, 0x4f, 0xcd, 0x0e, 0x0d, 0x47, 0x00, 0xc8, 0xf6, 0x7b, 0x0d, 0xe7, 0x84, 0x67, 0xe4, 0x83, 0x1d, 0xb6, 0xe1, 0x51, 0xe8, 0xcb, 0xf8, 0x97, 0x28, 0x77, 0x72, 0xbe, 0x39, 0x7f, 0xff, 0xcd, 0x47, 0x86, 0x8c, 0x6a, 0x1a, - 0xe1, 0xb8, 0x57, 0x16, 0xbe, 0x16, 0x07, 0x2e, 0x5d, 0x68, 0x72, 0xe4, + 0xe1, 0xb8, 0x57, 0x16, 0xbe, 0x16, 0x07, 0xcf, 0x9d, 0x68, 0x72, 0xe4, 0x83, 0x97, 0xa6, 0x51, 0x87, 0x2f, 0xfb, 0x3d, 0xbc, 0xf7, 0x73, 0xf3, 0x94, 0xa9, 0xf6, 0xb8, 0xa8, 0x8f, 0xdc, 0xe2, 0x72, 0xb4, 0x78, 0x6c, 0x2e, 0xbe, 0x8f, 0x63, 0x0e, 0x5f, 0xbd, 0x02, 0x9f, 0x9c, 0xbf, 0x68, - 0x1c, 0x7f, 0x6c, 0xe5, 0xfd, 0x8d, 0xbf, 0xec, 0xc3, 0x95, 0xc9, 0x14, - 0x78, 0x43, 0xd2, 0x71, 0x2d, 0xbf, 0xf4, 0x31, 0x3e, 0xd8, 0x26, 0x02, + 0x1c, 0x7f, 0x6c, 0xe5, 0xfd, 0x8d, 0xbf, 0xec, 0xc3, 0x95, 0xf1, 0x14, + 0x78, 0x43, 0xd2, 0x71, 0x2d, 0xbf, 0xf4, 0x31, 0x39, 0xd8, 0x26, 0x02, 0xa7, 0x2f, 0xe4, 0x1f, 0x77, 0x24, 0x72, 0xff, 0x0c, 0x36, 0xd3, 0x35, - 0x07, 0x2c, 0xdf, 0x24, 0x51, 0x49, 0x08, 0x25, 0x97, 0xed, 0x4f, 0x1e, + 0x07, 0x2c, 0xdf, 0xc4, 0x51, 0x49, 0x08, 0x25, 0x97, 0xed, 0x4f, 0x1e, 0xd9, 0xcb, 0xe7, 0xd3, 0xc8, 0xe5, 0xb5, 0x87, 0x94, 0x25, 0x37, 0x9b, - 0x6d, 0xb3, 0x97, 0xd3, 0x8a, 0x41, 0x4e, 0x66, 0x82, 0xff, 0x9a, 0xfa, - 0xe3, 0x20, 0xc4, 0xe7, 0x2f, 0x9f, 0xd0, 0x13, 0x97, 0x7d, 0x23, 0x97, - 0xf9, 0x58, 0xf6, 0xfa, 0xe0, 0x39, 0x7e, 0x49, 0xf3, 0xef, 0x1c, 0xb9, + 0x6d, 0xb3, 0x97, 0xd3, 0x8a, 0x41, 0x4f, 0xa6, 0x82, 0xff, 0x9a, 0xfa, + 0xe3, 0x20, 0xc4, 0xe7, 0x2f, 0x9f, 0xd0, 0x13, 0x97, 0x73, 0x23, 0x97, + 0xf9, 0x58, 0xf6, 0xfa, 0xe0, 0x39, 0x7e, 0x49, 0xf3, 0x9f, 0x1c, 0xb9, 0x16, 0x72, 0xa1, 0x11, 0x6a, 0x8c, 0x30, 0xd3, 0xc5, 0x37, 0xe5, 0x5f, - 0x7c, 0x64, 0x72, 0xbe, 0x3e, 0x8f, 0x1e, 0xde, 0xc0, 0x34, 0x39, 0x5c, + 0x7c, 0x64, 0x72, 0xb9, 0x3e, 0x8f, 0x1e, 0xde, 0xc0, 0x34, 0x39, 0x5c, 0x22, 0xec, 0x87, 0x0a, 0x18, 0x88, 0xd1, 0xc3, 0x0c, 0x5c, 0x86, 0xfa, 0x42, 0x0f, 0xa8, 0xce, 0x66, 0x27, 0x80, 0x8c, 0x51, 0xa1, 0x1d, 0xff, 0xdc, 0x5b, 0xcd, 0x8a, 0x46, 0xb2, 0x73, 0x97, 0xff, 0xff, 0xfe, 0x6b, - 0xe5, 0xdc, 0xfa, 0x5d, 0x67, 0x25, 0xf4, 0x1e, 0xf6, 0x0f, 0x73, 0xd0, - 0x1e, 0x5c, 0xba, 0xd0, 0xe5, 0xff, 0x07, 0x01, 0xc3, 0xa7, 0x5d, 0x87, + 0xf9, 0xdc, 0xe6, 0x5d, 0x67, 0xc5, 0xf4, 0x1e, 0xf6, 0x0f, 0x73, 0xd0, + 0x1f, 0x9f, 0x3a, 0xd0, 0xe5, 0xff, 0x07, 0x01, 0xc3, 0xa7, 0x5d, 0x87, 0x2f, 0xd0, 0xc1, 0xc9, 0x8e, 0x61, 0xbd, 0xbd, 0xc7, 0x02, 0x72, 0xfe, 0xea, 0x40, 0x82, 0x0e, 0x5f, 0xe8, 0x6b, 0x57, 0x36, 0xed, 0x67, 0x29, 0x53, 0xe4, 0xe9, 0x5d, 0x75, 0x14, 0xaf, 0x08, 0x2b, 0xee, 0xc2, 0x9d, @@ -2337,239 +2337,239 @@ 0x34, 0x79, 0xce, 0x5f, 0x03, 0xfc, 0x15, 0x9b, 0x90, 0x0b, 0xda, 0x47, 0x2a, 0x73, 0xc9, 0xe9, 0xc5, 0xff, 0xd1, 0xd5, 0x03, 0xe4, 0xc9, 0xa1, 0x87, 0x2f, 0xfd, 0xe4, 0x6d, 0x7d, 0x4e, 0x28, 0x13, 0x97, 0xfb, 0x52, - 0xee, 0x71, 0x86, 0x1c, 0xaf, 0x8f, 0xd9, 0x10, 0x6f, 0xcf, 0x2d, 0xa7, - 0x13, 0x97, 0xfd, 0x9a, 0xce, 0x59, 0xa8, 0x09, 0xcb, 0xfb, 0x25, 0xf4, + 0xee, 0x71, 0x86, 0x1c, 0xae, 0x4f, 0xd9, 0x10, 0x6f, 0xcf, 0x2d, 0xa7, + 0x13, 0x97, 0xfd, 0x9a, 0xcf, 0x99, 0xa8, 0x09, 0xcb, 0xfb, 0x25, 0xcc, 0xb3, 0xc7, 0x2d, 0xe9, 0x1f, 0x3f, 0x4e, 0x6f, 0xa3, 0xc0, 0x61, 0xca, 0x34, 0x41, 0xcb, 0xf9, 0xe7, 0xfd, 0xc4, 0x24, 0xac, 0x1a, 0xb6, 0xd6, 0x7a, 0x8d, 0x06, 0x29, 0x88, 0xa0, 0xf3, 0xb5, 0xff, 0xf9, 0x9b, 0x79, 0x75, 0x33, 0xdb, 0xd6, 0x07, 0x0e, 0x5f, 0xf4, 0x78, 0x73, 0x88, 0xe6, 0xce, 0x54, 0x22, 0xbf, 0x08, 0xf6, 0xa9, 0x7f, 0x3f, 0x61, 0xac, 0x12, 0x39, 0x52, 0x5c, 0xaa, 0x5c, 0x28, 0xf5, 0x0a, 0x26, 0x11, 0xf6, 0x17, - 0x7f, 0x91, 0x0c, 0x24, 0x3d, 0x1b, 0xbf, 0x12, 0xeb, 0xfa, 0x43, 0x9f, - 0x7b, 0x0e, 0x5f, 0xff, 0x94, 0xff, 0xf8, 0xfb, 0x27, 0x0b, 0xba, 0xdc, + 0x7f, 0x91, 0x0c, 0x24, 0x3d, 0x1b, 0xbf, 0x12, 0xeb, 0xfa, 0x43, 0x9c, + 0xfb, 0x0e, 0x5f, 0xff, 0x94, 0xff, 0xf8, 0xe7, 0x27, 0x0b, 0xba, 0xdc, 0x27, 0x2a, 0x11, 0x0d, 0xa2, 0xdb, 0xf8, 0x7d, 0x2c, 0xd6, 0x1c, 0xb9, 0xa3, 0x9c, 0xa7, 0x3c, 0x45, 0x0b, 0x2f, 0xf7, 0x71, 0x6f, 0xd8, 0xe9, 0xcb, 0xff, 0x9d, 0x3d, 0x02, 0xbc, 0xf7, 0x50, 0xe5, 0xfc, 0x29, 0xfe, 0xfa, 0x87, 0x2e, 0xd0, 0x4e, 0x5c, 0xdb, 0x67, 0x2a, 0x46, 0xc1, 0xb1, - 0x7b, 0xd0, 0x9c, 0x4a, 0x73, 0x34, 0x57, 0xfc, 0x82, 0x9f, 0xef, 0x3a, + 0x7b, 0xd0, 0x9c, 0x4a, 0x7d, 0x34, 0x57, 0xfc, 0x82, 0x9f, 0xef, 0x3a, 0xe7, 0x2b, 0x13, 0x58, 0xe9, 0x93, 0xa0, 0xed, 0xff, 0xc5, 0xf7, 0xf4, 0x0f, 0xbb, 0x92, 0x39, 0x77, 0xfb, 0x39, 0x7f, 0x27, 0x51, 0x55, 0x60, 0xe5, 0x94, 0x09, 0xe3, 0x78, 0x62, 0xb4, 0x89, 0xbd, 0xb9, 0x52, 0x26, - 0x0e, 0xa4, 0x39, 0x2f, 0x36, 0xdb, 0x65, 0x28, 0xa7, 0x33, 0x41, 0x7c, + 0x0e, 0xa4, 0x39, 0x2f, 0x36, 0xdb, 0x65, 0x28, 0xa7, 0xd3, 0x41, 0x7c, 0x8d, 0xa4, 0xc5, 0x29, 0x67, 0x80, 0x83, 0xb7, 0xec, 0xd4, 0x71, 0xc3, 0x95, 0x0c, 0xc0, 0xe9, 0xd1, 0xb2, 0x50, 0x62, 0x4e, 0x70, 0x6a, 0x32, 0x36, 0x33, 0x76, 0x54, 0x08, 0xc2, 0x27, 0x64, 0x37, 0xda, 0x90, 0x30, - 0xe5, 0xfe, 0x1f, 0xbc, 0xa7, 0x5f, 0xf3, 0x97, 0x85, 0x36, 0x72, 0xf8, - 0x2e, 0x3f, 0x9c, 0xbf, 0xfa, 0x07, 0xf1, 0x8f, 0xa6, 0x81, 0xfc, 0xe5, + 0xe5, 0xfe, 0x1e, 0x7c, 0xa7, 0x5f, 0xf3, 0x97, 0x85, 0x36, 0x72, 0xf8, + 0x2e, 0x3f, 0x9c, 0xbf, 0xfa, 0x07, 0xf1, 0x8e, 0x66, 0x81, 0xfc, 0xe5, 0x62, 0x2e, 0x10, 0xdb, 0xf1, 0xbd, 0x91, 0x5f, 0x4b, 0xf9, 0x09, 0xcb, 0xf4, 0xcd, 0x3f, 0x69, 0x87, 0x2c, 0x87, 0x2f, 0xf9, 0xd5, 0x5f, 0x50, - 0x2f, 0x23, 0x97, 0xd3, 0xce, 0xff, 0x1c, 0xbb, 0xfd, 0xa1, 0xf7, 0x08, + 0x2f, 0x23, 0x97, 0xd3, 0xce, 0xfc, 0x9c, 0xbb, 0xfd, 0xa1, 0xf7, 0x08, 0x82, 0x87, 0x37, 0xd9, 0xae, 0xa1, 0xcb, 0xff, 0xcf, 0x21, 0xce, 0x2f, 0x34, 0x67, 0xb6, 0x72, 0xa0, 0xfa, 0xdc, 0x86, 0xff, 0xf3, 0x7f, 0xf7, - 0x32, 0x74, 0xce, 0x31, 0xf1, 0xcb, 0xff, 0xdf, 0xc3, 0x35, 0xa8, 0x9f, + 0x32, 0x74, 0xce, 0x31, 0xc9, 0xcb, 0xff, 0xdf, 0xc3, 0x35, 0xa8, 0x9f, 0xce, 0xea, 0x9c, 0xbf, 0xd2, 0xce, 0xe3, 0x21, 0x67, 0x2f, 0x63, 0x1a, 0xce, 0x5f, 0xf9, 0xf8, 0xe2, 0x83, 0x1d, 0x49, 0xce, 0x5f, 0xec, 0xd8, 0xe7, 0xba, 0x87, 0x28, 0x28, 0x90, 0xd0, 0xf8, 0xa0, 0x56, 0x2a, 0x51, 0x9a, 0x14, 0xdd, 0x20, 0xfd, 0x3b, 0xc9, 0x9c, 0x61, 0x85, 0x7d, 0x2f, 0xf3, 0xf3, 0x97, 0xf7, 0xb2, 0x61, 0x86, 0x1e, 0x20, 0x25, 0xf0, 0x87, - 0xb0, 0x68, 0x80, 0x9c, 0xcd, 0xd5, 0x7c, 0x89, 0xe7, 0x5e, 0xbf, 0xf9, - 0x3e, 0xd8, 0x70, 0x60, 0x41, 0x07, 0x2f, 0xda, 0x40, 0x70, 0xf0, 0x72, - 0xff, 0x6b, 0x3e, 0xdf, 0xef, 0xe3, 0x97, 0x01, 0x70, 0x7c, 0x2a, 0x96, - 0x5f, 0xa2, 0x4f, 0xf3, 0x67, 0x2f, 0xfb, 0x96, 0xb5, 0x9d, 0xfa, 0x5b, - 0x39, 0x7f, 0xff, 0xb3, 0x60, 0x7f, 0xb3, 0x05, 0x5d, 0xef, 0x07, 0xdb, - 0x39, 0x4b, 0x44, 0xef, 0xc7, 0xb7, 0xe7, 0x6c, 0x2a, 0xf1, 0x39, 0x58, + 0xb0, 0x68, 0x80, 0x9f, 0x4d, 0xd5, 0x72, 0x89, 0xe7, 0x5e, 0xbf, 0xf9, + 0x39, 0xd8, 0x70, 0x60, 0x41, 0x07, 0x2f, 0xda, 0x40, 0x70, 0xf0, 0x72, + 0xff, 0x6b, 0x39, 0xdf, 0xef, 0xe3, 0x97, 0x01, 0x70, 0x7c, 0x2a, 0x96, + 0x5f, 0xa2, 0x4f, 0xcb, 0x67, 0x2f, 0xfb, 0xe6, 0xb5, 0x9d, 0xe6, 0x5b, + 0x39, 0x7f, 0xff, 0xb3, 0x60, 0x7e, 0x73, 0x05, 0x5d, 0xef, 0x07, 0xdb, + 0x39, 0x4b, 0x44, 0xef, 0x27, 0xb7, 0xe7, 0x6c, 0x2a, 0xf1, 0x39, 0x58, 0x9f, 0x3a, 0x42, 0x8f, 0x45, 0xcf, 0x0c, 0x61, 0x24, 0xb4, 0xe7, 0x2f, - 0xdc, 0xb2, 0x64, 0x61, 0xcb, 0xff, 0xc0, 0x8e, 0x5c, 0x1e, 0x4d, 0xf7, - 0xe7, 0x6c, 0xe5, 0x4e, 0x7f, 0x7b, 0x2a, 0xbf, 0xf6, 0x07, 0xaf, 0xce, - 0x3b, 0x1f, 0x1c, 0xae, 0x11, 0x1e, 0x1a, 0x84, 0x6b, 0x08, 0xef, 0xf8, + 0xdf, 0x32, 0x64, 0x61, 0xcb, 0xff, 0xc0, 0x8f, 0x9c, 0x1e, 0x4d, 0xf7, + 0x97, 0x6c, 0xe5, 0x4e, 0x7f, 0x7b, 0x2a, 0xbf, 0xf6, 0x07, 0xaf, 0xf6, + 0x3b, 0x1c, 0x9c, 0xae, 0x11, 0x1e, 0x1a, 0x84, 0x6b, 0x08, 0xef, 0xf8, 0x55, 0xd0, 0xa2, 0xc0, 0x27, 0x2f, 0xde, 0x8c, 0x18, 0x39, 0x48, 0x7b, 0xa2, 0x71, 0x79, 0x41, 0xf1, 0xcb, 0xc8, 0xc7, 0x39, 0x53, 0x9b, 0x85, - 0x47, 0x6f, 0xff, 0xcf, 0xf7, 0xdb, 0x81, 0xf2, 0x93, 0x75, 0x3d, 0xb3, + 0x47, 0x6f, 0xff, 0xcf, 0xcf, 0x3b, 0x81, 0xf2, 0x93, 0x75, 0x3d, 0xb3, 0x95, 0x09, 0xb5, 0xe4, 0x25, 0xd1, 0x60, 0x04, 0x77, 0xcc, 0x8c, 0x61, - 0xcb, 0xff, 0x63, 0x21, 0x69, 0xed, 0x01, 0x87, 0x2f, 0x27, 0xdb, 0x39, + 0xcb, 0xff, 0x63, 0x21, 0x69, 0xed, 0x01, 0x87, 0x2f, 0x27, 0x3b, 0x39, 0x52, 0x3d, 0xbf, 0xcf, 0xaf, 0xb4, 0xf2, 0x98, 0xe5, 0xfb, 0x7b, 0x8f, 0xda, 0x93, 0x94, 0xa9, 0xe8, 0xb6, 0x47, 0x50, 0x89, 0x87, 0x74, 0xbf, - 0xda, 0x9b, 0x68, 0x3e, 0x43, 0x97, 0xfb, 0xa9, 0xf7, 0xfa, 0x70, 0x9c, - 0xbe, 0xfb, 0xfd, 0x41, 0x4b, 0x9b, 0x6c, 0xa5, 0x41, 0xbd, 0x6c, 0x92, - 0xe1, 0x42, 0x9c, 0xcd, 0x0d, 0xff, 0xff, 0xc3, 0xcf, 0x33, 0x82, 0x26, - 0x46, 0x44, 0xdc, 0x87, 0xe9, 0x74, 0x1f, 0x9c, 0xa3, 0x97, 0x9f, 0x52, - 0xe4, 0x9a, 0x04, 0xa1, 0x27, 0xf1, 0x3f, 0xef, 0x77, 0xf3, 0x8c, 0x96, + 0xda, 0x9b, 0x68, 0x3e, 0x43, 0x97, 0xfb, 0xa9, 0xcf, 0xfa, 0x70, 0x9c, + 0xbe, 0xe7, 0xfd, 0x41, 0x4b, 0x9b, 0x6c, 0xa5, 0x41, 0xbd, 0x6c, 0x92, + 0xe1, 0x42, 0x9f, 0x4d, 0x0d, 0xff, 0xff, 0xc3, 0xf7, 0x33, 0x82, 0x26, + 0x46, 0x44, 0xdf, 0x07, 0x99, 0x74, 0x1f, 0x9c, 0xa3, 0x97, 0x9f, 0x52, + 0xf8, 0x9a, 0x04, 0xa1, 0x27, 0xc9, 0x3f, 0xef, 0x77, 0xf3, 0x8c, 0x96, 0x09, 0xce, 0x53, 0x56, 0xcd, 0x4e, 0x88, 0x6d, 0x4e, 0x79, 0x22, 0x3c, 0x95, 0xda, 0x91, 0x82, 0x6a, 0x50, 0x57, 0x65, 0x56, 0x3a, 0x00, 0xc6, 0x29, 0xe2, 0x10, 0x46, 0xe6, 0xda, 0xc5, 0xef, 0x23, 0x67, 0x2f, 0x4e, 0xec, 0x39, 0x72, 0x04, 0xe5, 0xef, 0x23, 0x67, 0x8c, 0x21, 0x78, 0x0e, - 0xa1, 0xa2, 0x07, 0x7c, 0x6a, 0xab, 0xa7, 0xf7, 0xe4, 0x0a, 0x74, 0x5d, + 0xa1, 0xa2, 0x07, 0x72, 0x6a, 0xab, 0xa7, 0xf7, 0xe4, 0x0a, 0x74, 0x5d, 0x02, 0x13, 0x17, 0x87, 0x5c, 0x39, 0xcb, 0xfd, 0x8b, 0x89, 0xc6, 0x16, - 0x72, 0xdf, 0x9c, 0xb3, 0x5f, 0x23, 0xc4, 0x43, 0x2b, 0xa0, 0x07, 0x2f, - 0xc0, 0x1f, 0xd4, 0x91, 0xcb, 0xff, 0xe1, 0xcd, 0xf2, 0x53, 0xb1, 0xfb, - 0x1e, 0x5c, 0xb0, 0xf0, 0x36, 0x2d, 0x40, 0x46, 0xbf, 0x16, 0xcb, 0xff, - 0x74, 0x13, 0xc7, 0x28, 0xf4, 0x04, 0xe5, 0xe7, 0xd4, 0xe7, 0x2e, 0x6d, - 0xb3, 0x97, 0xfb, 0x49, 0x9c, 0x54, 0x97, 0x35, 0x9b, 0x66, 0xc7, 0x6f, - 0xfc, 0x8a, 0xf2, 0xd8, 0x3f, 0x64, 0x48, 0xe5, 0xfe, 0xde, 0x79, 0xd9, + 0x72, 0xdf, 0x9c, 0xb3, 0x5f, 0xc3, 0xc4, 0x43, 0x2b, 0xa0, 0x07, 0x2f, + 0xc0, 0x1f, 0xd4, 0x91, 0xcb, 0xff, 0xe1, 0xcd, 0xfc, 0x53, 0xb1, 0xfb, + 0x1e, 0x5f, 0x30, 0xf0, 0x36, 0x2d, 0x40, 0x46, 0xbf, 0x16, 0xcb, 0xff, + 0x74, 0x13, 0xc7, 0xc8, 0xf4, 0x04, 0xe5, 0xe7, 0xd4, 0xe7, 0x2e, 0x6d, + 0xb3, 0x97, 0xfb, 0x49, 0x9c, 0x54, 0x97, 0xd5, 0x9b, 0x66, 0xc7, 0x6f, + 0xfc, 0x8a, 0xfc, 0xd8, 0x3f, 0x64, 0x48, 0xe5, 0xfe, 0xde, 0x79, 0xd9, 0x82, 0x72, 0x82, 0x99, 0xd6, 0x9d, 0xfa, 0x9f, 0xe4, 0x3b, 0xff, 0x6f, 0x07, 0x3b, 0x8b, 0xc1, 0x39, 0x7f, 0xd2, 0xdf, 0xbb, 0x8c, 0xc9, 0x1c, - 0xbf, 0xf6, 0x2b, 0xd7, 0x92, 0x8f, 0xf4, 0x1c, 0xa9, 0x22, 0xd1, 0x0e, + 0xbf, 0xf6, 0x2b, 0xd7, 0x92, 0x8f, 0xcc, 0x1c, 0xa9, 0x22, 0xd1, 0x0e, 0xc4, 0xe6, 0xa1, 0x32, 0x0c, 0x87, 0x95, 0xff, 0xcc, 0x63, 0xcb, 0x34, 0xb7, 0x75, 0x9a, 0x21, 0x85, 0xff, 0xff, 0xe7, 0xde, 0x0e, 0x2f, 0xb1, - 0xf4, 0x9a, 0x67, 0x56, 0x98, 0x2e, 0xa9, 0xca, 0xc4, 0x63, 0x81, 0x42, + 0xcc, 0x9a, 0x67, 0x56, 0x98, 0x2e, 0xa9, 0xca, 0xc4, 0x63, 0x81, 0x42, 0xa1, 0x73, 0x2d, 0x23, 0x3c, 0xec, 0xa7, 0xf1, 0x87, 0x75, 0xf8, 0x63, - 0xff, 0xbf, 0x39, 0x7f, 0x75, 0xe7, 0x18, 0x91, 0x4b, 0xff, 0x7b, 0xae, + 0xfe, 0x7f, 0x39, 0x7f, 0x75, 0xe7, 0x18, 0x91, 0x4b, 0xff, 0x7b, 0xae, 0x9e, 0x8d, 0x47, 0xe7, 0x2f, 0xdd, 0x71, 0x52, 0x73, 0x95, 0x24, 0x5f, 0x30, 0xa8, 0x4b, 0x5b, 0x3e, 0xbf, 0xf2, 0x2e, 0x36, 0xfa, 0xd2, 0x36, 0x72, 0xff, 0xfb, 0x7f, 0xa6, 0x95, 0x5f, 0x53, 0xa2, 0x09, 0xce, 0x5d, - 0xb0, 0x1c, 0xbf, 0xa5, 0xd7, 0x71, 0x83, 0x96, 0x85, 0x9e, 0x17, 0xc2, + 0xb0, 0x1c, 0xbf, 0xa5, 0xd7, 0x71, 0x83, 0x96, 0x85, 0x9e, 0x17, 0x22, 0xf7, 0xff, 0x67, 0xa3, 0xa9, 0x8a, 0xab, 0x12, 0x39, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0x82, 0x97, 0xbb, 0x0c, 0x39, 0x7f, 0xe8, 0x9d, 0xfd, 0xac, 0x93, 0x4c, 0x39, 0x41, 0x46, 0xa6, 0x22, 0x21, 0xa0, 0x8e, 0x5f, 0xbb, - 0x0c, 0x07, 0xc7, 0x2f, 0xbd, 0xb8, 0xfc, 0xa5, 0xe7, 0xd4, 0xe5, 0x2f, + 0x0c, 0x07, 0x27, 0x2f, 0xbd, 0xb8, 0xfc, 0xa5, 0xe7, 0xd4, 0xe5, 0x2f, 0x80, 0x2e, 0xa9, 0x4b, 0xfc, 0x93, 0xe7, 0xb7, 0x1f, 0x94, 0xa2, 0x97, 0xf6, 0x2e, 0x3b, 0x0c, 0x29, 0x73, 0x6d, 0x94, 0xbf, 0x86, 0x06, 0x74, 0xd1, 0x4a, 0xc4, 0xc4, 0x96, 0x46, 0xc1, 0xde, 0x91, 0x7e, 0x68, 0x21, - 0x6d, 0x96, 0x28, 0x33, 0x72, 0x68, 0xa7, 0x33, 0xf3, 0xa9, 0x2a, 0x11, - 0x98, 0xeb, 0xb1, 0xd7, 0x5f, 0xff, 0xa1, 0xbd, 0x8e, 0x7d, 0xe7, 0x19, - 0xf3, 0xef, 0x1c, 0xa8, 0x5c, 0xad, 0xc3, 0xd4, 0x3e, 0xec, 0x25, 0x5e, + 0x6d, 0x96, 0x28, 0x33, 0x72, 0x68, 0xa7, 0xd3, 0xf3, 0xa9, 0x2a, 0x11, + 0x98, 0xeb, 0xb1, 0xd7, 0x5f, 0xff, 0xa1, 0xbd, 0x8e, 0x73, 0xe7, 0x19, + 0xf3, 0x9f, 0x1c, 0xa8, 0x5c, 0xad, 0xc3, 0xd4, 0x3e, 0xec, 0x25, 0x5e, 0x58, 0x68, 0x9c, 0xde, 0x63, 0x84, 0xe5, 0xff, 0xff, 0x0e, 0x7b, 0xd1, - 0xf4, 0xb9, 0x76, 0x18, 0x0f, 0xb7, 0xd8, 0x39, 0x7f, 0x60, 0xed, 0x07, + 0xcc, 0xbe, 0x76, 0x18, 0x0e, 0x77, 0xd8, 0x39, 0x7f, 0x60, 0xed, 0x07, 0x0e, 0x5e, 0xe8, 0x18, 0x72, 0x95, 0x46, 0x6b, 0x58, 0xe7, 0x5a, 0xb8, 0x0a, 0xaf, 0xf3, 0x8e, 0x6f, 0x51, 0xb3, 0x97, 0xf0, 0x70, 0x5f, 0xdb, - 0x39, 0x52, 0x3d, 0xdd, 0x98, 0xdf, 0xda, 0xe4, 0xf3, 0x67, 0x4e, 0x54, - 0x1e, 0x92, 0x11, 0x5f, 0xb5, 0xf4, 0xb3, 0xc7, 0x2f, 0xff, 0x9d, 0x3f, - 0xde, 0x2a, 0xec, 0xd4, 0x60, 0x9c, 0xbf, 0x79, 0x33, 0xef, 0x1c, 0xbf, + 0x39, 0x52, 0x3d, 0xdd, 0x98, 0xdf, 0xda, 0xf8, 0xf3, 0x67, 0x4e, 0x54, + 0x1e, 0x92, 0x11, 0x5f, 0xb5, 0xcc, 0xb3, 0xc7, 0x2f, 0xff, 0x9d, 0x3f, + 0xde, 0x2a, 0xec, 0xd4, 0x60, 0x9c, 0xbf, 0x79, 0x33, 0x9f, 0x1c, 0xbf, 0xff, 0xee, 0xa6, 0xb0, 0x2e, 0xcc, 0x1f, 0x0c, 0x37, 0x9e, 0xd9, 0xcb, 0x41, 0xcb, 0xe8, 0xe2, 0x18, 0x59, 0xfa, 0x7e, 0xc9, 0x7f, 0xe7, 0x97, 0x5f, 0xdb, 0xc1, 0x91, 0xca, 0xe9, 0xfc, 0x78, 0xee, 0xb4, 0x9d, 0x6f, 0x4a, 0x76, 0x9d, 0xe8, 0xc5, 0x2f, 0x2f, 0x18, 0x72, 0xfe, 0x0b, 0xfb, 0x60, 0x91, 0xcb, 0xa4, 0xd2, 0x0f, 0x29, 0x41, 0xcb, 0xf9, 0xf5, 0x1e, - 0x4e, 0x27, 0x2b, 0xe3, 0xde, 0x13, 0x0b, 0xff, 0xff, 0x6b, 0x51, 0xf4, - 0xbe, 0xda, 0x69, 0x7d, 0xc5, 0x34, 0x90, 0x13, 0x97, 0xfc, 0xfa, 0xcf, - 0xa5, 0x1f, 0xc1, 0xca, 0x84, 0x65, 0x61, 0x10, 0x1b, 0xef, 0xff, 0xcb, - 0x55, 0xf7, 0x9a, 0x92, 0x75, 0xc7, 0xe9, 0x1c, 0xbf, 0xf2, 0xe3, 0xdb, - 0xcf, 0x27, 0xcd, 0x9c, 0xb3, 0xe2, 0x25, 0x95, 0x56, 0xa8, 0x55, 0x45, + 0x4e, 0x27, 0x2b, 0x93, 0xde, 0x13, 0x0b, 0xff, 0xff, 0x6b, 0x51, 0xcc, + 0xb9, 0xda, 0x69, 0x7d, 0xc5, 0x34, 0x90, 0x13, 0x97, 0xfc, 0xfa, 0xce, + 0x65, 0x1f, 0xc1, 0xca, 0x84, 0x65, 0x61, 0x10, 0x1b, 0xef, 0xff, 0xcb, + 0x55, 0xf7, 0x9a, 0x92, 0x75, 0xc7, 0x99, 0x1c, 0xbf, 0xf2, 0xe3, 0xdb, + 0xcf, 0x27, 0x2d, 0x9c, 0xb3, 0xe2, 0x25, 0x95, 0x56, 0xa8, 0x55, 0x45, 0xd8, 0xed, 0x86, 0x18, 0x97, 0xed, 0x88, 0x38, 0xc8, 0xe5, 0xe9, 0xd4, 0x59, 0xca, 0x83, 0xc9, 0x72, 0xab, 0x9f, 0xf3, 0x95, 0x23, 0x6f, 0xe2, - 0x0b, 0xff, 0xf3, 0xbc, 0x9f, 0xbc, 0xb2, 0x70, 0x78, 0x0e, 0xa1, 0xa2, + 0x0b, 0xff, 0xf3, 0xbc, 0x9f, 0xbf, 0x32, 0x70, 0x78, 0x0e, 0xa1, 0xa2, 0xfb, 0x5e, 0xfe, 0x02, 0x72, 0xfe, 0x75, 0xc0, 0xc7, 0xe7, 0x2f, 0xfd, - 0xb4, 0x1f, 0xa5, 0xa0, 0x46, 0xce, 0x54, 0xc8, 0xed, 0xd3, 0x2f, 0x47, + 0xb4, 0x1e, 0x65, 0xa0, 0x46, 0xce, 0x54, 0xc8, 0xed, 0xd3, 0x2f, 0x47, 0x7c, 0x59, 0x7e, 0xee, 0x4d, 0x0d, 0x67, 0x2f, 0xc1, 0xd6, 0xb1, 0xb3, 0x96, 0x89, 0xcf, 0x50, 0x4a, 0xec, 0xb3, 0x97, 0xff, 0xfb, 0xf4, 0xd2, 0xbd, 0x86, 0x4d, 0x24, 0x1e, 0xc6, 0xa0, 0xe5, 0xbd, 0x87, 0xe7, 0xb1, 0x1b, 0xef, 0x0e, 0x48, 0xe5, 0x41, 0xe4, 0x21, 0x3d, 0xff, 0x85, 0x25, 0xee, 0xe6, 0x93, 0x67, 0x2f, 0xd2, 0x1c, 0xc9, 0xce, 0x5d, 0xa9, 0xce, 0x54, 0x1b, 0xfc, 0x27, 0xbf, 0xce, 0x18, 0xfe, 0x1b, 0xd9, 0xca, 0xe9, - 0xe9, 0xb8, 0xfd, 0xfc, 0xd1, 0xa8, 0x72, 0xe5, 0xd6, 0x87, 0x88, 0x05, + 0xe9, 0xb8, 0xfd, 0xfc, 0xd1, 0xa8, 0x7c, 0xf9, 0xd6, 0x87, 0x88, 0x05, 0x7f, 0xbd, 0xfa, 0x83, 0x2e, 0xe1, 0xe2, 0x01, 0x5e, 0x7d, 0x48, 0xf1, 0x00, 0xab, 0x0f, 0xac, 0x08, 0x57, 0x3c, 0x8f, 0x10, 0x0a, 0xf9, 0xc7, - 0xe9, 0x1e, 0x20, 0x15, 0xfe, 0x45, 0xf7, 0x3f, 0xfe, 0x0f, 0x10, 0x0a, + 0x99, 0x1e, 0x20, 0x15, 0xfe, 0x45, 0xf7, 0x3f, 0xfe, 0x0f, 0x10, 0x0a, 0xf2, 0x08, 0x4f, 0x10, 0x0a, 0x82, 0x8b, 0xb6, 0x11, 0xf4, 0xbf, 0x8a, 0x0d, 0x95, 0x3c, 0x40, 0x2b, 0xda, 0x8f, 0x1e, 0x20, 0x15, 0x1e, 0x20, 0x15, 0xe6, 0x89, 0xf9, 0xe2, 0x01, 0x5d, 0x0c, 0x3c, 0x40, 0x2a, 0x09, 0xf3, 0xe0, 0xc2, 0x16, 0x5f, 0x23, 0x03, 0x07, 0x88, 0x05, 0x7b, 0xce, - 0xb3, 0xc4, 0x02, 0xbf, 0xf0, 0xbc, 0xb9, 0xf5, 0x16, 0xfa, 0x3c, 0x40, + 0xb3, 0xc4, 0x02, 0xbf, 0xf0, 0xbc, 0xbe, 0xf5, 0x16, 0xfa, 0x3c, 0x40, 0x2b, 0xff, 0x9f, 0xc0, 0x9d, 0x07, 0xdd, 0x79, 0x1e, 0x20, 0x15, 0xce, 0x13, 0xc4, 0x02, 0xbf, 0xc2, 0xed, 0xef, 0x71, 0xf9, 0xe2, 0x01, 0x5f, 0x91, 0x57, 0x1f, 0xcf, 0x10, 0x0a, 0xe4, 0xd9, 0xe2, 0x01, 0x56, 0x8f, - 0x63, 0xc6, 0xb7, 0xff, 0xba, 0x9e, 0xf6, 0x6f, 0x96, 0x92, 0x18, 0x78, - 0x80, 0x57, 0xef, 0x0c, 0x7d, 0x23, 0x44, 0x02, 0xbb, 0xf8, 0x3c, 0x40, - 0x2e, 0x66, 0xd6, 0xfc, 0x90, 0xc7, 0x09, 0xe2, 0x01, 0x5f, 0x01, 0xc5, - 0x67, 0x88, 0x05, 0x7a, 0x34, 0xb3, 0xc4, 0x02, 0xbf, 0xf6, 0x7d, 0xb0, + 0x63, 0xc6, 0xb7, 0xff, 0xba, 0x9e, 0xf6, 0x6f, 0xe6, 0x92, 0x18, 0x78, + 0x80, 0x57, 0xef, 0x0c, 0x73, 0x23, 0x44, 0x02, 0xbb, 0xf8, 0x3c, 0x40, + 0x2f, 0xa6, 0xd6, 0xfc, 0x90, 0xc7, 0x09, 0xe2, 0x01, 0x5f, 0x01, 0xc5, + 0x67, 0x88, 0x05, 0x7a, 0x34, 0xb3, 0xc4, 0x02, 0xbf, 0xf6, 0x73, 0xb0, 0xc6, 0x0f, 0xfb, 0x3c, 0x40, 0x2b, 0xf0, 0x1e, 0x52, 0x83, 0xc4, 0x02, - 0xbf, 0x3a, 0xfb, 0x1f, 0x1e, 0x20, 0x15, 0x62, 0x2d, 0x7a, 0x98, 0x03, + 0xbf, 0x3a, 0xfb, 0x1c, 0x9e, 0x20, 0x15, 0x62, 0x2d, 0x7a, 0x98, 0x03, 0x4b, 0xb5, 0xf9, 0xe2, 0x01, 0x54, 0x95, 0x9a, 0x04, 0x8f, 0x21, 0x32, 0xb2, 0x24, 0x84, 0x6f, 0x4d, 0xbf, 0x33, 0xd9, 0x77, 0xa1, 0xbc, 0x02, - 0xfb, 0xf6, 0x7b, 0x6f, 0xf1, 0xe2, 0x01, 0x5f, 0xe0, 0xc2, 0xe6, 0xd4, + 0xfb, 0xf6, 0x7b, 0x6f, 0xc9, 0xe2, 0x01, 0x5f, 0xe0, 0xc2, 0xe6, 0xd4, 0x78, 0xf1, 0x00, 0x82, 0x6d, 0x6f, 0x6a, 0x1b, 0x3c, 0x40, 0x2a, 0x59, 0xfd, 0xe9, 0x46, 0xff, 0x01, 0xe5, 0x28, 0x51, 0x87, 0x88, 0x05, 0x7c, - 0x83, 0x2d, 0x9e, 0x20, 0x15, 0xfc, 0xf3, 0x4b, 0x3e, 0x91, 0xe2, 0x01, - 0x56, 0x23, 0x37, 0xa4, 0x5f, 0xa0, 0x80, 0xba, 0xff, 0xbb, 0x1b, 0xe7, + 0x83, 0x2d, 0x9e, 0x20, 0x15, 0xfc, 0xf3, 0x4b, 0x39, 0x91, 0xe2, 0x01, + 0x56, 0x23, 0x37, 0xa4, 0x5f, 0xa0, 0x80, 0xba, 0xff, 0xbb, 0x1b, 0xfb, 0xb0, 0x6b, 0xf3, 0xc4, 0x02, 0xb2, 0x1e, 0x20, 0x15, 0xcf, 0x38, 0x4f, - 0x9f, 0xa9, 0x57, 0x6b, 0xf3, 0xc4, 0x02, 0xbf, 0x3f, 0xb6, 0x9f, 0x1e, + 0x9f, 0xa9, 0x57, 0x6b, 0xf3, 0xc4, 0x02, 0xbf, 0x3f, 0xb6, 0x9c, 0x9e, 0x20, 0x15, 0xfc, 0x82, 0x09, 0x66, 0xcf, 0x10, 0x0a, 0xa1, 0x12, 0x62, 0x4b, 0xe3, 0x5a, 0x86, 0x53, 0xf8, 0x61, 0x6b, 0x90, 0xdc, 0x43, 0xf9, 0x87, 0xf5, 0x09, 0x0e, 0x96, 0xb9, 0x77, 0xe5, 0x22, 0x99, 0xb9, 0x70, 0xbe, 0x94, 0x30, 0xd2, 0x14, 0x8a, 0x43, 0x06, 0xf7, 0x91, 0xb3, 0xc6, - 0x12, 0xbc, 0xee, 0xb3, 0x44, 0x02, 0xe6, 0x98, 0xa7, 0xd0, 0xea, 0xbe, + 0x12, 0xbc, 0xee, 0xb3, 0x44, 0x02, 0xfa, 0x98, 0xa7, 0x30, 0xea, 0xbe, 0x57, 0x85, 0xc2, 0xc3, 0x97, 0x71, 0x9c, 0xe5, 0xfd, 0x3c, 0x6b, 0xae, 0xd6, 0x72, 0xfd, 0xc4, 0x60, 0x3d, 0x39, 0x50, 0x7e, 0x98, 0x34, 0x86, 0x37, 0xff, 0x48, 0x71, 0x7d, 0x4f, 0xff, 0x04, 0xc7, 0x2f, 0xde, 0xc0, 0xbf, 0x4e, 0x5d, 0xfc, 0x14, 0xb2, 0xa5, 0x2f, 0x76, 0x27, 0x39, 0x73, 0x6d, 0x94, 0xa4, 0x3d, 0xf6, 0xb1, 0x79, 0x84, 0x9b, 0x1d, 0xb6, 0xca, - 0x73, 0x3c, 0x0b, 0x33, 0x11, 0xd4, 0x90, 0xc6, 0xbf, 0xbd, 0xbc, 0x6f, + 0x7d, 0x3c, 0x0b, 0x33, 0x11, 0xd4, 0x90, 0xc6, 0xbf, 0xbd, 0xbc, 0x6f, 0xa8, 0x72, 0xde, 0x39, 0x64, 0xf1, 0xbf, 0x01, 0x75, 0xff, 0xef, 0x6f, - 0x15, 0x4d, 0x29, 0xff, 0xf1, 0xf1, 0xca, 0x9d, 0x9f, 0x9f, 0x22, 0x00, + 0x15, 0x4d, 0x29, 0xff, 0xf1, 0xc9, 0xca, 0x9d, 0x9f, 0x9f, 0x22, 0x00, 0xc3, 0x3d, 0x74, 0xbb, 0x44, 0x50, 0xd4, 0x27, 0xdc, 0xb3, 0xf8, 0xcc, 0x7c, 0xd6, 0xa1, 0x35, 0xff, 0x64, 0x90, 0x2e, 0xbd, 0xc8, 0xe5, 0xff, 0x31, 0x05, 0x69, 0xa4, 0xfc, 0xe5, 0x2c, 0xfc, 0x3a, 0x71, 0x79, 0x7d, 0x13, 0x97, 0xff, 0x79, 0xa6, 0x4d, 0x27, 0xd4, 0xe1, 0x83, 0x94, 0xc3, 0xe4, 0x11, 0xcb, 0x87, 0xf3, 0x97, 0x46, 0xce, 0x5e, 0xf2, 0x9c, 0x50, - 0xd6, 0xf1, 0x17, 0xbf, 0xd9, 0xf7, 0xbc, 0xf2, 0xd9, 0xcb, 0xd2, 0xe1, - 0xe4, 0x72, 0xef, 0xa4, 0x78, 0xc0, 0x15, 0xf1, 0xe3, 0x89, 0x15, 0xff, + 0xd6, 0xf1, 0x17, 0xbf, 0xd9, 0xcf, 0xbc, 0xf2, 0xd9, 0xcb, 0xd2, 0xe1, + 0xe4, 0x72, 0xee, 0x64, 0x78, 0xc0, 0x15, 0xc9, 0xe3, 0x89, 0x15, 0xff, 0xfa, 0x33, 0xbb, 0x17, 0xf0, 0x3c, 0x1e, 0xa2, 0xa7, 0x2a, 0x13, 0xfd, 0xc8, 0x43, 0x22, 0x76, 0x8d, 0xdd, 0xec, 0x48, 0xaf, 0xff, 0xc2, 0x20, - 0xfb, 0x3e, 0xf0, 0x74, 0xff, 0x64, 0xe7, 0x2f, 0xd9, 0xed, 0x46, 0xce, + 0xe7, 0x39, 0xf0, 0x74, 0xfc, 0xe4, 0xe7, 0x2f, 0xd9, 0xed, 0x46, 0xce, 0x52, 0x1f, 0xf8, 0xac, 0x5f, 0xa6, 0x94, 0x6a, 0x73, 0x97, 0xd0, 0xac, - 0x30, 0xe5, 0x48, 0xfb, 0x34, 0x40, 0xc2, 0xab, 0xff, 0x4b, 0x7c, 0x87, - 0x19, 0x1a, 0x54, 0xe5, 0xfb, 0x97, 0x2c, 0xeb, 0x9c, 0xbf, 0xa5, 0x1a, + 0x30, 0xe5, 0x48, 0xfb, 0x34, 0x40, 0xc2, 0xab, 0xff, 0x4b, 0x7f, 0x07, + 0x19, 0x1a, 0x54, 0xe5, 0xfb, 0xe7, 0xcc, 0xeb, 0x9c, 0xbf, 0xa5, 0x1a, 0xfd, 0x46, 0x1c, 0xbf, 0xfb, 0x88, 0xe6, 0xfd, 0x83, 0x2c, 0xd9, 0xcb, 0xe6, 0x40, 0x3c, 0x72, 0xb0, 0xf9, 0x9d, 0x12, 0xfc, 0xfe, 0xf3, 0xe8, 0xe5, 0xef, 0x38, 0x9c, 0xb3, 0xe2, 0x3e, 0x06, 0x12, 0xdb, 0x20, 0xe0, - 0x27, 0xae, 0x49, 0xb5, 0xf6, 0x32, 0x3b, 0xfe, 0x86, 0xb0, 0xf6, 0x27, + 0x27, 0xaf, 0x89, 0xb5, 0xf6, 0x32, 0x3b, 0xfe, 0x86, 0xb0, 0xf6, 0x27, 0x71, 0x39, 0x7f, 0xd0, 0xb8, 0x62, 0x33, 0xf4, 0x39, 0x5a, 0x44, 0xff, 0x4b, 0x38, 0x0e, 0xef, 0xe5, 0x1b, 0xd2, 0x67, 0x4a, 0x5f, 0xb7, 0xd8, - 0xc9, 0xce, 0x5f, 0xfd, 0xf8, 0xa6, 0x7d, 0xe9, 0xa4, 0xfa, 0x39, 0x7d, - 0x37, 0x5e, 0x63, 0x97, 0xcb, 0x7d, 0x4e, 0x72, 0xfd, 0x93, 0x4a, 0x3e, + 0xc9, 0xce, 0x5f, 0xfd, 0xf8, 0xa6, 0x73, 0xe9, 0xa4, 0xfa, 0x39, 0x7d, + 0x37, 0x5e, 0x63, 0x97, 0xcb, 0x7d, 0x4e, 0x72, 0xfd, 0x93, 0x4a, 0x39, 0x39, 0x72, 0x4c, 0x72, 0xfe, 0xde, 0x68, 0x3d, 0xc3, 0x95, 0xd3, 0xc4, 0xd8, 0xbd, 0xe1, 0x89, 0x14, 0xbf, 0xf0, 0xfe, 0x9c, 0x1c, 0x00, 0x94, - 0x35, 0x9c, 0xac, 0x3e, 0x37, 0x1b, 0xae, 0x49, 0xe3, 0xfc, 0x51, 0xa4, + 0x35, 0x9c, 0xac, 0x3e, 0x37, 0x1b, 0xaf, 0x89, 0xe3, 0xf2, 0x51, 0xa4, 0x6e, 0x92, 0x09, 0x1f, 0x9b, 0x78, 0x21, 0x0b, 0x50, 0xba, 0x25, 0x85, - 0xe9, 0x29, 0x2f, 0xa6, 0x6f, 0x1f, 0xb5, 0xfd, 0xf6, 0xf5, 0xa8, 0xf1, + 0xe9, 0x29, 0x2f, 0xa6, 0x6f, 0x1f, 0xb5, 0xfd, 0xce, 0xf5, 0xa8, 0xf1, 0xcb, 0xfa, 0x5b, 0x57, 0x4e, 0xb3, 0x97, 0x87, 0xdb, 0x39, 0x78, 0x52, - 0x47, 0x2f, 0xdb, 0x00, 0x81, 0x67, 0x2f, 0xef, 0x4d, 0x2c, 0xfa, 0x47, + 0x47, 0x2f, 0xdb, 0x00, 0x81, 0x67, 0x2f, 0xef, 0x4d, 0x2c, 0xe6, 0x47, 0x2a, 0x11, 0x7c, 0x85, 0xee, 0x38, 0x01, 0xb5, 0x0a, 0x2f, 0xfe, 0xeb, 0x71, 0xad, 0xe3, 0x6f, 0xa5, 0x4e, 0x5f, 0x04, 0x38, 0xc3, 0x97, 0x7f, 0x05, 0x2e, 0x6d, 0xb2, 0x94, 0x86, 0xc1, 0xb1, 0x7b, 0xf0, 0x40, 0xfa, - 0x91, 0x4e, 0x66, 0x86, 0xb1, 0x15, 0xaa, 0xb9, 0xdf, 0xfe, 0xf7, 0xcb, + 0x91, 0x4f, 0xa6, 0x86, 0xb1, 0x15, 0xaa, 0xb9, 0xdf, 0xfe, 0xf7, 0x2b, 0x4e, 0xb4, 0x8f, 0x75, 0x4d, 0x9c, 0xbf, 0xd1, 0x24, 0xf4, 0xa3, 0xc7, 0x2e, 0xe1, 0xf6, 0x73, 0x46, 0xca, 0xff, 0xba, 0xfe, 0xda, 0xc7, 0x27, - 0x39, 0x72, 0xd0, 0xe5, 0xf0, 0xa7, 0xd2, 0x39, 0x7f, 0xc9, 0xf7, 0x70, + 0x39, 0x72, 0xd0, 0xe5, 0xf0, 0xa7, 0x32, 0x39, 0x7f, 0xc9, 0xcf, 0x70, 0x3a, 0x75, 0x9c, 0xa8, 0x3d, 0xbd, 0x11, 0x5f, 0xed, 0xe2, 0x79, 0x54, 0xe9, 0xcb, 0xfe, 0xec, 0x6a, 0x16, 0x82, 0xb3, 0x97, 0x95, 0x7d, 0xad, 0x1f, 0x9a, 0x71, 0xf1, 0x0f, 0x01, 0x9d, 0x62, 0x70, 0xfe, 0x8c, 0xd6, 0xa4, 0xad, 0xd3, 0x50, 0xf4, 0x61, 0x18, 0x21, 0x02, 0xdc, 0x76, 0x77, - 0xf3, 0x6a, 0xbf, 0x86, 0x0e, 0x5f, 0x01, 0x98, 0x13, 0x95, 0xf1, 0xe8, - 0x70, 0x17, 0x5f, 0xfb, 0xb9, 0xc0, 0xe2, 0xae, 0x7d, 0xe3, 0x97, 0xfd, + 0xf3, 0x6a, 0xbf, 0x86, 0x0e, 0x5f, 0x01, 0x98, 0x13, 0x95, 0xc9, 0xe8, + 0x70, 0x17, 0x5f, 0xfb, 0xb9, 0xc0, 0xe2, 0xae, 0x73, 0xe3, 0x97, 0xfd, 0x8b, 0xea, 0x07, 0xa0, 0x54, 0xe5, 0xef, 0x62, 0xce, 0x53, 0x0f, 0x5b, 0x67, 0x57, 0xa4, 0xcf, 0xce, 0x52, 0xa8, 0xd8, 0xfe, 0x13, 0x1e, 0x22, - 0xbf, 0xe5, 0x5f, 0x94, 0x30, 0x51, 0x53, 0x97, 0xfe, 0x7d, 0xb2, 0x13, + 0xbf, 0xe5, 0x5f, 0xe4, 0x30, 0x51, 0x53, 0x97, 0xfe, 0x7d, 0xb2, 0x13, 0x5a, 0x46, 0xce, 0x5b, 0x6a, 0x9f, 0xcf, 0x4e, 0xef, 0x9e, 0x4f, 0xa3, - 0x97, 0xfd, 0x9e, 0xf2, 0x2b, 0xec, 0x59, 0xcb, 0xfa, 0x3e, 0xde, 0x7d, + 0x97, 0xfd, 0x9e, 0xf2, 0x2b, 0xec, 0x59, 0xcb, 0xfa, 0x39, 0xde, 0x73, 0xe3, 0x97, 0x6a, 0x0e, 0x50, 0x4f, 0x17, 0xc5, 0xf7, 0xfb, 0xc8, 0xb4, 0x0c, 0x78, 0xe5, 0xfb, 0x70, 0xbc, 0x61, 0xca, 0x83, 0xd9, 0xd9, 0x95, - 0xb6, 0x14, 0xc6, 0xb1, 0xfb, 0x4f, 0x75, 0xf2, 0x73, 0x4c, 0x29, 0xf4, - 0x67, 0x77, 0xfd, 0xe4, 0x9e, 0x3e, 0xff, 0x50, 0x72, 0xf6, 0xfd, 0x87, - 0x2e, 0xcd, 0xf2, 0x3d, 0x75, 0x0e, 0xef, 0xf7, 0x56, 0x9b, 0x04, 0x90, - 0xe5, 0xff, 0xd9, 0xe4, 0xfa, 0x43, 0x1c, 0x33, 0x51, 0x68, 0x72, 0xff, - 0xf0, 0x25, 0xd7, 0x4f, 0x20, 0xf8, 0x1d, 0x39, 0x7f, 0x95, 0xf7, 0xcb, + 0xb6, 0x14, 0xc6, 0xb1, 0xfb, 0x4f, 0x75, 0xca, 0x73, 0x4c, 0x29, 0xf4, + 0x67, 0x77, 0xfd, 0xe4, 0x9e, 0x39, 0xff, 0x50, 0x72, 0xf6, 0xfd, 0x87, + 0x2e, 0xcd, 0xfc, 0x3d, 0x75, 0x0e, 0xef, 0xf7, 0x56, 0x9b, 0x04, 0x90, + 0xe5, 0xff, 0xd9, 0xe4, 0xe6, 0x43, 0x1c, 0x33, 0x51, 0x68, 0x72, 0xff, + 0xf0, 0x25, 0xd7, 0x4f, 0x20, 0xf8, 0x1d, 0x39, 0x7f, 0x95, 0xf7, 0x2b, 0x4d, 0x6c, 0xe5, 0xfb, 0x3d, 0xfb, 0xf8, 0xe5, 0x42, 0x65, 0x72, 0x33, 0xd2, 0x88, 0x12, 0x5a, 0x1b, 0x5f, 0xff, 0xa3, 0xaf, 0x83, 0x1a, 0x54, 0x20, 0x7d, 0x48, 0xe5, 0x49, 0x3f, 0xbf, 0x46, 0xb7, 0xc0, 0x99, 0x50, 0xbd, 0x73, 0x90, 0xad, 0x48, 0x7f, 0x3c, 0xa4, 0xa0, 0x4a, 0x8a, 0xbe, 0xea, 0x3c, 0x8e, 0x5f, 0xec, 0x19, 0x66, 0xd4, 0x61, 0xcb, 0xf3, 0x37, - 0xfb, 0xb9, 0xca, 0xf1, 0xed, 0xa8, 0x67, 0x7f, 0xda, 0xc1, 0xe5, 0xdc, - 0xf9, 0xb3, 0x97, 0xfd, 0x21, 0x07, 0xfc, 0x96, 0xcf, 0xce, 0x54, 0xe9, - 0x8c, 0xc9, 0xf3, 0x08, 0xfe, 0x3c, 0xbf, 0xf9, 0xfb, 0xb4, 0x92, 0x7a, + 0xfb, 0xb9, 0xca, 0xf1, 0xed, 0xa8, 0x67, 0x7f, 0xda, 0xc1, 0xf9, 0xdc, + 0xe5, 0xb3, 0x97, 0xfd, 0x21, 0x07, 0xff, 0x16, 0xcf, 0xce, 0x54, 0xe9, + 0x8c, 0xc9, 0xf3, 0x08, 0xf9, 0x3c, 0xbf, 0xf9, 0xfb, 0xb4, 0x92, 0x7a, 0x3d, 0xb3, 0x97, 0xfb, 0x3d, 0xd4, 0x68, 0xf3, 0x9c, 0xbf, 0xe1, 0x8c, - 0xfb, 0xd9, 0xa8, 0x39, 0x7f, 0xe8, 0xea, 0x9b, 0x1c, 0xf7, 0x70, 0xe5, + 0xe7, 0xd9, 0xa8, 0x39, 0x7f, 0xe8, 0xea, 0x9b, 0x1c, 0xf7, 0x70, 0xe5, 0x42, 0x65, 0x88, 0x7f, 0xd4, 0x37, 0x35, 0xfc, 0xde, 0xfc, 0xfc, 0x42, 0x18, 0x39, 0x76, 0xf6, 0x72, 0xf3, 0x6d, 0xb6, 0x72, 0xef, 0xdc, 0xa7, - 0x33, 0x41, 0x5a, 0x3e, 0x0d, 0x9b, 0xdf, 0xfb, 0x36, 0x2e, 0xac, 0xc2, + 0xd3, 0x41, 0x5a, 0x3e, 0x0d, 0x9b, 0xdf, 0xfb, 0x36, 0x2e, 0xac, 0xc2, 0x93, 0x1c, 0xbf, 0xbf, 0x89, 0x75, 0x4d, 0x9c, 0xbf, 0x90, 0x7f, 0x5a, 0xd0, 0xe5, 0xe7, 0xff, 0x0a, 0x54, 0x93, 0x63, 0x64, 0x22, 0x7a, 0x45, 0xf9, 0xff, 0x13, 0x06, 0x85, 0xb7, 0xd0, 0x14, 0x09, 0xcb, 0xf0, 0x74, - 0x80, 0x9c, 0xe5, 0xfe, 0x6f, 0x07, 0x38, 0xa6, 0x8e, 0x5f, 0xc3, 0x9f, - 0x7e, 0xa4, 0x8e, 0x54, 0xc8, 0x8d, 0x12, 0x9f, 0x1a, 0x5f, 0xb3, 0x3d, - 0xdc, 0x39, 0x73, 0xb0, 0xe5, 0xff, 0x03, 0x7e, 0x89, 0x81, 0xf6, 0xce, - 0x5f, 0xec, 0xe3, 0x9c, 0xdb, 0x6d, 0xb2, 0x97, 0xe9, 0xa3, 0x3b, 0xb3, - 0x95, 0xc9, 0x13, 0xc2, 0x78, 0xa1, 0xd5, 0xfe, 0xe1, 0xe0, 0x0b, 0xea, + 0x80, 0x9c, 0xe5, 0xfe, 0x6f, 0x07, 0x38, 0xa6, 0x8e, 0x5f, 0xc3, 0x9c, + 0xfe, 0xa4, 0x8e, 0x54, 0xc8, 0x8d, 0x12, 0x9f, 0x1a, 0x5f, 0xb3, 0x3d, + 0xdc, 0x39, 0x73, 0xb0, 0xe5, 0xff, 0x03, 0x7e, 0x89, 0x81, 0xce, 0xce, + 0x5f, 0xec, 0xe3, 0x9f, 0x5b, 0x6d, 0xb2, 0x97, 0xe9, 0xa3, 0x3b, 0xb3, + 0x95, 0xf1, 0x13, 0xc2, 0x78, 0xa1, 0xd5, 0xfe, 0xe1, 0xe0, 0x0b, 0xea, 0x68, 0xe5, 0xe6, 0x3f, 0x8e, 0x54, 0xc9, 0x9d, 0x76, 0x16, 0x80, 0x32, 0xe2, 0x71, 0x77, 0xed, 0x51, 0xcb, 0xf7, 0x17, 0x62, 0x30, 0xe5, 0x41, 0xe3, 0x08, 0xed, 0xfb, 0x26, 0x94, 0x48, 0xe5, 0xfd, 0x38, 0x63, 0x04, @@ -2579,107 +2579,107 @@ 0x04, 0xe5, 0xba, 0x72, 0xf0, 0x1e, 0x71, 0x3c, 0x2d, 0x98, 0xd9, 0x34, 0x89, 0x0f, 0x2e, 0xd3, 0x13, 0x0e, 0x71, 0xce, 0x1e, 0x19, 0x56, 0x13, 0x97, 0xd1, 0x3c, 0x48, 0xe5, 0x39, 0xb2, 0x11, 0x0b, 0xff, 0xd8, 0x17, - 0x66, 0x7d, 0x2c, 0xff, 0x02, 0x72, 0xee, 0xb9, 0xcb, 0xa6, 0xd9, 0xcb, - 0xf6, 0x71, 0x41, 0x0e, 0x1a, 0xe5, 0x05, 0xaf, 0xee, 0x5e, 0xcd, 0xee, - 0x0e, 0x5f, 0xbb, 0x9f, 0x7a, 0x0e, 0x5f, 0xb8, 0x1e, 0x75, 0x24, 0x72, - 0xb9, 0x26, 0x75, 0xcd, 0xe2, 0x0f, 0xb0, 0xbc, 0x05, 0x17, 0xc1, 0xce, + 0x66, 0x73, 0x2c, 0xff, 0x02, 0x72, 0xee, 0xb9, 0xcb, 0xa6, 0xd9, 0xcb, + 0xf6, 0x71, 0x41, 0x0e, 0x1a, 0xe5, 0x05, 0xaf, 0xef, 0x9e, 0xcd, 0xee, + 0x0e, 0x5f, 0xbb, 0x9c, 0xfa, 0x0e, 0x5f, 0xb8, 0x1e, 0x75, 0x24, 0x72, + 0xbe, 0x26, 0x75, 0xf5, 0xe2, 0x0f, 0xb0, 0xbc, 0x05, 0x17, 0xc1, 0xce, 0xb9, 0xcb, 0xff, 0x60, 0xcb, 0xb8, 0x23, 0x0d, 0x9c, 0xbf, 0xf6, 0x6b, - 0x4f, 0x2e, 0x5c, 0x61, 0xac, 0xe5, 0x42, 0x20, 0x64, 0x79, 0x5a, 0x4c, + 0x4f, 0x2f, 0x9c, 0x61, 0xac, 0xe5, 0x42, 0x20, 0x64, 0x79, 0x5a, 0x4c, 0x44, 0x53, 0x7d, 0x0a, 0x2b, 0xfd, 0xad, 0xf7, 0x05, 0x36, 0x72, 0xa1, 0x56, 0x8a, 0x4a, 0x6a, 0x73, 0x5b, 0xfe, 0xc0, 0xe0, 0xc0, 0x82, 0x0e, 0x5d, 0x0d, 0x9c, 0xa8, 0x7c, 0x78, 0x39, 0xe1, 0xaf, 0x29, 0xcf, 0x20, - 0xce, 0xdd, 0x64, 0x65, 0xca, 0xc3, 0xcd, 0x73, 0x8d, 0xff, 0x42, 0xed, + 0xce, 0xdd, 0x64, 0x65, 0xca, 0xc3, 0xcd, 0x73, 0x8d, 0xfc, 0xc2, 0xed, 0x23, 0x0e, 0x9a, 0x12, 0x5a, 0xac, 0x2c, 0x59, 0x2c, 0x5b, 0xb3, 0xca, 0xae, 0xad, 0xfc, 0x3b, 0x46, 0x94, 0xeb, 0xb9, 0x54, 0xde, 0x9d, 0x4d, 0x04, 0x71, 0xfc, 0x65, 0x9e, 0xa8, 0x6d, 0xc0, 0x6b, 0x7f, 0xd9, 0xa1, 0x8f, 0x4b, 0x3a, 0x72, 0xff, 0xe1, 0x5a, 0xaf, 0xbc, 0x94, 0x0a, 0xce, 0x5f, 0xbf, 0xc0, 0xbc, 0x8e, 0x52, 0x1f, 0x58, 0xa1, 0xdf, 0xf7, 0xb7, - 0xd4, 0x86, 0x38, 0x4e, 0x5f, 0xfb, 0xa8, 0x31, 0xf6, 0xd1, 0x90, 0x72, - 0xf6, 0xe3, 0x47, 0x2e, 0xf6, 0xd6, 0x7b, 0x3f, 0x1e, 0xd4, 0x23, 0x00, + 0xd4, 0x86, 0x38, 0x4e, 0x5f, 0xfb, 0xa8, 0x31, 0xce, 0xd1, 0x90, 0x72, + 0xf6, 0xe3, 0x47, 0x2e, 0xf6, 0xd6, 0x7b, 0x3c, 0x9e, 0xd4, 0x23, 0x00, 0x10, 0x91, 0xbf, 0xcb, 0x1c, 0x94, 0x9f, 0x67, 0x2f, 0xe7, 0x6f, 0x3f, - 0x53, 0xc7, 0x2f, 0xcf, 0x2e, 0x41, 0x43, 0x97, 0xf6, 0xf0, 0x29, 0xb9, + 0x53, 0xc7, 0x2f, 0xcf, 0x2f, 0x81, 0x43, 0x97, 0xf6, 0xf0, 0x29, 0xb9, 0xce, 0x5e, 0x94, 0x7e, 0x72, 0xfc, 0xa4, 0xd2, 0x86, 0xb2, 0x95, 0x0a, 0xab, 0x32, 0x14, 0x4a, 0xc3, 0x81, 0x09, 0xf4, 0x65, 0xd3, 0x0d, 0x94, 0xf8, 0xb9, 0x41, 0xdb, 0x2c, 0xe5, 0xff, 0xca, 0x88, 0x1d, 0x4c, 0xda, 0x40, 0x9c, 0xbc, 0xd1, 0x02, 0x72, 0xb4, 0x7c, 0x2c, 0x43, 0xbd, 0x0f, - 0xa3, 0x97, 0xf3, 0x3d, 0xd8, 0xe3, 0x07, 0x2f, 0xfe, 0xfb, 0xc0, 0x67, + 0xa3, 0x97, 0xf3, 0x3d, 0xd8, 0xe3, 0x07, 0x2f, 0xfe, 0xe7, 0xc0, 0x67, 0x61, 0x05, 0xc2, 0x72, 0xf9, 0x5d, 0x3b, 0x67, 0x2c, 0xa1, 0xa2, 0x05, 0x5b, 0xc6, 0xa0, 0x51, 0x5e, 0x37, 0xad, 0x8f, 0xd6, 0x22, 0x0d, 0x18, - 0x6f, 0xe4, 0xe1, 0xd7, 0xd8, 0x6c, 0xe5, 0xfe, 0xea, 0x29, 0xcf, 0xff, + 0x6f, 0xe4, 0xe1, 0xd7, 0xd8, 0x6c, 0xe5, 0xfe, 0xea, 0x29, 0xf7, 0xff, 0xe0, 0xa5, 0x68, 0xfa, 0xda, 0x19, 0xdf, 0x0f, 0x07, 0x0f, 0xb3, 0x94, 0x87, 0x9c, 0xa1, 0x25, 0xfd, 0xdc, 0x07, 0x0f, 0x9b, 0x39, 0x7f, 0xc3, - 0xed, 0x83, 0xef, 0x23, 0x67, 0x2f, 0xff, 0xd8, 0xdc, 0x30, 0x0e, 0x1f, - 0x7c, 0xb4, 0x16, 0xce, 0x5f, 0xe0, 0x3e, 0xf3, 0x05, 0x53, 0x95, 0x08, - 0xc4, 0x09, 0xdf, 0x55, 0xef, 0xfa, 0x3d, 0xbe, 0x58, 0xc4, 0x09, 0xcb, - 0xff, 0x72, 0x17, 0x57, 0x96, 0xff, 0xfe, 0x0e, 0x5f, 0xfe, 0x9c, 0x1f, + 0xed, 0x83, 0x9f, 0x23, 0x67, 0x2f, 0xff, 0xd8, 0xdc, 0x30, 0x0e, 0x1f, + 0x72, 0xb4, 0x16, 0xce, 0x5f, 0xe0, 0x3e, 0xf3, 0x05, 0x53, 0x95, 0x08, + 0xc4, 0x09, 0xdf, 0x55, 0xef, 0xfa, 0x3d, 0xbf, 0x98, 0xc4, 0x09, 0xcb, + 0xff, 0x7c, 0x17, 0x57, 0xe6, 0xff, 0xfe, 0x0e, 0x5f, 0xfe, 0x9c, 0x1f, 0xee, 0x49, 0xbd, 0xc6, 0xa4, 0x72, 0xc8, 0xaa, 0x24, 0xb4, 0x8b, 0x7f, - 0x9f, 0xbf, 0x6e, 0x07, 0xc7, 0x2b, 0x67, 0xb9, 0xe2, 0x9b, 0xff, 0xfe, + 0x9f, 0xbc, 0xee, 0x07, 0xc7, 0x2b, 0x67, 0xb9, 0xe2, 0x9b, 0xff, 0xfe, 0x9c, 0x3d, 0x85, 0xf5, 0x26, 0x77, 0x92, 0xae, 0xa3, 0xb5, 0x9c, 0xbf, 0xdd, 0x49, 0xa5, 0x03, 0x23, 0x97, 0xfe, 0x86, 0xf7, 0xc2, 0x3a, 0xf3, - 0xef, 0x1c, 0xa8, 0x47, 0x22, 0xdb, 0x3c, 0x67, 0x7d, 0x2e, 0xe4, 0xe7, - 0x2f, 0xfa, 0x3e, 0x63, 0xfb, 0x3e, 0xf1, 0xcb, 0x9e, 0x73, 0x95, 0xf1, + 0x9f, 0x1c, 0xa8, 0x47, 0x22, 0xdb, 0x3c, 0x67, 0x7d, 0x2e, 0xe4, 0xe7, + 0x2f, 0xfa, 0x39, 0x63, 0xfb, 0x39, 0xf1, 0xcb, 0x9e, 0x73, 0x95, 0xc9, 0xfa, 0x09, 0x1b, 0x67, 0x57, 0xe0, 0x77, 0x50, 0xd9, 0xcb, 0x9a, 0x39, 0xcb, 0xa1, 0x7e, 0x3c, 0x15, 0x0a, 0x6e, 0xd3, 0x9c, 0xbf, 0xfb, 0x8a, 0x6f, 0x78, 0x2b, 0x71, 0xfc, 0xe5, 0xfe, 0xea, 0x04, 0x38, 0xdc, 0xc7, 0x2f, 0x46, 0xbf, 0xc3, 0xfa, 0x5a, 0x2d, 0x69, 0x18, 0x7d, 0x84, 0x85, - 0xff, 0x9f, 0xed, 0xe7, 0x91, 0x8f, 0x23, 0x96, 0xf1, 0xca, 0xfc, 0xf3, + 0xff, 0x9f, 0x9d, 0xe7, 0x91, 0x8f, 0x23, 0x96, 0xf1, 0xca, 0xfc, 0xf3, 0xd4, 0x3e, 0xbf, 0xff, 0xd3, 0x0c, 0x33, 0x50, 0xbc, 0xd6, 0x75, 0x35, - 0xd7, 0x39, 0x7f, 0xfc, 0xfa, 0xfd, 0xa6, 0x6a, 0x24, 0x9f, 0x7b, 0x0e, + 0xd7, 0x39, 0x7f, 0xfc, 0xfa, 0xfd, 0xa6, 0x6a, 0x24, 0x9c, 0xfb, 0x0e, 0x5f, 0xff, 0xfc, 0x0d, 0xf5, 0xe5, 0xb9, 0x27, 0x94, 0xd4, 0x76, 0x3d, - 0xb7, 0xf8, 0xe5, 0xfa, 0x30, 0x7c, 0xd0, 0xe5, 0xfc, 0x9f, 0x7f, 0xa7, + 0xb7, 0xe4, 0xe5, 0xfa, 0x30, 0x7c, 0xd0, 0xe5, 0xfc, 0x9c, 0xff, 0xa7, 0x09, 0xcb, 0x30, 0xe5, 0x30, 0xfa, 0x3a, 0x50, 0x25, 0xf7, 0x69, 0xac, - 0xe5, 0xe9, 0x00, 0x27, 0x2e, 0x7f, 0xb9, 0x1f, 0x2c, 0xc5, 0xce, 0x35, + 0xe5, 0xe9, 0x00, 0x27, 0x2e, 0x7e, 0x7e, 0x1f, 0x2c, 0xc5, 0xce, 0x35, 0x58, 0xa8, 0xbd, 0x17, 0xf4, 0xa5, 0xb8, 0xd0, 0x6f, 0xff, 0xec, 0x19, 0xf7, 0xb8, 0xff, 0x3a, 0x9a, 0x76, 0xfc, 0x72, 0xfe, 0x0e, 0x0a, 0xba, - 0x83, 0x95, 0x26, 0x47, 0x70, 0x61, 0xec, 0xb2, 0xff, 0xa3, 0x28, 0x9a, + 0x83, 0x95, 0x26, 0x47, 0x70, 0x61, 0xec, 0xb2, 0xfe, 0x63, 0x28, 0x9a, 0x30, 0x6d, 0x42, 0x8d, 0x8e, 0x3d, 0x87, 0x8f, 0xee, 0xfe, 0x94, 0xa6, 0xda, 0x1b, 0x45, 0xcb, 0xff, 0xfc, 0x38, 0x1e, 0xc3, 0x63, 0x89, 0x3b, 0x40, 0x75, 0x34, 0x72, 0xa1, 0x94, 0x86, 0x94, 0x91, 0x00, 0x43, 0x46, 0xd0, 0x72, 0xff, 0xfa, 0x67, 0x79, 0x6e, 0x18, 0x1e, 0xc0, 0xac, 0xe5, - 0x41, 0xef, 0xa0, 0x85, 0xff, 0x64, 0xd2, 0x8f, 0xb3, 0xef, 0x1c, 0xbb, + 0x41, 0xef, 0xa0, 0x85, 0xff, 0x64, 0xd2, 0x8e, 0x73, 0x9f, 0x1c, 0xbb, 0x53, 0xe1, 0xed, 0x89, 0x05, 0xf0, 0x7a, 0x09, 0xce, 0x5f, 0xe0, 0xbc, 0xb2, 0x70, 0x09, 0xcb, 0xff, 0x6b, 0x1a, 0xe6, 0xeb, 0xb1, 0x36, 0x72, 0xd3, 0xc2, 0x26, 0x70, 0x93, 0x46, 0x77, 0x70, 0xf8, 0x72, 0xb0, 0xf4, 0x1c, 0xd6, 0xfe, 0xf3, 0x40, 0x77, 0x16, 0x72, 0xff, 0x6a, 0x3c, 0x9f, - 0xc4, 0x8e, 0x5f, 0xdf, 0x4e, 0xf2, 0x86, 0xb3, 0x97, 0x0c, 0x8e, 0x54, + 0xc4, 0x8e, 0x5f, 0xdc, 0xce, 0xf2, 0x86, 0xb3, 0x97, 0x0c, 0x8e, 0x54, 0x1e, 0x44, 0xe6, 0x55, 0xc2, 0x33, 0xef, 0xe1, 0xca, 0x44, 0x4a, 0x8d, 0xa1, 0x7b, 0x21, 0x8f, 0xda, 0x58, 0xeb, 0xc3, 0xe8, 0x63, 0x16, 0xd9, - 0x07, 0x8c, 0x00, 0xf7, 0x7f, 0xee, 0x11, 0x48, 0x62, 0xfa, 0xff, 0x7e, - 0x72, 0xff, 0x4a, 0x6c, 0x17, 0xee, 0x1c, 0xbe, 0xfa, 0x50, 0xc3, 0x97, + 0x07, 0x8c, 0x00, 0xf7, 0x7f, 0xee, 0x11, 0x48, 0x62, 0xfa, 0xfc, 0xfe, + 0x72, 0xff, 0x4a, 0x6c, 0x17, 0xee, 0x1c, 0xbe, 0xe6, 0x50, 0xc3, 0x97, 0x47, 0x4e, 0x5f, 0xcf, 0x30, 0x60, 0x67, 0x39, 0x53, 0x9f, 0x38, 0x91, 0xf1, 0x16, 0xbe, 0x89, 0x93, 0xa7, 0x2f, 0x70, 0x43, 0x0e, 0x53, 0x9e, 0x0f, 0x01, 0x15, 0xf7, 0x04, 0x0a, 0xce, 0x5f, 0xdd, 0xc5, 0x5e, 0x27, 0x39, 0x7e, 0x64, 0x4d, 0xa8, 0x39, 0x7d, 0x00, 0xe1, 0xd0, 0xe5, 0xf9, - 0xf7, 0xe4, 0x98, 0xe5, 0xfe, 0x4d, 0x44, 0xef, 0xa5, 0x9c, 0xb7, 0xb9, + 0xf7, 0xe4, 0x98, 0xe5, 0xfe, 0x4d, 0x44, 0xef, 0xa5, 0x9c, 0xb7, 0xbe, 0x26, 0x3f, 0x84, 0x8b, 0x24, 0x42, 0xed, 0x14, 0x6c, 0x9b, 0xc5, 0x17, 0xff, 0xb4, 0xb1, 0xce, 0x23, 0x91, 0xa8, 0xd9, 0xcb, 0xfc, 0xf3, 0x77, 0x19, 0x9b, 0x39, 0x58, 0x7f, 0x9c, 0x52, 0x6f, 0x34, 0x8f, 0x1c, 0xbf, - 0x95, 0xe5, 0x1c, 0x53, 0x89, 0xca, 0x9c, 0xf4, 0x84, 0x7a, 0xfc, 0xaf, + 0x95, 0xf9, 0x1c, 0x53, 0x89, 0xca, 0x9c, 0xf4, 0x84, 0x7a, 0xfc, 0xaf, 0xb3, 0x18, 0x72, 0xb0, 0xf2, 0x90, 0x8a, 0xff, 0xf4, 0xc3, 0x8a, 0xaa, 0xfe, 0xda, 0x0c, 0xc7, 0x2f, 0xd8, 0x14, 0xd6, 0xce, 0x5f, 0x94, 0x92, - 0x7f, 0xb3, 0x97, 0xed, 0x2e, 0x32, 0x73, 0x97, 0xbd, 0xef, 0x8e, 0x5f, - 0xfd, 0xf2, 0xd3, 0xbc, 0xb8, 0x33, 0xa8, 0xc3, 0x95, 0xf9, 0xf4, 0x78, + 0x7f, 0xb3, 0x97, 0xed, 0x2e, 0x32, 0x73, 0x97, 0xbd, 0xee, 0x4e, 0x5f, + 0xfd, 0xca, 0xd3, 0xbf, 0x38, 0x33, 0xa8, 0xc3, 0x95, 0xf9, 0xf4, 0x78, 0x7a, 0xe0, 0x68, 0xe5, 0x62, 0x32, 0xb7, 0x09, 0x06, 0x84, 0x76, 0x89, 0xd3, 0x51, 0x61, 0x3b, 0x70, 0xf4, 0xa8, 0x5d, 0x31, 0xc8, 0xe4, 0x52, - 0x1c, 0xfd, 0x85, 0xfb, 0x90, 0x7a, 0x39, 0xdb, 0xff, 0x0a, 0x29, 0xf6, - 0x71, 0xfa, 0x14, 0x39, 0x7f, 0xf9, 0x33, 0x41, 0x86, 0xf3, 0xb1, 0xf6, - 0xce, 0x5f, 0x29, 0x1a, 0xfc, 0xe5, 0xff, 0xa3, 0xee, 0xf6, 0x27, 0x80, + 0x1c, 0xfd, 0x85, 0xfb, 0x90, 0x7a, 0x39, 0xdb, 0xff, 0x0a, 0x29, 0xce, + 0x71, 0xe6, 0x14, 0x39, 0x7f, 0xf9, 0x33, 0x41, 0x86, 0xf3, 0xb1, 0xce, + 0xce, 0x5f, 0x29, 0x1a, 0xfc, 0xe5, 0xff, 0xa3, 0x9e, 0xf6, 0x27, 0x80, 0x30, 0xe5, 0xca, 0x48, 0xe5, 0xcf, 0xa3, 0x97, 0xf7, 0x92, 0x76, 0x42, 0xce, 0x50, 0x4f, 0x13, 0xa2, 0xd7, 0xff, 0xbf, 0x9a, 0x49, 0xa9, 0x4d, - 0x24, 0xd4, 0x8e, 0x5e, 0xf2, 0x4e, 0x72, 0xbe, 0x3e, 0xbd, 0x27, 0x5f, + 0x24, 0xd4, 0x8e, 0x5e, 0xf2, 0x4e, 0x72, 0xb9, 0x3e, 0xbd, 0x27, 0x5f, 0x99, 0x80, 0xd4, 0xe7, 0x2f, 0x40, 0x42, 0x72, 0xec, 0xe0, 0x39, 0x7d, 0xfa, 0x83, 0x23, 0x96, 0x71, 0x37, 0xbe, 0x19, 0xbf, 0x6f, 0x78, 0x3f, 0x9c, 0xaf, 0xcf, 0x34, 0x49, 0x6a, 0x13, 0xa1, 0x48, 0x46, 0xb9, 0x1f, - 0x8a, 0x41, 0x0a, 0x6b, 0xbe, 0x98, 0xe5, 0xf9, 0x4f, 0x7e, 0xcc, 0x39, + 0x8a, 0x41, 0x0a, 0x6b, 0xb9, 0x98, 0xe5, 0xf9, 0x4f, 0x7e, 0xcc, 0x39, 0x4c, 0x3c, 0x3f, 0xc6, 0x6f, 0x2e, 0x36, 0x72, 0xff, 0xa4, 0xfa, 0xf0, 0xc3, 0x36, 0x72, 0xff, 0x40, 0x63, 0x40, 0x8f, 0xce, 0x5c, 0xcd, 0xcc, - 0x7d, 0x6c, 0x38, 0xbf, 0xfe, 0x8c, 0xfb, 0xdd, 0xc4, 0x92, 0x2a, 0xae, + 0x7d, 0x6c, 0x38, 0xbf, 0xfe, 0x8c, 0xe7, 0xdd, 0xc4, 0x92, 0x2a, 0xae, 0x1c, 0xbf, 0xff, 0x9d, 0xb0, 0xbb, 0xea, 0x7e, 0xbf, 0xba, 0x9a, 0x91, 0xcb, 0xff, 0x43, 0x8e, 0x7b, 0xc8, 0xdf, 0x8e, 0x54, 0x27, 0x85, 0x84, 0x69, 0x08, 0x7d, 0x17, 0x8a, 0x80, 0x17, 0x2b, 0x86, 0x66, 0x0d, 0xc2, 0x3c, 0xa7, 0x72, 0xb1, 0xb1, 0x68, 0x73, 0x25, 0x74, 0x93, 0xf4, 0x0d, - 0xc7, 0xfb, 0xe9, 0x4a, 0xf7, 0xf4, 0x03, 0xe4, 0xfb, 0x80, 0xe5, 0xfb, - 0x1b, 0xcf, 0xbc, 0x72, 0xb9, 0x1e, 0xda, 0x19, 0x5f, 0xef, 0xa5, 0x81, + 0xc7, 0xfb, 0xe9, 0x4a, 0xf7, 0xf4, 0x03, 0x94, 0xe7, 0x80, 0xe5, 0xfb, + 0x1b, 0xce, 0x7c, 0x72, 0xbe, 0x1e, 0xda, 0x19, 0x5f, 0xee, 0x65, 0x81, 0xee, 0x4e, 0x72, 0xb4, 0x7b, 0x02, 0x47, 0x7b, 0x59, 0xb3, 0x97, 0xe4, 0x1e, 0x39, 0x23, 0x97, 0xb1, 0x27, 0x39, 0x4a, 0x9f, 0x03, 0x07, 0x3a, 0x51, 0x7f, 0x44, 0xf9, 0xec, 0x61, 0xcb, 0xff, 0xb0, 0x40, 0xbe, 0xe3, @@ -2688,9 +2688,9 @@ 0x3c, 0x72, 0xfd, 0x13, 0x66, 0x2c, 0xe5, 0x42, 0x2b, 0xb0, 0x85, 0x0c, 0xfa, 0x67, 0x7f, 0xee, 0xe4, 0xc9, 0x30, 0x38, 0x01, 0xb3, 0x97, 0x93, 0x4a, 0x9c, 0xa4, 0x3e, 0x11, 0x44, 0xbf, 0x47, 0x07, 0x62, 0x63, 0x95, - 0x23, 0xcb, 0xd9, 0x05, 0xff, 0xc0, 0x99, 0x3b, 0x1f, 0x4a, 0x26, 0x83, - 0x97, 0xe0, 0xb8, 0xc7, 0x4e, 0x5f, 0xd2, 0x8f, 0xbd, 0x9d, 0x39, 0x7f, - 0xfb, 0xdb, 0x4f, 0xe2, 0x5b, 0xcc, 0xfb, 0xc7, 0x2a, 0x63, 0xf9, 0xd9, + 0x23, 0xcb, 0xd9, 0x05, 0xff, 0xc0, 0x99, 0x3b, 0x1c, 0xca, 0x26, 0x83, + 0x97, 0xe0, 0xb8, 0xc7, 0x4e, 0x5f, 0xd2, 0x8e, 0x7d, 0x9d, 0x39, 0x7f, + 0xfb, 0xdb, 0x4f, 0xe2, 0x5b, 0xcc, 0xe7, 0xc7, 0x2a, 0x63, 0xf9, 0xd9, 0x75, 0x75, 0x18, 0x4d, 0xc2, 0x7e, 0xff, 0x75, 0xe6, 0xc4, 0xe0, 0x09, 0xca, 0x43, 0xdf, 0xd9, 0x4d, 0xff, 0xfb, 0x40, 0xd6, 0xa0, 0x71, 0x54, 0xef, 0x71, 0x43, 0x97, 0xa6, 0xd4, 0x1c, 0xbf, 0x3a, 0x06, 0x04, 0xe5, @@ -2699,50 +2699,50 @@ 0xdf, 0xfc, 0x8c, 0x4d, 0xf6, 0x13, 0x40, 0x6b, 0x39, 0x50, 0x8c, 0x74, 0x59, 0x72, 0x8b, 0xf8, 0x76, 0x9c, 0x60, 0x27, 0x2f, 0xfb, 0xf4, 0x1f, 0x46, 0xc1, 0xd3, 0x97, 0x85, 0x15, 0x39, 0x7f, 0x79, 0x34, 0x9e, 0x01, - 0xcb, 0x47, 0x24, 0x41, 0x30, 0xe5, 0x41, 0xcb, 0xf8, 0x0a, 0x77, 0x3e, + 0xcb, 0x47, 0xc4, 0x41, 0x30, 0xe5, 0x41, 0xcb, 0xf8, 0x0a, 0x77, 0x39, 0xd9, 0xcb, 0xff, 0xff, 0xf6, 0xa3, 0xc2, 0xeb, 0x4d, 0xcc, 0x9a, 0x5c, - 0x6f, 0xd1, 0xf4, 0x29, 0x9b, 0x39, 0x7f, 0xbb, 0x9f, 0x46, 0x91, 0x87, - 0x2f, 0xff, 0xff, 0xfb, 0x79, 0xee, 0xbb, 0x37, 0xad, 0x27, 0xde, 0x77, - 0x57, 0x32, 0x60, 0x7a, 0x1b, 0xfa, 0x0e, 0x5f, 0x81, 0x36, 0x34, 0xc3, - 0x95, 0xb4, 0x60, 0xfa, 0x12, 0xf7, 0xfd, 0xf6, 0xc5, 0x19, 0xec, 0x6b, + 0x6f, 0xd1, 0xcc, 0x29, 0x9b, 0x39, 0x7f, 0xbb, 0x9c, 0xc6, 0x91, 0x87, + 0x2f, 0xff, 0xff, 0xfb, 0x79, 0xee, 0xbb, 0x37, 0xad, 0x27, 0x3e, 0x77, + 0x57, 0x32, 0x60, 0x7a, 0x1b, 0xe6, 0x0e, 0x5f, 0x81, 0x36, 0x34, 0xc3, + 0x95, 0xb4, 0x60, 0xfa, 0x12, 0xf7, 0xfd, 0xce, 0xc5, 0x19, 0xec, 0x6b, 0x39, 0x76, 0x68, 0xe5, 0x41, 0xe9, 0x74, 0xf2, 0xfe, 0xf0, 0xbf, 0xf8, - 0x27, 0x2f, 0xc2, 0xff, 0xe0, 0x9c, 0xae, 0x47, 0xa5, 0xe2, 0xca, 0x85, + 0x27, 0x2f, 0xc2, 0xff, 0xe0, 0x9c, 0xaf, 0x87, 0xa5, 0xe2, 0xca, 0x85, 0x51, 0x01, 0x84, 0x1b, 0xc3, 0xd3, 0xcf, 0x40, 0x73, 0xbf, 0xf7, 0x93, - 0x62, 0xfe, 0x99, 0xc2, 0x72, 0xfb, 0xf7, 0xfb, 0x67, 0x2e, 0x6d, 0xb3, - 0x95, 0xb3, 0x7a, 0xd9, 0x25, 0xf7, 0x5f, 0x3a, 0x53, 0x99, 0xa2, 0xac, + 0x62, 0xfe, 0x99, 0xc2, 0x72, 0xfb, 0xf7, 0xe7, 0x67, 0x2e, 0x6d, 0xb3, + 0x95, 0xb3, 0x7a, 0xd9, 0x25, 0xf7, 0x5f, 0x3a, 0x53, 0xe9, 0xa2, 0xac, 0x46, 0x82, 0x42, 0x76, 0xfc, 0xa6, 0x31, 0x34, 0x72, 0xff, 0x81, 0xe8, 0x15, 0xb5, 0x7f, 0xb0, 0xe5, 0xee, 0xc7, 0xe7, 0x2f, 0xfc, 0x00, 0xf5, - 0x34, 0x9f, 0x4d, 0x07, 0x2b, 0x11, 0x88, 0x85, 0x0e, 0x7e, 0x23, 0xb7, - 0xbb, 0xc9, 0xac, 0xe5, 0xfb, 0xb0, 0x39, 0x39, 0xca, 0x83, 0xc9, 0x72, + 0x34, 0x9c, 0xcd, 0x07, 0x2b, 0x11, 0x88, 0x85, 0x0e, 0x7e, 0x23, 0xb7, + 0xbb, 0xf1, 0xac, 0xe5, 0xfb, 0xb0, 0x39, 0x39, 0xca, 0x83, 0xc9, 0x72, 0x2b, 0xfd, 0xd8, 0xf0, 0x18, 0x0f, 0x1c, 0xa8, 0x66, 0x71, 0x4a, 0x32, - 0x20, 0xc3, 0x77, 0xe8, 0x73, 0x35, 0x91, 0x4d, 0x1b, 0x3e, 0x88, 0x59, + 0x20, 0xc3, 0x77, 0x98, 0x73, 0x35, 0x91, 0x4d, 0x1b, 0x3e, 0x88, 0x59, 0x0a, 0xee, 0xc3, 0xd1, 0xcb, 0x7f, 0x85, 0x87, 0x0e, 0x70, 0x32, 0xae, 0x37, 0x19, 0x27, 0xa1, 0xd5, 0xc6, 0x10, 0x5c, 0x04, 0x17, 0xc9, 0xa5, 0x26, 0x39, 0x7f, 0xe1, 0xfd, 0x8f, 0x21, 0x8f, 0x6c, 0xe5, 0xd9, 0x87, 0x2f, 0x97, 0xd4, 0x50, 0xe5, 0x75, 0x13, 0x4e, 0x49, 0xc3, 0x9f, 0x28, 0x2b, 0x7e, 0x9a, 0x26, 0xec, 0x1c, 0xbf, 0xfc, 0x3e, 0xda, 0x9e, 0x41, 0x04, 0xb3, 0x67, 0x2e, 0x52, 0x0e, 0x5e, 0x6d, 0xb6, 0xca, 0x5f, 0x4b, - 0xd8, 0xb2, 0x9c, 0xcd, 0x05, 0xfb, 0x02, 0x9f, 0xec, 0xf7, 0x7f, 0x2b, + 0xd8, 0xb2, 0x9f, 0x4d, 0x05, 0xfb, 0x02, 0x9f, 0xec, 0xf7, 0x7f, 0x2b, 0x47, 0xd2, 0x26, 0x95, 0x09, 0x9a, 0x61, 0x4e, 0x92, 0x9e, 0x14, 0x17, - 0x7b, 0x67, 0x2f, 0xf7, 0xbb, 0x1e, 0xdf, 0x50, 0xe5, 0xfb, 0x96, 0x4c, - 0x93, 0x9c, 0xae, 0x47, 0xbd, 0xb3, 0x3b, 0x6c, 0xe5, 0xfe, 0xf7, 0xd2, - 0xec, 0x0c, 0xe5, 0x2f, 0xfd, 0x9f, 0x49, 0x30, 0x47, 0x02, 0x72, 0xfd, - 0x3b, 0x01, 0xf7, 0x8e, 0x54, 0x26, 0x8d, 0xf3, 0xae, 0x89, 0x04, 0x47, - 0x66, 0xbe, 0x3c, 0xb2, 0x1c, 0xbe, 0x75, 0x1c, 0x27, 0x2e, 0xfa, 0x4e, - 0x6c, 0x80, 0x21, 0x7f, 0xc3, 0x0d, 0xed, 0x07, 0xe9, 0x1c, 0xba, 0x16, + 0x7b, 0x67, 0x2f, 0xf7, 0xbb, 0x1e, 0xdf, 0x50, 0xe5, 0xfb, 0xe6, 0x4c, + 0x93, 0x9c, 0xaf, 0x87, 0xbd, 0xb3, 0x3b, 0x6c, 0xe5, 0xfe, 0xf7, 0x32, + 0xec, 0x0c, 0xe5, 0x2f, 0xfd, 0x9c, 0xc9, 0x30, 0x47, 0x02, 0x72, 0xfd, + 0x3b, 0x01, 0xcf, 0x8e, 0x54, 0x26, 0x8d, 0xcb, 0xae, 0x89, 0x04, 0x47, + 0x66, 0xbe, 0x3c, 0xb2, 0x1c, 0xbe, 0x75, 0x1c, 0x27, 0x2e, 0xe6, 0x4e, + 0x6c, 0x80, 0x21, 0x7f, 0xc3, 0x0d, 0xed, 0x07, 0x99, 0x1c, 0xba, 0x16, 0x72, 0x84, 0xf3, 0xf8, 0x9c, 0xdf, 0x4e, 0xa4, 0x35, 0x9c, 0xbf, 0x0c, - 0x37, 0x82, 0x72, 0xff, 0xbb, 0xf4, 0x2b, 0x34, 0xa1, 0xac, 0xe5, 0xb6, + 0x37, 0x82, 0x72, 0xff, 0xbb, 0xcc, 0x2b, 0x34, 0xa1, 0xac, 0xe5, 0xb6, 0x13, 0xe5, 0xc2, 0x6a, 0xd2, 0x2c, 0xfd, 0x08, 0xca, 0x85, 0x40, 0x79, - 0x08, 0x94, 0x7c, 0x78, 0x6b, 0x5f, 0xc3, 0xf6, 0xe6, 0xcf, 0x1c, 0xbf, + 0x08, 0x94, 0x7c, 0x78, 0x6b, 0x5f, 0xc3, 0xce, 0xe6, 0xcf, 0x1c, 0xbf, 0x93, 0xc2, 0xff, 0xec, 0xe5, 0xff, 0xef, 0x4d, 0x9a, 0xc7, 0x64, 0x75, - 0x02, 0x72, 0xfe, 0x03, 0x33, 0xbf, 0x39, 0xca, 0x55, 0x14, 0x82, 0x5b, - 0xb4, 0x9b, 0xff, 0xc8, 0x11, 0x7f, 0x87, 0x3d, 0x89, 0xf9, 0xcb, 0xe5, + 0x02, 0x72, 0xfe, 0x03, 0x33, 0xbc, 0xb9, 0xca, 0x55, 0x14, 0x82, 0x5b, + 0xb4, 0x9b, 0xff, 0xc8, 0x11, 0x7e, 0x47, 0x3d, 0x89, 0xf9, 0xcb, 0xe5, 0x84, 0x13, 0x9c, 0xbd, 0x2d, 0x80, 0xe5, 0xd1, 0xec, 0x3c, 0x1e, 0x92, 0x5f, 0xba, 0xfa, 0xcd, 0x1c, 0xb8, 0x0e, 0x72, 0x96, 0x6f, 0x44, 0x9e, - 0xfa, 0x5e, 0x00, 0x4e, 0x5f, 0xa1, 0x24, 0xfb, 0x39, 0x5f, 0x1e, 0x4e, - 0x88, 0xef, 0xfd, 0xf6, 0xd1, 0x5c, 0xf2, 0x6b, 0x0e, 0x54, 0xe8, 0xcb, + 0xfa, 0x5e, 0x00, 0x4e, 0x5f, 0xa1, 0x24, 0xfb, 0x39, 0x5c, 0x9e, 0x4e, + 0x88, 0xef, 0xfd, 0xce, 0xd1, 0x5c, 0xf2, 0x6b, 0x0e, 0x54, 0xe8, 0xcb, 0x16, 0x9f, 0x11, 0xdf, 0xe0, 0x8e, 0x71, 0x4d, 0x39, 0xca, 0x83, 0xe3, - 0x01, 0x85, 0xfa, 0x76, 0xb4, 0xcf, 0x8e, 0x5f, 0x93, 0x71, 0x3b, 0x0f, + 0x01, 0x85, 0xfa, 0x76, 0xb4, 0xce, 0x4e, 0x5f, 0x93, 0x71, 0x3b, 0x0f, 0x67, 0xea, 0xfd, 0x0f, 0xaf, 0xc0, 0x7b, 0x3f, 0x57, 0x3c, 0x8f, 0x67, 0xea, 0xf8, 0x12, 0xcd, 0x9e, 0xcf, 0xd5, 0x04, 0xf4, 0x84, 0x8e, 0xfd, 0x19, 0xbc, 0x13, 0xd9, 0xfa, 0xa3, 0xd9, 0xfa, 0xb9, 0xfc, 0x7b, 0x3f, @@ -2751,127 +2751,127 @@ 0xd6, 0x71, 0xc0, 0x9e, 0xcf, 0xd5, 0xfd, 0x9d, 0x4d, 0x82, 0x73, 0xd9, 0xfa, 0xaf, 0xd1, 0x4c, 0x24, 0x9b, 0x47, 0xbe, 0xd4, 0xf1, 0xe3, 0xd9, 0xfa, 0xa3, 0xd9, 0xfa, 0xc3, 0x61, 0x73, 0x6d, 0x9e, 0xcf, 0xd5, 0x49, - 0x58, 0xe0, 0x4d, 0x72, 0x10, 0xff, 0x42, 0x77, 0x44, 0xec, 0x31, 0xdc, - 0x2f, 0xbc, 0xc0, 0xd9, 0x3d, 0xe9, 0x42, 0xa5, 0xb3, 0xf4, 0xe6, 0x89, - 0x0b, 0xfa, 0x31, 0x48, 0x94, 0x8e, 0x5f, 0xed, 0xe4, 0xa5, 0x1e, 0xf8, + 0x58, 0xe0, 0x4d, 0x72, 0x10, 0xfc, 0xc2, 0x77, 0x44, 0xec, 0x31, 0xdc, + 0x2f, 0xbc, 0xc0, 0xd9, 0x3d, 0xe9, 0x42, 0xa5, 0xb3, 0xf4, 0xfa, 0x89, + 0x0b, 0xfa, 0x31, 0x48, 0x94, 0x8e, 0x5f, 0xed, 0xe4, 0xa5, 0x1e, 0xe4, 0xe5, 0x62, 0x28, 0x04, 0xff, 0x65, 0xb7, 0xfe, 0xc5, 0x87, 0x34, 0xdb, - 0xf6, 0x63, 0x97, 0xff, 0x6c, 0x72, 0x68, 0x9f, 0xf7, 0xfb, 0x67, 0x2e, - 0x94, 0xe5, 0x2f, 0xa6, 0x77, 0xd1, 0xca, 0x9d, 0x1d, 0xff, 0x17, 0x75, + 0xf6, 0x63, 0x97, 0xff, 0x6c, 0x72, 0x68, 0x9f, 0xf7, 0xe7, 0x67, 0x2e, + 0x94, 0xe5, 0x2f, 0xa6, 0x77, 0xd1, 0xca, 0x9d, 0x1d, 0xfc, 0x97, 0x75, 0x00, 0x51, 0xf8, 0x06, 0x2e, 0x49, 0xce, 0x56, 0x97, 0x73, 0x1e, 0x75, 0x9f, 0xc9, 0xd7, 0xf9, 0x9b, 0x1c, 0xf6, 0x7e, 0x72, 0xfe, 0xf6, 0x76, 0x35, 0xf9, 0xcb, 0xfe, 0x5c, 0x7e, 0x10, 0x3e, 0xa4, 0x72, 0xff, 0xce, - 0xf3, 0xe3, 0x1c, 0x7e, 0x91, 0xcb, 0xce, 0xae, 0xf0, 0xfe, 0x26, 0x3a, - 0xb3, 0x7c, 0x91, 0xb4, 0x30, 0xa6, 0xa8, 0x4c, 0xf5, 0xe3, 0x0d, 0xbf, + 0xf3, 0xe3, 0x1c, 0x79, 0x91, 0xcb, 0xce, 0xae, 0xf0, 0xfe, 0x26, 0x3a, + 0xb3, 0x7f, 0x11, 0xb4, 0x30, 0xa6, 0xa8, 0x4c, 0xf5, 0xe3, 0x0d, 0xbf, 0x0f, 0xbb, 0x93, 0x9c, 0xb8, 0x2d, 0x9c, 0xa8, 0x3c, 0x0c, 0x28, 0xbf, 0xff, 0x4b, 0x51, 0xc5, 0xe6, 0x80, 0xf6, 0x18, 0xf3, 0x1c, 0xbf, 0xdc, - 0x0f, 0xb4, 0xdc, 0xd8, 0x72, 0xbe, 0x44, 0x76, 0x96, 0x2f, 0x20, 0xc8, + 0x0f, 0xb4, 0xdc, 0xd8, 0x72, 0xb9, 0x44, 0x76, 0x96, 0x2f, 0x20, 0xc8, 0xe5, 0x43, 0x3e, 0xaa, 0x52, 0xe2, 0x71, 0x15, 0x21, 0xa6, 0xd6, 0x61, 0xa8, 0x44, 0xf6, 0x39, 0x77, 0x9d, 0xed, 0x18, 0xdd, 0xf6, 0xd0, 0x08, - 0x57, 0x70, 0x12, 0x5f, 0xff, 0xf2, 0x75, 0xfb, 0x12, 0xe7, 0x9f, 0xc4, - 0xb6, 0x1e, 0xc6, 0x8e, 0x5f, 0xf9, 0x58, 0xf8, 0x63, 0xbd, 0x02, 0xce, + 0x57, 0x70, 0x12, 0x5f, 0xff, 0xf2, 0x75, 0xfb, 0x12, 0xfb, 0x9f, 0xc4, + 0xb6, 0x1e, 0xc6, 0x8e, 0x5f, 0xf9, 0x58, 0xe4, 0x63, 0xbd, 0x02, 0xce, 0x5f, 0xfd, 0xa8, 0xc1, 0xc9, 0x27, 0x73, 0x89, 0xcb, 0xff, 0xe1, 0x75, - 0x77, 0x9c, 0x63, 0xef, 0x6c, 0x0c, 0x39, 0x41, 0x44, 0xb0, 0xa1, 0xde, + 0x77, 0x9c, 0x63, 0x9f, 0x6c, 0x0c, 0x39, 0x41, 0x44, 0xb0, 0xa1, 0xde, 0x1e, 0x38, 0x72, 0xfe, 0x17, 0x57, 0xaf, 0x23, 0x97, 0xe5, 0xe3, 0x23, - 0x67, 0x2f, 0x36, 0xdb, 0x65, 0x2f, 0x29, 0x1f, 0x94, 0xe6, 0x68, 0x2f, + 0x67, 0x2f, 0x36, 0xdb, 0x65, 0x2f, 0x29, 0x1f, 0x94, 0xfa, 0x68, 0x2f, 0xf9, 0xe4, 0xa6, 0xb3, 0x8b, 0xe8, 0xe5, 0xff, 0xfb, 0xb9, 0x25, 0x04, 0x72, 0x79, 0xa5, 0x1a, 0x9c, 0xe5, 0x0a, 0x24, 0xfc, 0x77, 0x7f, 0xfb, - 0xf8, 0x93, 0x8c, 0x91, 0x99, 0xf7, 0x8e, 0x5f, 0xf7, 0x9c, 0x73, 0x7a, - 0x8d, 0x9c, 0xbe, 0x94, 0x7f, 0xf1, 0xcb, 0xfb, 0xf8, 0x1c, 0xfb, 0xc7, - 0x2e, 0x7f, 0xf9, 0x1e, 0x92, 0x84, 0x97, 0xff, 0x94, 0x19, 0x95, 0x70, + 0xf8, 0x93, 0x8c, 0x91, 0x99, 0xcf, 0x8e, 0x5f, 0xf7, 0x9c, 0x73, 0x7a, + 0x8d, 0x9c, 0xbe, 0x94, 0x7f, 0xc9, 0xcb, 0xfb, 0xf8, 0x1c, 0xe7, 0xc7, + 0x2e, 0x7f, 0xfe, 0x1e, 0x92, 0x84, 0x97, 0xff, 0x94, 0x19, 0x95, 0x70, 0xf7, 0x17, 0x9a, 0x39, 0x48, 0x9a, 0x83, 0xa5, 0x0c, 0x22, 0x76, 0x63, 0x7b, 0x8c, 0x68, 0xe5, 0x49, 0x72, 0x10, 0x2d, 0x19, 0x0d, 0x64, 0x22, 0x60, 0xeb, 0x96, 0xfe, 0x8e, 0x30, 0xc3, 0xf4, 0x6e, 0x5c, 0x50, 0x2e, 0x49, 0xce, 0x5f, 0xe1, 0x58, 0x53, 0x8c, 0x04, 0xe5, 0x04, 0xf2, 0xc0, - 0x2f, 0x6f, 0xce, 0x5f, 0xf6, 0x43, 0x5f, 0x2e, 0xbe, 0x68, 0xe5, 0xe6, + 0x2f, 0x6f, 0xce, 0x5f, 0xf6, 0x43, 0x5f, 0xce, 0xbe, 0x68, 0xe5, 0xe6, 0x24, 0xc7, 0x2f, 0xd9, 0xfe, 0xe2, 0x47, 0x2f, 0xc8, 0xc0, 0x87, 0x0e, - 0x5b, 0xf1, 0x3c, 0xf6, 0x85, 0x17, 0xfd, 0xee, 0xe6, 0xf9, 0x79, 0x27, + 0x5b, 0xf1, 0x3c, 0xf6, 0x85, 0x17, 0xfd, 0xee, 0xe6, 0xfe, 0x79, 0x27, 0x39, 0x50, 0x7c, 0xc8, 0x55, 0x7f, 0xc2, 0x80, 0xe1, 0xf6, 0xd2, 0x3c, 0x72, 0xa4, 0x9b, 0xfc, 0xc2, 0x4c, 0x3c, 0xec, 0x34, 0x84, 0x82, 0xfb, 0x3c, 0xa4, 0xe7, 0x2f, 0x36, 0xdb, 0x65, 0x88, 0x40, 0xbe, 0x5b, 0xba, - 0xcb, 0x10, 0x81, 0xcc, 0xd7, 0x5f, 0x3e, 0xb1, 0xb3, 0x95, 0xa3, 0xe3, - 0xe2, 0x83, 0x79, 0xb6, 0xdb, 0x2c, 0x41, 0xe5, 0x16, 0x20, 0xf3, 0x99, + 0xcb, 0x10, 0x81, 0xf4, 0xd7, 0x5f, 0x3e, 0xb1, 0xb3, 0x95, 0xa3, 0xe3, + 0xe2, 0x83, 0x79, 0xb6, 0xdb, 0x2c, 0x41, 0xe5, 0x16, 0x20, 0xf3, 0xe9, 0xae, 0xbf, 0xb3, 0xdd, 0x03, 0xc8, 0xe5, 0xe6, 0xdb, 0x6c, 0xe5, 0xed, - 0xc2, 0xa5, 0x39, 0x9a, 0x0a, 0xc4, 0x7c, 0xad, 0x48, 0x4a, 0xfc, 0x9b, + 0xc2, 0xa5, 0x3e, 0x9a, 0x0a, 0xc4, 0x7c, 0xad, 0x48, 0x4a, 0xfc, 0x9b, 0x4d, 0x69, 0xf4, 0xb2, 0x3a, 0xeb, 0xff, 0xbb, 0x12, 0x4f, 0x67, 0x57, 0x0c, 0x39, 0x50, 0x7e, 0x1c, 0x4b, 0x6f, 0xfb, 0x63, 0x0c, 0xde, 0xc0, 0x27, 0x2f, 0xff, 0x67, 0x53, 0x5d, 0x7c, 0xda, 0x3c, 0xe7, 0x2f, 0xa3, - 0xd0, 0xc3, 0x95, 0xf2, 0x28, 0x58, 0x71, 0xe4, 0x8b, 0xfe, 0xec, 0x0a, - 0xfe, 0xdb, 0xb5, 0x9c, 0xbf, 0x38, 0x40, 0xea, 0x1c, 0xa9, 0x1f, 0x23, + 0xd0, 0xc3, 0x95, 0xca, 0x28, 0x58, 0x71, 0xe4, 0x8b, 0xfe, 0xec, 0x0a, + 0xf9, 0xdb, 0xb5, 0x9c, 0xbf, 0x38, 0x40, 0xea, 0x1c, 0xa9, 0x1f, 0x23, 0x67, 0x97, 0xc2, 0x90, 0xa9, 0xcb, 0xca, 0x47, 0xe7, 0x2a, 0x73, 0x7e, 0xc2, 0x1b, 0xf2, 0xe3, 0xb0, 0xc2, 0x97, 0xe1, 0x71, 0x1c, 0x29, 0x76, 0x2c, 0xa5, 0xcd, 0xb6, 0x52, 0xb0, 0xfe, 0xb6, 0x4f, 0xe2, 0x46, 0xc5, - 0xaf, 0xf0, 0xa9, 0x1f, 0xf7, 0x38, 0x0a, 0x73, 0x37, 0x97, 0xff, 0xa7, + 0xaf, 0xf0, 0xa9, 0x1f, 0xf7, 0x38, 0x0a, 0x7d, 0x37, 0x97, 0xff, 0xa7, 0x0e, 0x9d, 0x63, 0x9c, 0x74, 0x9b, 0x39, 0x50, 0xa9, 0x93, 0x21, 0x2a, 0x8c, 0x4f, 0x0d, 0x80, 0x24, 0xdf, 0xfd, 0x1f, 0xef, 0x30, 0x2e, 0x2e, - 0xa9, 0xcb, 0xff, 0xf7, 0x53, 0x8a, 0x08, 0x77, 0x1a, 0x4c, 0xfb, 0x67, + 0xa9, 0xcb, 0xff, 0xf7, 0x53, 0x8a, 0x08, 0x77, 0x1a, 0x4c, 0xe7, 0x67, 0x2f, 0xe1, 0x8c, 0xd3, 0xfe, 0x72, 0xff, 0xd1, 0xae, 0xc2, 0x76, 0x05, 0x0e, 0x5d, 0x2d, 0xad, 0x17, 0xbe, 0x56, 0x6c, 0xb2, 0xff, 0x40, 0xe3, - 0x13, 0xe9, 0x1c, 0xbf, 0xfe, 0xd8, 0xe7, 0xdf, 0xbe, 0xdf, 0x49, 0xf7, - 0xe7, 0x2b, 0xe4, 0x60, 0xf8, 0xf5, 0xb3, 0x2a, 0xea, 0x7e, 0x6f, 0x1e, + 0x13, 0x99, 0x1c, 0xbf, 0xfe, 0xd8, 0xe7, 0x3f, 0xbe, 0xdf, 0x49, 0xcf, + 0xe7, 0x2b, 0x94, 0x60, 0xf8, 0xf5, 0xb3, 0x2a, 0xea, 0x7e, 0x6f, 0x1e, 0x0d, 0xee, 0x2a, 0x30, 0xe5, 0xfd, 0xb5, 0x02, 0x01, 0x91, 0xcb, 0xf9, - 0x16, 0x1c, 0x7f, 0xce, 0x5f, 0xff, 0xbd, 0xbf, 0xb9, 0x07, 0x03, 0x0f, - 0xac, 0x1f, 0xce, 0x5f, 0xff, 0xfb, 0x97, 0xa5, 0x9f, 0xb4, 0xce, 0x41, - 0xc0, 0xc3, 0xeb, 0x07, 0xf2, 0x21, 0x7f, 0xf6, 0x7b, 0x92, 0xfa, 0x9d, - 0xea, 0x7e, 0x68, 0x42, 0xd5, 0x24, 0x65, 0x6d, 0xda, 0xf4, 0x4f, 0xcf, - 0x69, 0xa2, 0xfa, 0x32, 0x2b, 0xf3, 0x36, 0xdb, 0xfc, 0x72, 0xdb, 0x09, - 0xf4, 0x28, 0x7d, 0x7f, 0x64, 0xd2, 0x4d, 0x6c, 0xe5, 0xfd, 0x1f, 0x29, + 0x16, 0x1c, 0x7f, 0xce, 0x5f, 0xff, 0xbd, 0xbe, 0x7e, 0x07, 0x03, 0x0f, + 0xac, 0x1f, 0xce, 0x5f, 0xff, 0xfb, 0xe7, 0xa5, 0x9f, 0xb4, 0xcf, 0x81, + 0xc0, 0xc3, 0xeb, 0x07, 0xf2, 0x21, 0x7f, 0xf6, 0x7b, 0xe2, 0xfa, 0x9d, + 0xea, 0x7e, 0x68, 0x42, 0xd5, 0x24, 0x65, 0x6d, 0xda, 0xf4, 0x4f, 0xf7, + 0x69, 0xa2, 0xfa, 0x32, 0x2b, 0xf3, 0x36, 0xdb, 0xf2, 0x72, 0xdb, 0x09, + 0xf4, 0x28, 0x7d, 0x7f, 0x64, 0xd2, 0x4d, 0x6c, 0xe5, 0xfd, 0x1c, 0xa9, 0xb8, 0xc3, 0x95, 0x0c, 0xd7, 0x60, 0xc3, 0xa3, 0x23, 0xa1, 0x49, 0x55, 0x3a, 0x96, 0x50, 0xf2, 0x91, 0x7f, 0x29, 0xe1, 0xc8, 0x04, 0xbf, 0x71, 0xed, 0x78, 0xa4, 0x05, 0xd7, 0x9b, 0x6d, 0xb2, 0x97, 0x9c, 0x42, 0x53, - 0x99, 0xa0, 0xbe, 0xcd, 0x67, 0x8e, 0x57, 0xe7, 0x9d, 0xb2, 0xdb, 0xee, + 0xe9, 0xa0, 0xbe, 0xcd, 0x67, 0x8e, 0x57, 0xe7, 0x9d, 0xb2, 0xdb, 0xee, 0xa3, 0xc8, 0xe5, 0xfe, 0xf6, 0xd3, 0x5a, 0x46, 0x1c, 0xbc, 0xc9, 0xc2, - 0x72, 0x84, 0xf4, 0x7c, 0x67, 0x7b, 0x92, 0xad, 0x0e, 0x5e, 0xf3, 0x84, + 0x72, 0x84, 0xf4, 0x7c, 0x67, 0x7b, 0xe2, 0xad, 0x0e, 0x5e, 0xf3, 0x84, 0xe5, 0x68, 0xdf, 0x6c, 0x8a, 0xfe, 0x5c, 0x7e, 0x9a, 0x54, 0xa5, 0xfc, - 0xa6, 0x6b, 0x32, 0x63, 0x97, 0xe7, 0xef, 0x20, 0xc1, 0xca, 0x92, 0x73, + 0xa6, 0x6b, 0x32, 0x63, 0x97, 0xe7, 0xef, 0xc0, 0xc1, 0xca, 0x92, 0x73, 0x61, 0x23, 0xc7, 0x24, 0x5f, 0x12, 0x1d, 0x97, 0xf8, 0xba, 0xfc, 0xfa, - 0xd6, 0x7c, 0x72, 0xff, 0xf7, 0xba, 0x8f, 0xfe, 0x68, 0x30, 0x32, 0x39, - 0x7f, 0xfb, 0xee, 0x5f, 0x7f, 0x02, 0xb7, 0x9c, 0x5c, 0xe5, 0x42, 0x2f, - 0xf0, 0xa0, 0x52, 0x6f, 0xd1, 0xb5, 0x06, 0x47, 0x2f, 0xb9, 0x2d, 0x24, + 0xd6, 0x72, 0x72, 0xff, 0xf7, 0xba, 0x8f, 0xfe, 0x68, 0x30, 0x32, 0x39, + 0x7f, 0xfb, 0x9f, 0x9c, 0xff, 0x02, 0xb7, 0x9c, 0x5c, 0xe5, 0x42, 0x2f, + 0xf0, 0xa0, 0x52, 0x6f, 0xd1, 0xb5, 0x06, 0x47, 0x2f, 0xbe, 0x2d, 0x24, 0x72, 0xff, 0xcb, 0xcd, 0x62, 0x6f, 0xb1, 0xc4, 0xe5, 0xff, 0xff, 0xce, - 0x9e, 0x4e, 0xad, 0x39, 0x49, 0x3a, 0xe3, 0xe9, 0x66, 0xb0, 0xe5, 0xee, - 0xe7, 0x01, 0xca, 0xea, 0x23, 0xdd, 0xc2, 0xff, 0x86, 0x3e, 0xdc, 0x7a, - 0x02, 0x72, 0xf6, 0xd4, 0xdf, 0x23, 0xda, 0xc2, 0x2a, 0x0a, 0x70, 0x5f, - 0x12, 0x7a, 0x32, 0x8b, 0xff, 0xff, 0xfe, 0x8d, 0xc7, 0xa7, 0xc6, 0xf5, + 0x9e, 0x4e, 0xad, 0x3e, 0x49, 0x3a, 0xe3, 0xe9, 0x66, 0xb0, 0xe5, 0xee, + 0xe7, 0x01, 0xca, 0xea, 0x23, 0xdd, 0xc2, 0xff, 0x86, 0x39, 0xdc, 0x7a, + 0x02, 0x72, 0xf6, 0xd4, 0xdf, 0xc3, 0xda, 0xc2, 0x2a, 0x0a, 0x70, 0x5c, + 0x92, 0x7a, 0x32, 0x8b, 0xff, 0xff, 0xfe, 0x8d, 0xc7, 0xa7, 0xc6, 0xf5, 0x9d, 0x75, 0x37, 0x8a, 0xb8, 0xff, 0x03, 0x13, 0x76, 0x0e, 0x5f, 0xb7, 0xd7, 0x5c, 0x1c, 0xbf, 0x3c, 0xed, 0xbc, 0x8e, 0x50, 0xa3, 0x95, 0xb8, - 0x4a, 0xa8, 0x4f, 0x7f, 0xff, 0xf2, 0x2b, 0xf4, 0xbd, 0x83, 0xed, 0xf2, - 0xde, 0xf3, 0x58, 0x2f, 0x23, 0x97, 0xff, 0x73, 0x08, 0xc0, 0x17, 0x8a, + 0x4a, 0xa8, 0x4f, 0x7f, 0xff, 0xf2, 0x2b, 0xcc, 0xbd, 0x83, 0xed, 0xfc, + 0xde, 0xf3, 0x58, 0x2f, 0x23, 0x97, 0xff, 0x7d, 0x08, 0xc0, 0x17, 0x8a, 0xa6, 0x8e, 0x5d, 0x8d, 0x9c, 0xb6, 0x41, 0xee, 0xed, 0x1a, 0xfe, 0x9f, - 0xaf, 0xed, 0x41, 0xcb, 0xfc, 0x1e, 0xc4, 0xce, 0xff, 0x1c, 0xbd, 0xdf, + 0xaf, 0xed, 0x41, 0xcb, 0xfc, 0x1e, 0xc4, 0xce, 0xfc, 0x9c, 0xbd, 0xdf, 0xf8, 0x9c, 0xad, 0x1e, 0xa7, 0x01, 0xa5, 0x49, 0x19, 0xba, 0x26, 0x78, 0x41, 0x5f, 0xfd, 0x9a, 0xfd, 0x89, 0xb5, 0x37, 0x18, 0x72, 0xfc, 0x1d, - 0x47, 0xcd, 0x67, 0x2f, 0xff, 0xfd, 0xe8, 0xd7, 0xeb, 0xea, 0x49, 0x34, + 0x47, 0x2d, 0x67, 0x2f, 0xff, 0xfd, 0xe8, 0xd7, 0xeb, 0xea, 0x49, 0x34, 0xff, 0xf8, 0x61, 0x9b, 0x39, 0x73, 0x5e, 0xce, 0x52, 0xa8, 0x87, 0x76, 0xda, 0x92, 0x63, 0x78, 0x8a, 0xf0, 0xb3, 0xbc, 0xd4, 0x8f, 0xe7, 0x2e, - 0xc6, 0x1c, 0xbf, 0xfb, 0x07, 0xfe, 0x4a, 0x6b, 0xf6, 0x26, 0xce, 0x50, + 0xc6, 0x1c, 0xbf, 0xfb, 0x07, 0xff, 0x8a, 0x6b, 0xf6, 0x26, 0xce, 0x50, 0x4f, 0x7d, 0x82, 0xd7, 0xdf, 0xfb, 0x3f, 0x39, 0x7e, 0x8d, 0xed, 0x38, - 0x9c, 0xa4, 0x3e, 0xfd, 0x11, 0x74, 0x92, 0xf3, 0x4f, 0xa0, 0xe5, 0xff, - 0x2f, 0xa3, 0x1f, 0x24, 0x74, 0xe5, 0x43, 0x23, 0x86, 0x51, 0x90, 0x84, + 0x9c, 0xa4, 0x3e, 0xfd, 0x11, 0x74, 0x92, 0xf3, 0x4e, 0x60, 0xe5, 0xff, + 0x2f, 0xa3, 0x1c, 0xa4, 0x74, 0xe5, 0x43, 0x23, 0x86, 0x51, 0x90, 0x84, 0xb7, 0x23, 0xaa, 0x48, 0xc7, 0x74, 0x6c, 0xf1, 0xcf, 0x0c, 0x69, 0xfb, 0x34, 0x04, 0x3c, 0x1a, 0x17, 0x28, 0x3f, 0x7f, 0xe7, 0x40, 0x83, 0xdb, 0x9f, 0x1b, 0x39, 0x7e, 0xde, 0x2b, 0x1b, 0x39, 0x7f, 0x35, 0xed, 0x07, - 0xe9, 0x1c, 0xbf, 0xf3, 0xe9, 0xa2, 0x77, 0x1f, 0xef, 0xce, 0x5f, 0xff, - 0x93, 0xd0, 0xcc, 0xfb, 0xd0, 0xc5, 0x34, 0xff, 0x9c, 0xbe, 0x41, 0x70, - 0x9c, 0xbf, 0xed, 0xc6, 0xbd, 0x1c, 0xc2, 0x87, 0x2a, 0x48, 0xb1, 0x0a, - 0xbe, 0xc8, 0x2f, 0xff, 0xec, 0xef, 0x2c, 0x62, 0x76, 0x39, 0x6f, 0x78, + 0x99, 0x1c, 0xbf, 0xf3, 0xe9, 0xa2, 0x77, 0x1f, 0x9f, 0xce, 0x5f, 0xff, + 0x93, 0xd0, 0xcc, 0xe7, 0xd0, 0xc5, 0x34, 0xff, 0x9c, 0xbe, 0x41, 0x70, + 0x9c, 0xbf, 0xed, 0xc6, 0xbd, 0x1f, 0x42, 0x87, 0x2a, 0x48, 0xb1, 0x0a, + 0xbe, 0xc8, 0x2f, 0xff, 0xec, 0xef, 0xcc, 0x62, 0x76, 0x3e, 0x6f, 0x78, 0x3f, 0x9c, 0xbf, 0xf9, 0x35, 0x12, 0xec, 0x4c, 0x20, 0x54, 0xe5, 0x75, 0x14, 0x7b, 0x5e, 0xb9, 0x6d, 0x0e, 0x5f, 0xca, 0xfa, 0x3b, 0x1b, 0x39, - 0x7f, 0x75, 0x3e, 0xdb, 0xfc, 0x72, 0xa4, 0x7e, 0xc8, 0x33, 0xf9, 0x75, + 0x7f, 0x75, 0x39, 0xdb, 0xf2, 0x72, 0xa4, 0x7e, 0xc8, 0x33, 0xf9, 0x75, 0xff, 0xd8, 0xe3, 0x3b, 0x78, 0x21, 0xec, 0x1c, 0xbc, 0xb8, 0x6b, 0x39, 0x7f, 0xa6, 0xeb, 0xeb, 0x48, 0x13, 0x95, 0x87, 0xa6, 0xe3, 0xf7, 0xc9, 0xd7, 0x61, 0xcb, 0xfe, 0x11, 0xc9, 0xfd, 0xe8, 0x61, 0xca, 0x99, 0x30, 0xf1, 0x84, 0xb7, 0x88, 0x14, 0x21, 0xbf, 0x6b, 0x36, 0x8d, 0x9c, 0xbd, 0x0d, 0x45, 0xce, 0x5f, 0xca, 0x40, 0x16, 0x06, 0x1c, 0xb9, 0x04, 0xe5, 0xf4, 0xa0, 0x56, 0x72, 0x82, 0x6d, 0xb0, 0x56, 0xfe, 0x8f, 0x70, 0x8f, - 0x1f, 0x1c, 0xae, 0x47, 0xa4, 0x84, 0x17, 0xd1, 0xfe, 0x09, 0xca, 0x92, + 0x1c, 0x9c, 0xaf, 0x87, 0xa4, 0x84, 0x17, 0xd1, 0xfe, 0x09, 0xca, 0x92, 0xeb, 0xee, 0x14, 0x2c, 0xc5, 0x21, 0xe5, 0x34, 0x34, 0xf5, 0x09, 0x96, 0x46, 0x7c, 0xe8, 0x9b, 0x28, 0x01, 0x0b, 0x70, 0xb7, 0x68, 0x47, 0x7c, 0xce, 0x14, 0xd4, 0x5a, 0xb3, 0x97, 0x7b, 0x67, 0x29, 0x0f, 0x2e, 0x63, 0x4b, 0xe5, 0x21, 0xbd, 0x9c, 0xbb, 0xff, 0x1c, 0xbb, 0xfe, 0x9c, 0xbe, - 0xd6, 0xb3, 0x67, 0x2e, 0xc9, 0x8e, 0x5a, 0x5c, 0x91, 0x1b, 0x39, 0x23, + 0xd6, 0xb3, 0x67, 0x2e, 0xc9, 0x8e, 0x5a, 0x5f, 0x11, 0x1b, 0x39, 0x23, 0x06, 0x1c, 0x61, 0x42, 0x2b, 0xf2, 0x79, 0xc7, 0x0e, 0x5f, 0xb4, 0x1c, - 0xc1, 0x39, 0x7f, 0xf3, 0x5a, 0x67, 0x63, 0x8e, 0xfb, 0x1f, 0x1c, 0xbf, - 0xbe, 0xd0, 0x3e, 0xf4, 0x8e, 0x53, 0xa2, 0x83, 0x64, 0xc0, 0x49, 0xbf, + 0xc1, 0x39, 0x7f, 0xf3, 0x5a, 0x67, 0x63, 0x8e, 0xfb, 0x1c, 0x9c, 0xbf, + 0xb9, 0xd0, 0x39, 0xf4, 0x8e, 0x53, 0xa2, 0x83, 0x64, 0xc0, 0x49, 0xbf, 0x37, 0xef, 0x64, 0xe7, 0x2f, 0xfb, 0x07, 0x59, 0xbc, 0x4e, 0x9c, 0xbf, 0xfe, 0x97, 0x87, 0x1f, 0xc3, 0x9e, 0xf6, 0x36, 0x72, 0xec, 0xe2, 0x72, 0xff, 0x97, 0xdc, 0x0b, 0x13, 0x58, 0x72, 0xa7, 0x3d, 0x0c, 0x18, 0xbf, @@ -2880,47 +2880,47 @@ 0x5f, 0x6d, 0x33, 0xf3, 0x97, 0xd9, 0xe4, 0xd9, 0xcb, 0xf9, 0xa9, 0x98, 0x5a, 0xb9, 0xc0, 0x72, 0xb6, 0x7b, 0x7e, 0x21, 0xbf, 0xf0, 0x1d, 0x9b, 0x41, 0x7d, 0x2a, 0x72, 0xa4, 0xae, 0xe8, 0x30, 0xc5, 0xc2, 0xf5, 0x95, - 0x7c, 0x6d, 0xa8, 0x4f, 0x74, 0x88, 0x61, 0x53, 0xb2, 0x0f, 0x3e, 0xb6, - 0x45, 0x7f, 0xfe, 0xf2, 0x6e, 0x7c, 0x6f, 0x69, 0x38, 0xbf, 0xde, 0x39, + 0x72, 0x6d, 0xa8, 0x4f, 0x74, 0x88, 0x61, 0x53, 0xb2, 0x0f, 0x3e, 0xb6, + 0x45, 0x7f, 0xfe, 0xf2, 0x6e, 0x7c, 0x6f, 0x69, 0x38, 0xbf, 0x3e, 0x39, 0x79, 0xbc, 0xe9, 0xcb, 0xfd, 0xb4, 0x57, 0xae, 0x28, 0x72, 0xfd, 0x38, 0x45, 0xd5, 0x39, 0x7c, 0x9b, 0xc0, 0xe2, 0x34, 0x1d, 0x63, 0xc3, 0xaa, - 0x19, 0x5f, 0xf9, 0xda, 0xff, 0x06, 0xd0, 0x7e, 0x91, 0xcb, 0xfc, 0x1c, - 0x14, 0x6f, 0xa0, 0x39, 0x7f, 0xfd, 0xd4, 0x8f, 0x27, 0xf1, 0x2e, 0x6d, - 0xb6, 0xd9, 0x4b, 0xff, 0x92, 0x3d, 0xfc, 0x4b, 0x9b, 0x6d, 0xb6, 0x52, + 0x19, 0x5f, 0xf9, 0xda, 0xff, 0x06, 0xd0, 0x79, 0x91, 0xcb, 0xfc, 0x1c, + 0x14, 0x6f, 0xa0, 0x39, 0x7f, 0xfd, 0xd4, 0x8f, 0x27, 0xf1, 0x2f, 0xad, + 0xb6, 0xd9, 0x4b, 0xff, 0x92, 0x3d, 0xfc, 0x4b, 0xeb, 0x6d, 0xb6, 0x52, 0xb1, 0x13, 0xfd, 0x55, 0xa9, 0xd1, 0xe9, 0xe8, 0x69, 0x5f, 0xee, 0x81, 0xd8, 0x17, 0x61, 0xca, 0x13, 0xdc, 0xf1, 0x4d, 0xf0, 0x73, 0x15, 0x29, - 0x7c, 0xff, 0xbf, 0x8e, 0x5f, 0xf6, 0x9d, 0x7c, 0xbb, 0x0a, 0x09, 0xcb, + 0x7c, 0xff, 0xbf, 0x8e, 0x5f, 0xf6, 0x9d, 0x7f, 0x3b, 0x0a, 0x09, 0xcb, 0xc0, 0x8d, 0x1c, 0xbb, 0xdb, 0x09, 0xeb, 0xcc, 0x77, 0x7a, 0x42, 0x03, 0x44, 0x32, 0xbd, 0xd8, 0x9c, 0xe5, 0xfb, 0xd1, 0x25, 0x58, 0x72, 0xf3, - 0x6d, 0xb6, 0x52, 0xf6, 0x0a, 0xca, 0x73, 0x34, 0x17, 0xfe, 0xc9, 0xf0, + 0x6d, 0xb6, 0x52, 0xf6, 0x0a, 0xca, 0x7d, 0x34, 0x17, 0xfe, 0xc9, 0xf0, 0x2f, 0x21, 0x89, 0xce, 0x54, 0x22, 0xd3, 0xf4, 0x91, 0x2d, 0xbe, 0x71, 0x6a, 0x1c, 0x31, 0xcb, 0x9a, 0x83, 0x50, 0x39, 0x7e, 0xcf, 0x78, 0x13, 0x9c, 0xb4, 0x9a, 0x81, 0xe6, 0x09, 0x1d, 0xe7, 0x6b, 0x83, 0x97, 0xec, 0x0f, 0x5d, 0xac, 0xe5, 0xf8, 0x70, 0x30, 0xc3, 0x95, 0x0a, 0xc9, 0xe7, - 0x21, 0x09, 0x16, 0x3c, 0xfc, 0x5f, 0x31, 0x4e, 0xa1, 0xa3, 0xd2, 0xf7, + 0x21, 0x09, 0x16, 0x3c, 0xf2, 0x5f, 0x31, 0x4e, 0xa1, 0xa3, 0xd2, 0xf7, 0x78, 0x01, 0x6f, 0x11, 0xe6, 0xca, 0xaf, 0xe6, 0x62, 0x6a, 0x69, 0x1c, 0xbf, 0xfe, 0x55, 0x47, 0x1e, 0xbc, 0xb7, 0x8c, 0x86, 0xb3, 0x95, 0x08, 0x81, 0x42, 0xeb, 0xde, 0x48, 0x39, 0x76, 0x09, 0xca, 0x43, 0x60, 0x01, - 0xbb, 0xf0, 0xc7, 0xd1, 0xb3, 0x97, 0xfe, 0xc4, 0x17, 0xf6, 0xdb, 0x81, + 0xbb, 0xf0, 0xc7, 0x31, 0xb3, 0x97, 0xfe, 0xc4, 0x17, 0xf6, 0xdb, 0x81, 0x39, 0x7b, 0xaf, 0xa8, 0x3e, 0x3d, 0x93, 0xdf, 0x26, 0xa3, 0xc7, 0x2f, - 0xb7, 0x91, 0x23, 0x94, 0x13, 0xc2, 0x12, 0x1b, 0xf4, 0x4b, 0xb9, 0xf1, - 0xcb, 0xbe, 0xfc, 0xe5, 0xfc, 0xc8, 0xdf, 0xe8, 0xb3, 0x97, 0xb7, 0x0a, + 0xb7, 0x91, 0x23, 0x94, 0x13, 0xc2, 0x12, 0x1b, 0xf4, 0x4b, 0xb9, 0xc9, + 0xcb, 0xb9, 0xfc, 0xe5, 0xfc, 0xc8, 0xdf, 0xe8, 0xb3, 0x97, 0xb7, 0x0a, 0xfe, 0x78, 0xfb, 0x19, 0xbf, 0xc0, 0xcd, 0x7f, 0xfa, 0x09, 0xcb, 0xce, 0xd5, 0xce, 0x72, 0xff, 0xd8, 0xc4, 0x0e, 0xb0, 0x2e, 0xc3, 0x97, 0xd8, 0xc5, 0x02, 0x72, 0xba, 0x7c, 0x02, 0x7b, 0x7f, 0xf9, 0x03, 0xd5, 0x37, 0x9a, 0x5b, 0xba, 0xcd, 0x10, 0x62, 0xff, 0xdd, 0x03, 0xab, 0x9e, 0xf6, - 0x74, 0xe5, 0xff, 0xb7, 0xfb, 0xfd, 0xb5, 0x35, 0xd7, 0x39, 0x7c, 0x0e, + 0x74, 0xe5, 0xff, 0xb7, 0xfb, 0xf3, 0xb5, 0x35, 0xd7, 0x39, 0x7c, 0x0e, 0xe2, 0xce, 0x54, 0x91, 0xf4, 0x15, 0x7f, 0x1f, 0xb4, 0x42, 0xbf, 0xed, 0xee, 0x35, 0x25, 0xa4, 0xe7, 0x2f, 0xe0, 0x2a, 0x39, 0x38, 0x0e, 0x54, 0x1f, 0x4f, 0x4e, 0xaf, 0x74, 0x0d, 0x67, 0x2f, 0xff, 0x69, 0xf8, 0xe0, 0xaf, 0xa9, 0xfa, 0x9e, 0x39, 0x50, 0x99, 0xb4, 0xa1, 0x51, 0xc3, 0x90, - 0x80, 0x82, 0xbe, 0x57, 0x07, 0xd3, 0x51, 0x34, 0xdc, 0x20, 0xbd, 0x29, + 0x80, 0x82, 0xb9, 0x57, 0x07, 0xd3, 0x51, 0x34, 0xdc, 0x20, 0xbd, 0x29, 0x46, 0xfd, 0xe4, 0x5a, 0x04, 0xe5, 0xfe, 0xd0, 0x1d, 0x40, 0x3a, 0x87, 0x2e, 0xe3, 0x87, 0x2b, 0x0f, 0x35, 0xcd, 0x6e, 0xff, 0xf3, 0x97, 0xfc, 0xbe, 0xa6, 0x85, 0x3d, 0xb3, 0x94, 0xc3, 0xd1, 0xfc, 0x66, 0xff, 0x7e, - 0x9d, 0xee, 0x7e, 0xe7, 0x2f, 0xff, 0xf9, 0x99, 0xef, 0x3e, 0x86, 0x3e, + 0x9d, 0xee, 0x7e, 0xe7, 0x2f, 0xff, 0xf9, 0x99, 0xef, 0x3e, 0x86, 0x39, 0x92, 0x9a, 0xfd, 0x89, 0xb3, 0x97, 0xfc, 0xc4, 0x6f, 0x04, 0x3d, 0x83, - 0x97, 0x74, 0x07, 0x2f, 0xff, 0xd2, 0x41, 0x0f, 0x73, 0xe5, 0x1c, 0x7c, + 0x97, 0x74, 0x07, 0x2f, 0xff, 0xd2, 0x41, 0x0f, 0x73, 0x95, 0x1c, 0x7c, 0x21, 0x39, 0x79, 0x1b, 0x6b, 0x39, 0x7f, 0xb3, 0x8e, 0xfd, 0xe8, 0x61, 0xca, 0xd1, 0xea, 0xf4, 0x82, 0xa1, 0x38, 0x4c, 0x69, 0x43, 0x89, 0x85, 0xf7, 0x0a, 0xab, 0xf9, 0x18, 0xbc, 0x15, 0x9c, 0xbf, 0xb3, 0x6d, 0x33, @@ -2928,24 +2928,24 @@ 0x1d, 0x16, 0x42, 0x92, 0xfc, 0xa6, 0x58, 0x63, 0xa3, 0xb8, 0xfe, 0x47, 0xb8, 0xee, 0x3d, 0x0a, 0x8b, 0xfd, 0xbd, 0xe0, 0xfe, 0xd3, 0x0e, 0x5f, 0x0a, 0x70, 0x41, 0xcb, 0xe5, 0x07, 0x36, 0x72, 0xd3, 0x1c, 0xbf, 0xb7, - 0x83, 0xfb, 0x4c, 0x39, 0x5c, 0x91, 0x77, 0x86, 0xae, 0x47, 0xf9, 0x16, + 0x83, 0xfb, 0x4c, 0x39, 0x5f, 0x11, 0x77, 0x86, 0xae, 0x47, 0xf9, 0x16, 0xc4, 0xaf, 0xbc, 0xee, 0x27, 0x2b, 0x89, 0xf5, 0xb6, 0x97, 0x7f, 0xc0, - 0xf7, 0xe0, 0x64, 0x67, 0x8e, 0x5f, 0xfe, 0x19, 0xf9, 0x4c, 0x83, 0x81, - 0xc1, 0x54, 0xe5, 0xfc, 0x9f, 0x70, 0x76, 0x3c, 0x72, 0xf2, 0x99, 0x07, + 0xf7, 0xe0, 0x64, 0x67, 0x8e, 0x5f, 0xfe, 0x19, 0xfe, 0x4c, 0x83, 0x81, + 0xc1, 0x54, 0xe5, 0xfc, 0x9c, 0xf0, 0x76, 0x3c, 0x72, 0xf2, 0x99, 0x07, 0x2f, 0xfb, 0xb8, 0x1d, 0x3a, 0xfd, 0xf9, 0xca, 0x84, 0x69, 0xb5, 0xa6, 0x39, 0x8e, 0xc7, 0x2f, 0xff, 0xf6, 0x0b, 0xfb, 0x79, 0xaf, 0xff, 0x8c, - 0xfb, 0xdb, 0x43, 0x97, 0x63, 0x43, 0x96, 0x70, 0x9f, 0xcf, 0x98, 0x6f, - 0x46, 0xa6, 0x39, 0x5c, 0x9d, 0x04, 0x04, 0x4e, 0xde, 0xcf, 0x18, 0x70, - 0x61, 0x5f, 0x93, 0x81, 0xab, 0x8d, 0xe7, 0xe5, 0x24, 0x9c, 0xba, 0xec, + 0xe7, 0xdb, 0x43, 0x97, 0x63, 0x43, 0x96, 0x70, 0x9f, 0xcf, 0x98, 0x6f, + 0x46, 0xa6, 0x39, 0x5f, 0x1d, 0x04, 0x04, 0x4e, 0xde, 0xcf, 0x18, 0x70, + 0x61, 0x5f, 0x93, 0x81, 0xab, 0x8d, 0xe7, 0x95, 0x24, 0x9c, 0xba, 0xec, 0x66, 0x0f, 0x49, 0x3f, 0xfe, 0x3d, 0x81, 0x25, 0x04, 0x61, 0xad, 0xc2, - 0xdd, 0xa1, 0x3d, 0xef, 0xa7, 0xe2, 0x72, 0xfc, 0xbe, 0xc7, 0xdc, 0x07, - 0x2f, 0xdd, 0x7d, 0x31, 0x0e, 0x5f, 0xca, 0x2f, 0xb1, 0xf7, 0x01, 0xca, - 0xe4, 0x88, 0x65, 0x96, 0x00, 0x9e, 0xf7, 0x2f, 0xdb, 0x39, 0x5f, 0x1e, + 0xdd, 0xa1, 0x3d, 0xee, 0x67, 0xe2, 0x72, 0xfc, 0xbe, 0xc7, 0x3c, 0x07, + 0x2f, 0xdd, 0x7d, 0x31, 0x0e, 0x5f, 0xca, 0x2f, 0xb1, 0xcf, 0x01, 0xca, + 0xf8, 0x88, 0x65, 0x96, 0x00, 0x9e, 0xf7, 0xcf, 0xdb, 0x39, 0x5c, 0x9e, 0x9f, 0x8c, 0xaf, 0xec, 0x6f, 0x30, 0x55, 0x39, 0x7c, 0xc7, 0xcd, 0x9c, 0xa4, 0x3c, 0xe7, 0x2d, 0xbf, 0xfe, 0x5c, 0x6f, 0x70, 0xcc, 0xf2, 0x6f, 0xae, 0x72, 0xff, 0x08, 0xc4, 0x99, 0x08, 0x72, 0xff, 0x79, 0x38, 0xa7, - 0xa5, 0x05, 0x2c, 0xc3, 0x97, 0xf6, 0x0a, 0xba, 0x8e, 0x68, 0x78, 0xaa, - 0x1a, 0x56, 0x26, 0x12, 0x89, 0xdb, 0x75, 0xbc, 0x0f, 0xa4, 0x72, 0xfa, + 0xa5, 0x05, 0x2c, 0xc3, 0x97, 0xf6, 0x0a, 0xba, 0x8f, 0xa8, 0x78, 0xaa, + 0x1a, 0x56, 0x26, 0x12, 0x89, 0xdb, 0x75, 0xbc, 0x0e, 0x64, 0x72, 0xfa, 0x5a, 0x7e, 0x27, 0x2b, 0x47, 0x84, 0x23, 0xd7, 0xf8, 0x64, 0x38, 0xc8, 0x59, 0xcb, 0xcf, 0xb4, 0x39, 0x6c, 0x39, 0x7b, 0x31, 0x53, 0x96, 0x60, 0x4d, 0x67, 0x00, 0x85, 0x42, 0x30, 0xf0, 0x87, 0xa6, 0x2e, 0x8f, 0x7f, @@ -2955,30 +2955,30 @@ 0x11, 0x5e, 0x55, 0x4e, 0x9c, 0xbf, 0xfe, 0x4f, 0x76, 0x37, 0x1d, 0x84, 0x9e, 0x15, 0x39, 0x7f, 0xbb, 0x13, 0x49, 0x35, 0x23, 0x97, 0xfb, 0xc8, 0xdc, 0xc2, 0xed, 0x9c, 0xbf, 0x7b, 0xdb, 0x7f, 0xce, 0x5f, 0xa1, 0x9e, - 0xc5, 0x9c, 0xb9, 0x27, 0x39, 0x50, 0x98, 0xf8, 0x53, 0xfe, 0x34, 0x43, + 0xc5, 0x9c, 0xb9, 0x27, 0x39, 0x50, 0x98, 0xf8, 0x53, 0xf9, 0x34, 0x43, 0x5e, 0x94, 0xf8, 0x9e, 0xfc, 0xda, 0x07, 0x81, 0x0e, 0x5f, 0xf7, 0x62, 0x48, 0x38, 0xc8, 0x39, 0x7f, 0xd9, 0xee, 0xe3, 0x05, 0xfc, 0x72, 0xfe, - 0xe2, 0x9a, 0xfa, 0x1a, 0xce, 0x58, 0x42, 0x7d, 0x58, 0x6f, 0x7e, 0x64, + 0xe2, 0x9a, 0xe6, 0x1a, 0xce, 0x58, 0x42, 0x7d, 0x58, 0x6f, 0x7e, 0x64, 0x2e, 0x70, 0x9c, 0xbe, 0x94, 0x31, 0xce, 0x5f, 0xb5, 0xfb, 0x13, 0x67, 0x2e, 0xf6, 0xf0, 0xfc, 0xdc, 0xa5, 0x42, 0x1a, 0x84, 0x69, 0x82, 0x13, 0x36, 0xd9, 0xcb, 0xfa, 0x27, 0xc1, 0x45, 0x4e, 0x56, 0x8d, 0xf6, 0xc4, - 0x6f, 0xfe, 0x81, 0x7e, 0xc7, 0xfc, 0xf5, 0xbd, 0x94, 0xa9, 0xd5, 0x1f, + 0x6f, 0xfe, 0x81, 0x7e, 0xc7, 0xff, 0x75, 0xbd, 0x94, 0xa9, 0xd5, 0x1f, 0x86, 0x37, 0x3c, 0x65, 0x61, 0x0d, 0xf9, 0xe6, 0x4c, 0xd9, 0xcb, 0xed, - 0xc6, 0xa4, 0x72, 0xe7, 0x0f, 0x23, 0xc9, 0xd9, 0x3d, 0xc0, 0x9c, 0xe5, - 0xfe, 0xfa, 0x5f, 0x6d, 0x3d, 0x07, 0x2f, 0x27, 0xdb, 0x39, 0x58, 0x7a, + 0xc6, 0xa4, 0x72, 0xe7, 0x0f, 0xc3, 0xc9, 0xd9, 0x3d, 0xc0, 0x9c, 0xe5, + 0xfe, 0xe6, 0x5c, 0xed, 0x3d, 0x07, 0x2f, 0x27, 0x3b, 0x39, 0x58, 0x7a, 0x48, 0x6b, 0x48, 0x88, 0xae, 0xb5, 0x5d, 0x8b, 0x39, 0x7b, 0x59, 0xb3, - 0x9e, 0x2d, 0xaf, 0xff, 0x83, 0xc9, 0xd3, 0x37, 0x13, 0xe0, 0xa2, 0xa7, - 0x2f, 0xf6, 0x99, 0x1f, 0x79, 0xd6, 0x72, 0xff, 0xfe, 0x1c, 0xf7, 0x72, + 0x9e, 0x2d, 0xaf, 0xff, 0x83, 0xf1, 0xd3, 0x37, 0x13, 0xe0, 0xa2, 0xa7, + 0x2f, 0xf6, 0x99, 0x1c, 0xf9, 0xd6, 0x72, 0xff, 0xfe, 0x1c, 0xf7, 0x72, 0x58, 0xb8, 0x5f, 0x85, 0xd8, 0x72, 0xb1, 0x1b, 0x88, 0xa1, 0xb3, 0x4b, - 0xe4, 0x64, 0x4c, 0x72, 0xff, 0xed, 0xa7, 0xc3, 0x93, 0x6a, 0x3d, 0xb3, + 0xe4, 0x64, 0x4c, 0x72, 0xff, 0xed, 0xa7, 0x23, 0x93, 0x6a, 0x3d, 0xb3, 0x97, 0xd9, 0x38, 0x24, 0x72, 0xa6, 0x44, 0x57, 0xe4, 0x4d, 0xa2, 0xdf, 0xed, 0xc4, 0x9e, 0x77, 0x61, 0xcb, 0xfb, 0xf9, 0xde, 0x50, 0xd6, 0x72, - 0xf0, 0x43, 0x07, 0x2b, 0xe3, 0xce, 0x01, 0x95, 0x42, 0x35, 0xd0, 0xcd, + 0xf0, 0x43, 0x07, 0x2b, 0x93, 0xce, 0x01, 0x95, 0x42, 0x35, 0xd0, 0xcd, 0xe1, 0x03, 0x76, 0x36, 0x72, 0x8b, 0x88, 0x61, 0x7f, 0x6d, 0x48, 0xd4, 0x30, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x52, 0x45, 0xca, 0x0c, 0xfe, 0x78, 0x01, 0x96, 0x83, 0x3c, 0x03, 0x37, 0x77, 0x0b, 0x88, 0x61, 0x7f, 0x3b, 0xfa, 0x68, - 0x61, 0x71, 0x0c, 0x39, 0x1a, 0x4b, 0x70, 0xe5, 0xc4, 0x30, 0xa2, 0xe2, + 0x61, 0x71, 0x0c, 0x3e, 0x1a, 0x4b, 0x70, 0xe5, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x2a, 0x46, 0xc9, 0x06, 0x68, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa9, 0xd1, 0x2c, 0x11, 0x94, 0x19, 0xfc, 0x67, 0x63, @@ -2988,68 +2988,68 @@ 0x28, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x4e, 0x7c, 0x8a, 0x8c, 0xe8, 0x67, 0xa3, 0x36, 0x54, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x41, 0x3e, - 0x4f, 0x86, 0x7f, 0x19, 0x00, 0xcd, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, + 0x4e, 0x46, 0x7f, 0x19, 0x00, 0xcd, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xbf, 0x76, 0x3f, 0xde, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x52, 0x44, 0xd2, 0xc6, 0x7a, 0x32, 0xe3, 0x3f, 0x9b, 0x59, 0x65, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x14, - 0x5c, 0x43, 0x0a, 0x91, 0xf2, 0x7c, 0x32, 0x83, 0x3c, 0x46, 0x68, 0xb8, + 0x5c, 0x43, 0x0a, 0x91, 0xf2, 0x72, 0x32, 0x83, 0x3c, 0x46, 0x68, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0xa4, 0x7c, 0x81, 0x19, 0xe8, 0xc8, 0x8c, 0xdb, 0xa5, 0xc4, 0x30, 0xa2, 0xe2, - 0x18, 0x51, 0x71, 0x0c, 0x2d, 0x22, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x3e, + 0x18, 0x51, 0x71, 0x0c, 0x2d, 0x22, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x39, 0x2f, 0xe8, 0xb8, 0x86, 0x14, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0xa7, 0x46, 0xf4, 0x86, 0x55, 0x38, 0x59, 0x4c, 0xc3, 0x3f, 0x8c, 0xf8, 0x66, 0xd8, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, - 0xc2, 0xd2, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc3, 0xe2, 0xfe, 0x8b, 0x88, + 0xc2, 0xd2, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc3, 0x92, 0xfe, 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa8, 0x45, 0x64, 0x86, 0x50, 0xe3, 0x45, 0x2c, 0x19, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x28, 0xb8, 0x86, 0x14, 0x5c, - 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x41, 0xfe, 0xfc, 0x33, 0xa1, 0x96, 0x0c, + 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x41, 0xfe, 0xf2, 0x33, 0xa1, 0x96, 0x0c, 0x88, 0xcd, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xad, 0x1e, 0x5e, 0xc6, 0x7c, 0x33, 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x51, 0x71, 0x0c, 0x29, 0x87, 0x96, 0x23, 0x3e, 0x19, 0xb3, 0x0b, 0x88, 0x61, 0x45, 0xc4, 0x30, 0xa2, 0xe2, 0x18, 0x57, 0xe6, 0xc8, 0x03, 0x34, 0x5c, 0x43, 0x0a, 0x2e, 0x21, 0x85, 0x17, 0x10, 0xc2, 0x8b, 0x88, 0x61, 0x50, 0x7c, 0x93, 0x0c, 0xf4, 0x64, 0x03, 0x35, 0x0c, 0xc1, 0x49, 0xe1, 0x01, - 0x24, 0xd0, 0xab, 0x64, 0x2d, 0x97, 0x08, 0xcf, 0xa1, 0x0a, 0x90, 0xa4, + 0x24, 0xd0, 0xab, 0x64, 0x2d, 0x97, 0x08, 0xce, 0x61, 0x0a, 0x90, 0xa4, 0x6b, 0x3e, 0x9a, 0x10, 0x9a, 0x86, 0xc3, 0x12, 0xbb, 0x08, 0x37, 0x85, 0x17, 0xe7, 0x63, 0x0f, 0xdd, 0xb4, 0x7a, 0x19, 0x40, 0x86, 0x2f, 0x18, 0x49, 0xb6, 0xf4, 0xd0, 0xb9, 0x45, 0x1e, 0x08, 0x43, 0x5f, 0xa4, 0x31, - 0x9b, 0x2e, 0x21, 0x87, 0x34, 0xe5, 0xaf, 0x24, 0x30, 0xb8, 0x86, 0x17, - 0xc8, 0xb7, 0xd1, 0xf1, 0x0c, 0x5e, 0x40, 0xe1, 0xf1, 0x0c, 0x5b, 0x9f, - 0xc8, 0xc8, 0xd2, 0x4f, 0x4a, 0x7c, 0x5d, 0x68, 0xe2, 0xcf, 0x88, 0x52, + 0x9b, 0x2e, 0x21, 0x87, 0xd4, 0xe5, 0xaf, 0x24, 0x30, 0xb8, 0x86, 0x17, + 0xc8, 0xb7, 0xd1, 0xf1, 0x0c, 0x5e, 0x40, 0xe1, 0xf1, 0x0c, 0x5b, 0xef, + 0x28, 0xc8, 0xd2, 0x4f, 0x4a, 0x7c, 0x5d, 0x68, 0xe2, 0xcf, 0x88, 0x52, 0x9e, 0x85, 0x7f, 0xba, 0x8d, 0x87, 0x51, 0x39, 0xcb, 0xc9, 0xc7, 0x87, - 0x39, 0x5f, 0x22, 0x42, 0x63, 0x8f, 0x1a, 0xdf, 0xb3, 0x26, 0x75, 0x0e, + 0x39, 0x5c, 0xa2, 0x42, 0x63, 0x8f, 0x1a, 0xdf, 0xb3, 0x26, 0x75, 0x0e, 0x5f, 0xe7, 0x15, 0x26, 0x92, 0x09, 0xcb, 0xbf, 0x83, 0x97, 0xf6, 0x9c, 0x54, 0x8f, 0xce, 0x5c, 0xfa, 0x39, 0x64, 0x38, 0xb2, 0xda, 0xcb, 0x39, - 0x66, 0x1c, 0xb7, 0x34, 0x44, 0xe6, 0x85, 0xfa, 0x88, 0xe3, 0xea, 0x08, + 0x66, 0x1c, 0xb7, 0xd4, 0x44, 0xe6, 0x85, 0xfa, 0x88, 0xe3, 0xea, 0x08, 0xd3, 0x13, 0x20, 0x69, 0x0c, 0xfb, 0xfe, 0xec, 0x33, 0x26, 0x81, 0x9c, - 0xe5, 0xff, 0xdc, 0x9d, 0x61, 0xec, 0x7f, 0x83, 0xf9, 0xcb, 0xbf, 0x83, + 0xe5, 0xff, 0xdf, 0x1d, 0x61, 0xec, 0x7f, 0x83, 0xf9, 0xcb, 0xbf, 0x83, 0x95, 0x87, 0xbd, 0xfa, 0x3d, 0x62, 0x39, 0x3f, 0x2b, 0x04, 0x25, 0xef, - 0xfe, 0x11, 0x89, 0xc7, 0x13, 0x8c, 0x34, 0x39, 0x7a, 0x3e, 0xd9, 0xca, + 0xfe, 0x11, 0x89, 0xc7, 0x13, 0x8c, 0x34, 0x39, 0x7a, 0x39, 0xd9, 0xca, 0x73, 0xe2, 0xda, 0x2d, 0xe7, 0xd4, 0x1c, 0xbf, 0x23, 0x47, 0x1f, 0xce, - 0x5f, 0x93, 0xed, 0xbf, 0xc7, 0x2a, 0x47, 0xda, 0xc1, 0xbd, 0x94, 0xdf, - 0xf2, 0x8e, 0x1d, 0xe3, 0x21, 0xac, 0xe5, 0xec, 0xf9, 0xb3, 0x97, 0xbe, + 0x5f, 0x93, 0x9d, 0xbf, 0x27, 0x2a, 0x47, 0xda, 0xc1, 0xbd, 0x94, 0xdf, + 0xf2, 0x8e, 0x1d, 0xe3, 0x21, 0xac, 0xe5, 0xec, 0xe5, 0xb3, 0x97, 0xb9, 0xff, 0x34, 0x7b, 0x42, 0x79, 0x7d, 0xc7, 0x35, 0x23, 0x97, 0x82, 0xe2, - 0x72, 0x90, 0xdf, 0xb9, 0x25, 0xff, 0xcf, 0xad, 0x3f, 0xf1, 0xcd, 0xb6, - 0xdb, 0x39, 0x7f, 0xe5, 0x73, 0xef, 0x27, 0xb4, 0x06, 0x1c, 0xb4, 0x72, + 0x72, 0x90, 0xdf, 0xb9, 0x25, 0xff, 0xcf, 0xad, 0x3f, 0xf1, 0xf5, 0xb6, + 0xdb, 0x39, 0x7f, 0xe5, 0x73, 0x9f, 0x27, 0xb4, 0x06, 0x1c, 0xb4, 0x7c, 0x44, 0x5f, 0x92, 0xaa, 0x13, 0xd0, 0x78, 0x44, 0xed, 0xcc, 0x10, 0xaa, - 0xbf, 0xf8, 0x0a, 0x4d, 0xca, 0x14, 0x75, 0xc7, 0x4e, 0x57, 0x08, 0xe8, + 0xbf, 0xf8, 0x0a, 0x4d, 0xf2, 0x14, 0x75, 0xc7, 0x4e, 0x57, 0x08, 0xe8, 0xdd, 0x22, 0x1f, 0x53, 0xb8, 0xca, 0x32, 0x90, 0xc6, 0x69, 0x91, 0x91, - 0x2a, 0x94, 0xb8, 0xcf, 0xbe, 0x57, 0x49, 0x4d, 0x4d, 0x70, 0x8e, 0x9a, + 0x2a, 0x94, 0xb8, 0xcf, 0xb9, 0x57, 0x49, 0x4d, 0x4d, 0x70, 0x8e, 0x9a, 0x17, 0x3a, 0x38, 0x64, 0x60, 0xfd, 0x8e, 0x3d, 0xeb, 0x04, 0xaf, 0xcc, 0x86, 0x51, 0x66, 0xe1, 0x2f, 0xe9, 0x4b, 0xca, 0x23, 0x5e, 0x66, 0xd6, - 0x72, 0xf0, 0xae, 0x0e, 0x57, 0x23, 0x70, 0x83, 0xb7, 0xf3, 0x6f, 0xad, - 0x3f, 0xc7, 0x2f, 0xff, 0xdb, 0xd6, 0x92, 0x6d, 0xea, 0x3c, 0x8b, 0x40, + 0x72, 0xf0, 0xae, 0x0e, 0x57, 0xc3, 0x70, 0x83, 0xb7, 0xf3, 0x6f, 0xad, + 0x3f, 0x27, 0x2f, 0xff, 0xdb, 0xd6, 0x92, 0x6d, 0xea, 0x3c, 0x8b, 0x40, 0x9c, 0xa6, 0x22, 0x9c, 0x48, 0x9b, 0x2f, 0xbe, 0x67, 0xa3, 0x67, 0x2f, 0xdf, 0xa4, 0xe8, 0x13, 0x97, 0xda, 0x41, 0x54, 0xe5, 0xfe, 0xf4, 0x01, - 0x7d, 0x4d, 0x1c, 0xbf, 0xb1, 0x7d, 0x8f, 0xa4, 0x72, 0xfe, 0x66, 0xd1, - 0x5f, 0x36, 0x72, 0xfd, 0x1f, 0x76, 0x24, 0x72, 0xb4, 0x8d, 0xb1, 0x22, - 0xf1, 0x9a, 0x85, 0xdc, 0x06, 0x17, 0xfd, 0x9f, 0x0e, 0x7b, 0xd9, 0x39, - 0xcb, 0xbe, 0xf1, 0xcb, 0xf6, 0x0c, 0xe9, 0xa3, 0x97, 0xef, 0x38, 0x83, + 0x7d, 0x4d, 0x1c, 0xbf, 0xb1, 0x7d, 0x8e, 0x64, 0x72, 0xfe, 0x66, 0xd1, + 0x5f, 0x36, 0x72, 0xfd, 0x1c, 0xf6, 0x24, 0x72, 0xb4, 0x8d, 0xb1, 0x22, + 0xf1, 0x9a, 0x85, 0xdc, 0x06, 0x17, 0xfd, 0x9c, 0x8e, 0x7b, 0xd9, 0x39, + 0xcb, 0xb9, 0xf1, 0xcb, 0xf6, 0x0c, 0xe9, 0xa3, 0x97, 0xef, 0x38, 0x83, 0x0e, 0x5f, 0xed, 0xe3, 0x13, 0xdd, 0x73, 0x96, 0x8c, 0x44, 0xbe, 0x86, - 0x04, 0x9f, 0xc4, 0xd7, 0xb9, 0x31, 0x0e, 0x5c, 0x2c, 0x39, 0x52, 0x36, + 0x04, 0x9f, 0xc4, 0xd7, 0xbe, 0x31, 0x0e, 0x5c, 0x2c, 0x39, 0x52, 0x36, 0x9b, 0x1e, 0xbd, 0xc1, 0xa8, 0x39, 0x7f, 0xdd, 0x4d, 0x75, 0xf8, 0x46, - 0xdb, 0x39, 0x7f, 0xb4, 0x93, 0x0e, 0x71, 0x73, 0x96, 0xdf, 0x24, 0x5a, - 0x41, 0x0e, 0x0f, 0xe9, 0x02, 0xf9, 0xc4, 0x18, 0x72, 0xbe, 0x3e, 0x3f, + 0xdb, 0x39, 0x7f, 0xb4, 0x93, 0x0e, 0x71, 0x73, 0x96, 0xdf, 0xc4, 0x5a, + 0x41, 0x0e, 0x0f, 0xe9, 0x02, 0xf9, 0xc4, 0x18, 0x72, 0xb9, 0x3e, 0x3f, 0xd0, 0xef, 0xf8, 0x61, 0xe7, 0xec, 0x6b, 0xf3, 0x97, 0xf9, 0x34, 0x3e, 0xf6, 0x4e, 0x72, 0xe7, 0xe2, 0x72, 0xfe, 0x90, 0xa4, 0xbb, 0x87, 0x2f, 0xd3, 0xa6, 0xa2, 0x47, 0x29, 0x54, 0x4f, 0xcc, 0x67, 0xa1, 0x81, 0x2c, @@ -3057,21 +3057,21 @@ 0x55, 0x7b, 0x5f, 0xa8, 0x72, 0xff, 0xe4, 0xf4, 0x7b, 0x7d, 0x74, 0xe8, 0x0e, 0x54, 0x1f, 0x13, 0x8f, 0xdf, 0x08, 0x82, 0x47, 0x2f, 0xfd, 0xd8, 0xd7, 0xe3, 0x8d, 0xbf, 0xe7, 0x2f, 0x66, 0x4c, 0x72, 0xd9, 0xd3, 0xdc, - 0xfd, 0x02, 0xf4, 0x7c, 0xd9, 0xcb, 0xf6, 0x80, 0xc7, 0x13, 0x95, 0xe3, - 0xc5, 0x00, 0xf5, 0xf3, 0x23, 0x27, 0x39, 0x7e, 0xce, 0x23, 0x1f, 0x1c, + 0xfd, 0x02, 0xf4, 0x72, 0xd9, 0xcb, 0xf6, 0x80, 0xc7, 0x13, 0x95, 0xe3, + 0xc5, 0x00, 0xf5, 0xf3, 0x23, 0x27, 0x39, 0x7e, 0xce, 0x23, 0x1c, 0x9c, 0xa4, 0x3c, 0xbd, 0x91, 0x5f, 0x40, 0xf9, 0x67, 0x28, 0x2a, 0xe6, 0x32, 0x1b, 0x1a, 0x84, 0x2f, 0x61, 0x04, 0xe4, 0x02, 0xfb, 0xb6, 0xdf, 0x36, 0xb4, 0x21, 0xbf, 0xdf, 0xa9, 0x82, 0x1e, 0xc1, 0xca, 0x84, 0x61, 0x3c, - 0x23, 0xaf, 0xed, 0xe3, 0x13, 0xb0, 0x72, 0xf7, 0xd2, 0xd9, 0xca, 0xf8, + 0x23, 0xaf, 0xed, 0xe3, 0x13, 0xb0, 0x72, 0xf7, 0x32, 0xd9, 0xca, 0xe4, 0xf2, 0xb4, 0x59, 0x7b, 0x7f, 0xb6, 0x72, 0xff, 0xa4, 0xc7, 0x97, 0xb7, 0x0a, 0x9c, 0xa8, 0x3f, 0xcc, 0x23, 0x71, 0xfb, 0xff, 0x23, 0x63, 0x9a, 0xdf, 0x71, 0x67, 0x2f, 0x80, 0xfa, 0x91, 0xcb, 0xe8, 0x07, 0x0f, 0xb2, - 0x97, 0xe9, 0x73, 0x6d, 0xb6, 0xce, 0x50, 0x9e, 0xa8, 0x09, 0xef, 0x9f, + 0x97, 0xe9, 0x7d, 0x6d, 0xb6, 0xce, 0x50, 0x9e, 0xa8, 0x09, 0xef, 0x9f, 0xcc, 0xf1, 0xca, 0x0a, 0x2e, 0xb1, 0xdf, 0xf2, 0x1b, 0xfd, 0xf8, 0xe7, 0x1d, 0x26, 0xce, 0x5f, 0xe5, 0x04, 0x5d, 0xb7, 0xe9, 0xca, 0x86, 0x59, - 0x26, 0x18, 0x7c, 0x44, 0x91, 0x82, 0x69, 0x35, 0x90, 0xd0, 0x78, 0xe2, + 0x26, 0x18, 0x72, 0x44, 0x91, 0x82, 0x69, 0x35, 0x90, 0xd0, 0x78, 0xe2, 0xff, 0x9c, 0x7e, 0x18, 0x76, 0x6c, 0xb0, 0x10, 0xf8, 0xe2, 0x60, 0xd9, - 0xad, 0xe6, 0xa9, 0xa8, 0xf0, 0x87, 0x2f, 0x48, 0x5c, 0xe5, 0xbe, 0x6a, + 0xad, 0xe6, 0xa9, 0xa8, 0xf0, 0x87, 0x2f, 0x48, 0x5c, 0xe5, 0xb9, 0x6a, 0x8f, 0x22, 0x0b, 0x6f, 0xdc, 0x11, 0x2d, 0x41, 0xcb, 0xde, 0x7f, 0xce, 0x5f, 0xd1, 0xa9, 0xe3, 0x53, 0x9c, 0xbf, 0xf4, 0x0f, 0xba, 0x07, 0x94, 0xa0, 0xe5, 0xf8, 0x1f, 0xe0, 0xac, 0xe5, 0xed, 0x44, 0xc7, 0x2f, 0x90, @@ -3082,37 +3082,37 @@ 0x1d, 0x12, 0x1f, 0x42, 0x2f, 0x8b, 0x1d, 0xff, 0x42, 0x76, 0x19, 0x3e, 0x36, 0x72, 0xfd, 0xd4, 0x9d, 0xc4, 0xe5, 0xf8, 0x0a, 0xb8, 0xfe, 0x72, 0xfe, 0xde, 0xa3, 0x02, 0x87, 0x2a, 0x0f, 0xf3, 0xa4, 0xfc, 0x4a, 0x6f, - 0xfa, 0x71, 0xc9, 0x77, 0x3f, 0xd9, 0xcb, 0xff, 0x60, 0xfd, 0x2d, 0xe8, + 0xfa, 0x71, 0xc9, 0x77, 0x3f, 0xd9, 0xcb, 0xff, 0x60, 0xf3, 0x2d, 0xe8, 0x11, 0xf9, 0xcb, 0xf6, 0x7b, 0x78, 0xa9, 0xca, 0x43, 0xe8, 0x62, 0x05, - 0xff, 0xb5, 0xd6, 0xdc, 0x3c, 0x7d, 0x8b, 0x39, 0x7e, 0xf7, 0x2e, 0xe7, + 0xff, 0xb5, 0xd6, 0xdc, 0x3c, 0x7d, 0x8b, 0x39, 0x7e, 0xf7, 0xce, 0xe7, 0x01, 0xca, 0x73, 0xef, 0x14, 0x2b, 0xc1, 0x8e, 0x27, 0x2f, 0xff, 0x08, - 0xc3, 0x61, 0x18, 0xfa, 0x48, 0x27, 0x2f, 0xcc, 0xce, 0xbf, 0x01, 0xca, - 0xc3, 0xf2, 0x44, 0x8b, 0xff, 0xcf, 0xca, 0x69, 0x46, 0xa7, 0xe4, 0xde, + 0xc3, 0x61, 0x18, 0xe6, 0x48, 0x27, 0x2f, 0xcc, 0xce, 0xbf, 0x01, 0xca, + 0xc3, 0xf2, 0x44, 0x8b, 0xff, 0xcf, 0xf2, 0x69, 0x46, 0xa7, 0xf8, 0xde, 0x74, 0xe5, 0x42, 0x64, 0x21, 0x20, 0xec, 0x24, 0x04, 0x82, 0xff, 0x99, 0xdc, 0xf6, 0x03, 0x53, 0x9c, 0xbf, 0xfb, 0xdb, 0x41, 0x9a, 0x17, 0xac, - 0xf8, 0xe5, 0xf8, 0x2a, 0xaa, 0x0f, 0x8e, 0x59, 0x57, 0x3f, 0x10, 0x22, - 0xdf, 0xf4, 0x7b, 0x34, 0xb7, 0x75, 0x9a, 0x2f, 0x85, 0xfb, 0x35, 0x1f, - 0x48, 0xe5, 0xee, 0xc3, 0x16, 0x7d, 0x9e, 0x44, 0xbf, 0xff, 0x0a, 0xf9, + 0xe4, 0xe5, 0xf8, 0x2a, 0xaa, 0x0e, 0x4e, 0x59, 0x57, 0x3f, 0x10, 0x22, + 0xdf, 0xf4, 0x7b, 0x34, 0xb7, 0x75, 0x9a, 0x2f, 0x85, 0xfb, 0x35, 0x1c, + 0xc8, 0xe5, 0xee, 0xc3, 0x16, 0x7d, 0x9e, 0x44, 0xbf, 0xff, 0x0a, 0xfe, 0x76, 0x13, 0x48, 0xc4, 0x69, 0x0c, 0x39, 0x79, 0xf5, 0x39, 0xa2, 0xff, - 0x54, 0x22, 0xd3, 0x0c, 0xd6, 0xaf, 0x7f, 0xcf, 0xed, 0xa0, 0xfd, 0x26, - 0x1c, 0xbf, 0xe8, 0xcd, 0x72, 0x92, 0x7d, 0x23, 0x95, 0xf9, 0xfa, 0x78, - 0xe6, 0xff, 0xff, 0x75, 0xf6, 0x91, 0xbe, 0x5e, 0xee, 0x33, 0x16, 0xfa, + 0x54, 0x22, 0xd3, 0x0c, 0xd6, 0xaf, 0x7f, 0xcf, 0xed, 0xa0, 0xf3, 0x26, + 0x1c, 0xbf, 0xe8, 0xcd, 0x7c, 0x92, 0x73, 0x23, 0x95, 0xf9, 0xfa, 0x78, + 0xe6, 0xff, 0xff, 0x75, 0xf6, 0x91, 0xbf, 0x9e, 0xee, 0x33, 0x16, 0xfa, 0x39, 0x74, 0x70, 0x1c, 0xbe, 0xde, 0xdd, 0x87, 0x2b, 0xa8, 0x9c, 0xfd, - 0x87, 0xc3, 0x37, 0xfe, 0x9f, 0x3e, 0xf2, 0x9d, 0xee, 0x35, 0x9c, 0xbe, - 0xfa, 0x5e, 0x73, 0x97, 0xff, 0xc1, 0x5f, 0x50, 0x73, 0x8b, 0xcb, 0x68, + 0x87, 0xc3, 0x37, 0xfe, 0x9f, 0x39, 0xf2, 0x9d, 0xee, 0x35, 0x9c, 0xbe, + 0xe6, 0x5e, 0x73, 0x97, 0xff, 0xc1, 0x5f, 0x50, 0x73, 0x8b, 0xcb, 0x68, 0x13, 0x95, 0x87, 0xe6, 0xe4, 0x77, 0xef, 0xf7, 0xec, 0xe9, 0xcb, 0xf9, 0xbf, 0x67, 0x65, 0x87, 0x2a, 0x0f, 0x5d, 0xca, 0x6a, 0x13, 0x4f, 0x94, - 0x2e, 0x05, 0xde, 0xff, 0xa1, 0x9c, 0x83, 0x99, 0xfe, 0xce, 0x5f, 0x23, + 0x2e, 0x05, 0xde, 0xff, 0xa1, 0x9f, 0x03, 0x99, 0xfe, 0xce, 0x5f, 0x23, 0x35, 0x39, 0xcb, 0xff, 0x7a, 0x37, 0xb8, 0x49, 0xdf, 0xc7, 0x2f, 0xf9, 0x30, 0x42, 0xaa, 0x66, 0x8e, 0x52, 0x23, 0x4f, 0x47, 0x7e, 0x23, 0xe0, - 0x3e, 0xbd, 0xec, 0xf8, 0xe5, 0xfc, 0xfa, 0xfa, 0x59, 0xe3, 0x97, 0xfe, + 0x3e, 0xbd, 0xec, 0xe4, 0xe5, 0xfc, 0xfa, 0xe6, 0x59, 0xe3, 0x97, 0xfe, 0xf6, 0xd3, 0x5e, 0x10, 0x3c, 0x8e, 0x5f, 0xff, 0x93, 0x78, 0x1e, 0xe7, 0x93, 0x37, 0x3e, 0x36, 0x72, 0xff, 0xf3, 0x21, 0xa6, 0x00, 0x73, 0x38, - 0xc7, 0xc7, 0x2f, 0xfd, 0x19, 0xac, 0xd7, 0xec, 0x4d, 0x9c, 0xbc, 0xff, - 0x70, 0x1c, 0xbf, 0x9f, 0xdb, 0x8c, 0x9c, 0xe5, 0x42, 0x73, 0x18, 0x5c, + 0xc7, 0x27, 0x2f, 0xfd, 0x19, 0xac, 0xd7, 0xec, 0x4d, 0x9c, 0xbc, 0xfc, + 0xf0, 0x1c, 0xbf, 0x9f, 0xdb, 0x8c, 0x9c, 0xe5, 0x42, 0x73, 0x18, 0x5c, 0xb3, 0xe4, 0x55, 0x14, 0xce, 0x27, 0xcd, 0x90, 0x5f, 0xf0, 0x21, 0x9b, 0xc6, 0x43, 0x59, 0xcb, 0xff, 0x6a, 0x7c, 0x0e, 0x77, 0xb8, 0xd6, 0x72, - 0xca, 0x9c, 0xbf, 0xde, 0xda, 0x9c, 0x63, 0x3e, 0x39, 0x6c, 0x83, 0xc9, + 0xca, 0x9c, 0xbf, 0xde, 0xda, 0x9c, 0x63, 0x39, 0x39, 0x6c, 0x83, 0xc9, 0x11, 0x2a, 0xc4, 0x58, 0x6e, 0x11, 0x77, 0xf6, 0xde, 0x43, 0x0c, 0x39, 0x7f, 0xfd, 0x28, 0xd4, 0xfe, 0x45, 0x77, 0xb7, 0x19, 0x1c, 0xbf, 0xa7, 0xde, 0x32, 0x1a, 0xce, 0x54, 0xc8, 0x82, 0x51, 0x46, 0xb4, 0x8d, 0x36, @@ -3123,71 +3123,71 @@ 0xfe, 0x97, 0x63, 0x4f, 0xe0, 0x79, 0x3d, 0xbe, 0xa1, 0xcb, 0xfb, 0x1b, 0x53, 0xaf, 0xe3, 0x97, 0xf4, 0x99, 0xe1, 0x04, 0xc7, 0x2f, 0xff, 0x94, 0x94, 0x71, 0x41, 0xff, 0x49, 0x0c, 0xc2, 0x95, 0xa4, 0x40, 0x78, 0xbe, - 0xfb, 0xaa, 0x7d, 0xe3, 0x97, 0xec, 0x66, 0x27, 0x13, 0x97, 0xa7, 0x99, + 0xfb, 0xaa, 0x73, 0xe3, 0x97, 0xec, 0x66, 0x27, 0x13, 0x97, 0xa7, 0x99, 0xac, 0xe5, 0x42, 0x72, 0xd3, 0xaa, 0xe4, 0x2b, 0xd6, 0x46, 0x84, 0xa0, 0x28, 0xbb, 0xd8, 0x72, 0xfd, 0xa4, 0x9d, 0xd8, 0x69, 0x84, 0xd7, 0xde, 0x04, 0x39, 0xa6, 0x13, 0x5d, 0xfc, 0x1a, 0x81, 0x35, 0xfe, 0x17, 0x57, 0xd1, 0xaf, 0xcd, 0x40, 0x9a, 0xff, 0x6f, 0x3a, 0x9b, 0x04, 0xe6, 0x98, 0x4d, 0x76, 0x04, 0xd3, 0x09, 0xae, 0x6d, 0xb3, 0xcc, 0x26, 0xac, 0x4d, - 0x4b, 0xe3, 0x54, 0x2e, 0x61, 0x26, 0xd0, 0x78, 0xa0, 0xb6, 0x47, 0x6f, - 0x16, 0x61, 0x33, 0x99, 0xf3, 0xd9, 0x3e, 0x54, 0x02, 0xdc, 0x79, 0xf5, + 0x4b, 0x93, 0x54, 0x2e, 0x61, 0x26, 0xd0, 0x78, 0xa0, 0xb6, 0x47, 0x6f, + 0x16, 0x61, 0x33, 0xe9, 0xf3, 0xd9, 0x39, 0x54, 0x02, 0xdc, 0x79, 0xf5, 0x0b, 0xb6, 0xa8, 0x53, 0xd8, 0x4b, 0xb9, 0x00, 0xc2, 0x47, 0x71, 0xdb, 0x7a, 0x52, 0xe5, 0xf3, 0xf1, 0xc6, 0xce, 0x5f, 0xff, 0xba, 0xf2, 0xec, - 0x42, 0x7b, 0x68, 0x3f, 0x48, 0xe5, 0xe1, 0xfd, 0x87, 0x2f, 0xfa, 0x01, + 0x42, 0x7b, 0x68, 0x3c, 0xc8, 0xe5, 0xe1, 0xfd, 0x87, 0x2f, 0xfa, 0x01, 0xe1, 0x4e, 0x2a, 0x30, 0xe5, 0xd9, 0xbc, 0x3d, 0x8d, 0x0e, 0xd6, 0x91, 0xf8, 0xe4, 0x83, 0x0a, 0xcb, 0xec, 0x4d, 0x2a, 0x72, 0xf0, 0x7f, 0x98, 0xe5, 0x43, 0x68, 0x97, 0x3c, 0x28, 0x83, 0x1d, 0x8e, 0x20, 0xab, 0x0a, - 0xb5, 0xc6, 0x91, 0xf4, 0x28, 0x92, 0x17, 0xf3, 0x47, 0x01, 0xa8, 0xc1, + 0xb5, 0xc6, 0x91, 0xcc, 0x28, 0x92, 0x17, 0xf3, 0x47, 0x01, 0xa8, 0xc1, 0xd8, 0x7f, 0xd8, 0xed, 0x45, 0x93, 0x70, 0xeb, 0xf4, 0xf5, 0x7f, 0x18, - 0xdd, 0x9a, 0x19, 0xa8, 0x45, 0x7e, 0xef, 0xdb, 0x48, 0x39, 0x7d, 0x9a, - 0x45, 0x4e, 0x54, 0x1e, 0x50, 0x4a, 0x2f, 0xee, 0xc2, 0x83, 0xf7, 0xe7, + 0xdd, 0x9a, 0x19, 0xa8, 0x45, 0x7e, 0xef, 0x3b, 0x48, 0x39, 0x7d, 0x9a, + 0x45, 0x4e, 0x54, 0x1e, 0x50, 0x4a, 0x2f, 0xee, 0xc2, 0x83, 0xcf, 0xe7, 0x2f, 0x35, 0x79, 0xc0, 0x72, 0xf6, 0x63, 0x67, 0x2e, 0x45, 0x4e, 0x54, - 0xe6, 0xcd, 0x07, 0x2f, 0xde, 0xc9, 0x91, 0x87, 0x2f, 0xd1, 0xf7, 0xff, + 0xe6, 0xcd, 0x07, 0x2f, 0xde, 0xc9, 0x91, 0x87, 0x2f, 0xd1, 0xcf, 0xff, 0xc1, 0xca, 0x83, 0xd2, 0x12, 0x8b, 0xf4, 0x71, 0x81, 0xf1, 0xcb, 0xf2, 0x71, 0xf2, 0x4e, 0x72, 0xff, 0xcc, 0x14, 0x56, 0x3d, 0xb4, 0xd1, 0xcb, 0xe9, 0x7b, 0x16, 0x72, 0xb0, 0xf8, 0x1c, 0xfa, 0xfc, 0x38, 0xa6, 0x4c, - 0x72, 0xff, 0xf8, 0x56, 0x8c, 0x08, 0x1f, 0x52, 0xcf, 0xbc, 0x72, 0xff, - 0xce, 0x3f, 0xfd, 0xed, 0x46, 0x36, 0x72, 0xff, 0xdb, 0xea, 0x72, 0xfa, + 0x72, 0xff, 0xf8, 0x56, 0x8c, 0x08, 0x1f, 0x52, 0xce, 0x7c, 0x72, 0xff, + 0xce, 0x3f, 0xf3, 0xed, 0x46, 0x36, 0x72, 0xff, 0xdb, 0xea, 0x7c, 0xe6, 0x51, 0x93, 0x9c, 0xb6, 0x35, 0xa2, 0x0b, 0xf4, 0x0b, 0xfe, 0xeb, 0xb3, - 0xa9, 0x1f, 0x48, 0xe5, 0xfc, 0xa0, 0xc9, 0xa3, 0xce, 0x72, 0xa1, 0x36, + 0xa9, 0x1c, 0xc8, 0xe5, 0xfc, 0xa0, 0xc9, 0xa3, 0xce, 0x72, 0xa1, 0x36, 0x89, 0x43, 0x49, 0x0b, 0x3f, 0x39, 0xa9, 0xd5, 0x62, 0x04, 0x81, 0x65, 0x1a, 0x84, 0x50, 0x90, 0x7a, 0x39, 0x0b, 0xff, 0x63, 0xf6, 0x64, 0x1e, - 0xe7, 0xc7, 0x2f, 0xef, 0xe6, 0x94, 0x7b, 0x67, 0x2f, 0xff, 0xff, 0xbb, - 0x83, 0xfe, 0x0f, 0xbb, 0x9d, 0x8c, 0x99, 0x35, 0x37, 0x53, 0xef, 0x1c, + 0xe7, 0x27, 0x2f, 0xef, 0xe6, 0x94, 0x7b, 0x67, 0x2f, 0xff, 0xff, 0xbb, + 0x83, 0xfe, 0x0f, 0xbb, 0x9d, 0x8c, 0x99, 0x35, 0x37, 0x53, 0x9f, 0x1c, 0xbf, 0xcc, 0xd2, 0x2f, 0xb9, 0x31, 0xca, 0xc4, 0x59, 0x3b, 0xf5, 0xf0, - 0xc6, 0x36, 0x72, 0xfa, 0x3e, 0xdb, 0x9c, 0xa8, 0x6f, 0x45, 0xa7, 0x84, + 0xc6, 0x36, 0x72, 0xfa, 0x39, 0xdb, 0x9c, 0xa8, 0x6f, 0x45, 0xa7, 0x84, 0x98, 0x61, 0x6b, 0x95, 0xa3, 0xda, 0x47, 0x18, 0xd6, 0x43, 0x31, 0x86, 0x95, 0xde, 0x59, 0xb8, 0xb2, 0x78, 0xf8, 0x10, 0xe2, 0xe2, 0x42, 0xa1, 0x0d, 0xff, 0xf2, 0x0e, 0x32, 0x14, 0x10, 0x48, 0x71, 0x87, 0x2f, 0xf8, - 0x29, 0x82, 0x09, 0x66, 0xce, 0x5f, 0xf6, 0xb5, 0x0b, 0xef, 0xce, 0xd6, + 0x29, 0x82, 0x09, 0x66, 0xce, 0x5f, 0xf6, 0xb5, 0x0b, 0xef, 0x2e, 0xd6, 0x72, 0xc0, 0x39, 0x7f, 0x2c, 0x0e, 0x16, 0x41, 0xcb, 0xfe, 0xea, 0x4b, - 0xaf, 0x24, 0x61, 0xcb, 0xff, 0x6d, 0x07, 0xe9, 0x79, 0x36, 0x87, 0x2b, + 0xaf, 0x24, 0x61, 0xcb, 0xff, 0x6d, 0x07, 0x99, 0x79, 0x36, 0x87, 0x2b, 0x0f, 0xdb, 0xc7, 0x17, 0xed, 0xb2, 0x03, 0x07, 0x2a, 0x49, 0xde, 0xe2, 0x6a, 0x1b, 0xcc, 0x7b, 0xa1, 0x16, 0x42, 0x8f, 0xc4, 0x37, 0xc3, 0x1a, - 0x91, 0xcb, 0xfe, 0xec, 0x49, 0x04, 0x41, 0xf1, 0xcb, 0xfe, 0x89, 0x27, - 0xa5, 0x03, 0xf9, 0xcb, 0xfe, 0x8c, 0xf2, 0x9f, 0xff, 0x1f, 0x1c, 0xb6, + 0x91, 0xcb, 0xfe, 0xec, 0x49, 0x04, 0x41, 0xc9, 0xcb, 0xfe, 0x89, 0x27, + 0xa5, 0x03, 0xf9, 0xcb, 0xfe, 0x8c, 0xf2, 0x9f, 0xff, 0x1c, 0x9c, 0xb6, 0xa1, 0x19, 0xb8, 0x43, 0xa3, 0x86, 0x1c, 0x5f, 0xc3, 0x0b, 0xd4, 0x48, 0xe5, 0xff, 0xf7, 0x5d, 0x3d, 0x20, 0x0f, 0xb7, 0xd7, 0x91, 0xc5, 0x0d, 0x65, 0xff, 0xb6, 0xa7, 0x90, 0x41, 0x2c, 0xd9, 0xcb, 0x83, 0xb3, 0x94, - 0xd6, 0x8b, 0x6e, 0xb0, 0x09, 0xfd, 0xff, 0xfd, 0x9f, 0x66, 0xdc, 0x7a, + 0xd6, 0x8b, 0x6e, 0xb0, 0x09, 0xfd, 0xff, 0xfd, 0x9c, 0xe6, 0xdc, 0x7a, 0x91, 0xee, 0x81, 0xd8, 0x72, 0xa1, 0x3a, 0xe7, 0x8c, 0x8c, 0x4c, 0xaf, 0xc0, 0x62, 0x76, 0x0e, 0x5f, 0xb3, 0x4b, 0x8c, 0x39, 0x42, 0x79, 0xaa, 0x13, 0xdf, 0xf6, 0x33, 0x34, 0x93, 0xbb, 0x0e, 0x5f, 0xfc, 0xec, 0x18, - 0xf9, 0xa2, 0xbe, 0xce, 0x9c, 0xbf, 0xff, 0x38, 0xf9, 0xdf, 0xa3, 0x1e, + 0xe5, 0xa2, 0xbe, 0xce, 0x9c, 0xbf, 0xff, 0x38, 0xf9, 0xdf, 0xa3, 0x1e, 0xdb, 0x79, 0xd3, 0x97, 0xff, 0x33, 0x6f, 0x2d, 0x46, 0xe0, 0x67, 0x39, 0x7f, 0xd1, 0xee, 0xe3, 0x33, 0x58, 0x72, 0xfd, 0xee, 0xa4, 0x6c, 0xe5, 0xe9, 0xdc, 0x74, 0x7b, 0xdb, 0x37, 0xbf, 0xe8, 0xff, 0x61, 0x03, 0xea, 0x47, 0x2f, 0x6b, 0x7b, 0x3c, 0x40, 0x6b, 0xe5, 0xbb, 0xac, 0xd1, 0x01, - 0xb9, 0x9a, 0xab, 0x64, 0x91, 0x49, 0xa6, 0x4b, 0xfe, 0x8e, 0xad, 0x36, - 0xe9, 0x39, 0xcb, 0xed, 0x47, 0x63, 0x91, 0xf0, 0x68, 0xa2, 0xb1, 0x50, + 0xbe, 0x9a, 0xab, 0x64, 0x91, 0x49, 0xa6, 0x4b, 0xfe, 0x8e, 0xad, 0x36, + 0xe9, 0x39, 0xcb, 0xed, 0x47, 0x63, 0xe1, 0xf0, 0x68, 0xa2, 0xb1, 0x50, 0x9b, 0xc2, 0x89, 0x48, 0xcd, 0xe8, 0x2a, 0xc8, 0x7a, 0x71, 0xfa, 0x3f, 0xa5, 0x33, 0x5e, 0xe3, 0x1d, 0x39, 0x58, 0xae, 0xa1, 0x25, 0xa1, 0xa8, - 0x8f, 0x73, 0xfc, 0x72, 0xf7, 0x5d, 0xac, 0xe5, 0xf4, 0x7e, 0xd3, 0x0e, + 0x8f, 0x73, 0xf2, 0x72, 0xf7, 0x5d, 0xac, 0xe5, 0xf4, 0x7e, 0xd3, 0x0e, 0x5f, 0x31, 0x8f, 0xe3, 0x94, 0xc3, 0xfc, 0xfc, 0x5f, 0xc3, 0xea, 0x12, 0x5f, 0x0f, 0xbf, 0x01, 0xcb, 0xf3, 0x1a, 0xa6, 0xa9, 0xaa, 0x6a, 0x4e, 0x5f, 0xff, 0xd2, 0xcd, 0xa6, 0xb4, 0x8c, 0x53, 0xdd, 0xc6, 0xfc, 0x72, 0xb1, 0x17, 0xa8, 0x46, 0xe7, 0xb7, 0xff, 0x9b, 0xc1, 0xf6, 0x0c, 0xb3, - 0x6a, 0x30, 0xe5, 0xff, 0xe9, 0x67, 0xd2, 0x52, 0x3f, 0xe6, 0xdb, 0x6d, + 0x6a, 0x30, 0xe5, 0xff, 0xe9, 0x67, 0x32, 0x52, 0x3f, 0xfa, 0xdb, 0x6d, 0x94, 0xbf, 0x31, 0xbc, 0x4e, 0x27, 0x2f, 0x4b, 0x06, 0x63, 0xfd, 0x51, 0x4e, 0xa1, 0x1f, 0x6f, 0x0c, 0x7b, 0xff, 0xf3, 0xea, 0x41, 0xec, 0x6c, 0x71, 0xb7, 0xd2, 0xa7, 0x2a, 0x15, 0x4f, 0xf6, 0x1f, 0x63, 0x19, 0x40, @@ -3196,78 +3196,78 @@ 0xb7, 0x75, 0x9a, 0x20, 0x95, 0xff, 0x47, 0xb3, 0x4b, 0x77, 0x59, 0xa2, 0xf9, 0x5f, 0x9c, 0x3d, 0x85, 0x4e, 0x5e, 0x1c, 0xd8, 0x51, 0x54, 0xb3, 0xe6, 0x22, 0x50, 0xa6, 0x2b, 0xc6, 0x1a, 0xb7, 0xff, 0x47, 0x51, 0x5c, - 0xd4, 0xec, 0x07, 0xc7, 0x2f, 0xf8, 0x3a, 0xc6, 0x64, 0x9c, 0x27, 0x2b, + 0xd4, 0xec, 0x07, 0x27, 0x2f, 0xf8, 0x3a, 0xc6, 0x64, 0x9c, 0x27, 0x2b, 0x13, 0xe2, 0x48, 0xce, 0x7a, 0x54, 0xe8, 0xf7, 0xe9, 0x67, 0xea, 0x78, 0xe5, 0xfd, 0xd6, 0x9d, 0x45, 0xf4, 0xe5, 0x39, 0xed, 0x00, 0xaa, 0xff, - 0xde, 0x86, 0x6e, 0x12, 0x77, 0xf1, 0xcb, 0xff, 0x4e, 0xff, 0x34, 0xcf, + 0xde, 0x86, 0x6e, 0x12, 0x77, 0xf1, 0xcb, 0xff, 0x4e, 0xfc, 0xb4, 0xcf, 0x0b, 0xf1, 0x39, 0x7f, 0xfd, 0x9e, 0x81, 0xf6, 0xf3, 0x15, 0x55, 0xe4, 0x72, 0xfe, 0x57, 0x3d, 0xec, 0x09, 0xcb, 0xff, 0x60, 0x62, 0x51, 0xdc, 0xfd, 0xce, 0x5f, 0xcf, 0x20, 0x49, 0xc2, 0x72, 0xfe, 0xea, 0x4f, 0xbd, - 0xb9, 0xcb, 0xcd, 0xb6, 0xd9, 0x4b, 0xf7, 0x71, 0x6f, 0xa2, 0x9c, 0xcd, - 0x05, 0xff, 0xfe, 0x9b, 0x51, 0xc7, 0x92, 0xaf, 0xc9, 0x49, 0xb7, 0xcb, - 0x3e, 0xf1, 0xca, 0x84, 0x7b, 0x79, 0x39, 0x43, 0x9b, 0xff, 0xc9, 0xa4, + 0xb9, 0xcb, 0xcd, 0xb6, 0xd9, 0x4b, 0xf7, 0x71, 0x6f, 0xa2, 0x9f, 0x4d, + 0x05, 0xff, 0xfe, 0x9b, 0x51, 0xc7, 0xe2, 0xaf, 0xf1, 0x49, 0xb7, 0xf3, + 0x39, 0xf1, 0xca, 0x84, 0x7b, 0x79, 0x39, 0x43, 0x9b, 0xff, 0xc9, 0xa4, 0xf0, 0x33, 0xce, 0xcc, 0x13, 0x95, 0x3a, 0xa9, 0x75, 0xa1, 0xe9, 0x3d, - 0x85, 0xdf, 0x9e, 0x8c, 0x64, 0x7e, 0x30, 0xbf, 0xf3, 0x23, 0xed, 0x8e, - 0x4e, 0xa4, 0x8e, 0x5f, 0xff, 0xe4, 0xeb, 0x8f, 0xd2, 0x52, 0x50, 0x32, + 0x85, 0xdf, 0x9e, 0x8c, 0x64, 0x7e, 0x30, 0xbf, 0xf3, 0x23, 0x9d, 0x8e, + 0x4e, 0xa4, 0x8e, 0x5f, 0xff, 0xe4, 0xeb, 0x8f, 0x32, 0x52, 0x50, 0x32, 0x76, 0x60, 0x4e, 0x5f, 0xfe, 0xcc, 0xe8, 0x7b, 0x1b, 0xce, 0xa7, 0xe7, 0x2f, 0xd3, 0x4a, 0x35, 0xb3, 0x97, 0xfb, 0x04, 0x12, 0xdc, 0xee, 0x72, - 0xca, 0xf2, 0x3d, 0xc0, 0x94, 0xd4, 0xe9, 0xb8, 0xc9, 0x04, 0x2c, 0x09, - 0x0a, 0x5b, 0xee, 0x49, 0xd0, 0x1c, 0xbf, 0x64, 0xbb, 0x1a, 0x39, 0x4b, - 0x3c, 0xb6, 0xb2, 0x4b, 0xfd, 0xe8, 0x4e, 0xab, 0x1f, 0x1c, 0xbf, 0xfb, - 0xdb, 0x79, 0x6f, 0x17, 0x0c, 0x43, 0x97, 0xff, 0xbe, 0x1e, 0x4b, 0xea, + 0xca, 0xfc, 0x3d, 0xc0, 0x94, 0xd4, 0xe9, 0xb8, 0xc9, 0x04, 0x2c, 0x09, + 0x0a, 0x5b, 0xef, 0x89, 0xd0, 0x1c, 0xbf, 0x64, 0xbb, 0x1a, 0x39, 0x4b, + 0x3c, 0xb6, 0xb2, 0x4b, 0xfd, 0xe8, 0x4e, 0xab, 0x1c, 0x9c, 0xbf, 0xfb, + 0xdb, 0x79, 0x6f, 0x17, 0x0c, 0x43, 0x97, 0xff, 0xb9, 0x1f, 0x8b, 0xea, 0x7f, 0xfc, 0x6a, 0x47, 0x2a, 0x11, 0xd6, 0x84, 0xa0, 0x34, 0x51, 0x0e, 0xfe, 0x4d, 0xe0, 0x54, 0xc3, 0x97, 0xee, 0x04, 0x1c, 0xe2, 0x72, 0xff, 0x6b, 0x02, 0x80, 0x5f, 0x56, 0x7b, 0x0e, 0x5b, 0x7f, 0xb6, 0x39, 0xc7, 0xaf, 0x23, 0x97, 0xb7, 0x2e, 0x27, 0x29, 0x0f, 0x4d, 0xac, 0xd2, 0xff, - 0xf4, 0x4e, 0xa7, 0x63, 0xef, 0x64, 0xe2, 0x13, 0x94, 0x89, 0x86, 0xbc, + 0xf4, 0x4e, 0xa7, 0x63, 0x9f, 0x64, 0xe2, 0x13, 0x94, 0x89, 0x86, 0xbc, 0x27, 0x04, 0x92, 0xff, 0xf7, 0x5e, 0x58, 0x11, 0x47, 0xec, 0x30, 0xe5, - 0xfe, 0x8c, 0x1f, 0x70, 0x8d, 0xac, 0xe5, 0xfe, 0xee, 0x71, 0xe5, 0xb9, + 0xfe, 0x8c, 0x1f, 0x70, 0x8d, 0xac, 0xe5, 0xfe, 0xee, 0x71, 0xf9, 0xb9, 0x2c, 0xe5, 0x6c, 0xfc, 0x3c, 0x71, 0x5e, 0x46, 0xc8, 0x21, 0x6f, 0x7f, - 0x0f, 0x25, 0x35, 0xd7, 0x39, 0x7f, 0xe0, 0x3c, 0xb9, 0x42, 0x07, 0x18, + 0x0f, 0xc5, 0x35, 0xd7, 0x39, 0x7f, 0xe0, 0x3c, 0xbe, 0x42, 0x07, 0x18, 0x72, 0x9c, 0xfb, 0xc4, 0xc2, 0xff, 0xda, 0x4f, 0xe7, 0xec, 0x6c, 0x1b, - 0x39, 0x7e, 0xcd, 0x3f, 0xcd, 0x9c, 0xbf, 0xff, 0xd3, 0xe3, 0x63, 0x81, + 0x39, 0x7e, 0xcd, 0x3f, 0x2d, 0x9c, 0xbf, 0xff, 0xd3, 0xe3, 0x63, 0x81, 0xd2, 0x02, 0x70, 0xf6, 0x06, 0x73, 0x95, 0x3a, 0x23, 0x36, 0x53, 0x7f, 0xa6, 0x17, 0x6f, 0xd9, 0xd3, 0x97, 0xbb, 0x8b, 0x39, 0x79, 0xb6, 0xdb, - 0x29, 0x7f, 0x7f, 0x03, 0x9f, 0x78, 0xa7, 0x33, 0x41, 0x5c, 0x91, 0x60, - 0xd0, 0xd1, 0x43, 0xcb, 0xff, 0xfb, 0x87, 0xe4, 0xbe, 0xa0, 0x43, 0x8d, - 0xf2, 0xf6, 0xf2, 0x73, 0x95, 0xd4, 0x4e, 0x00, 0xd6, 0xa1, 0x53, 0x02, + 0x29, 0x7f, 0x7f, 0x03, 0x9c, 0xf8, 0xa7, 0xd3, 0x41, 0x5f, 0x11, 0x60, + 0xd0, 0xd1, 0x43, 0xcb, 0xff, 0xfb, 0x87, 0xf8, 0xbe, 0xa0, 0x43, 0x8d, + 0xfc, 0xf6, 0xf2, 0x73, 0x95, 0xd4, 0x4e, 0x00, 0xd6, 0xa1, 0x53, 0x02, 0x43, 0x35, 0xe3, 0x70, 0xbf, 0xe5, 0x23, 0x78, 0xda, 0x83, 0xe3, 0x95, - 0x3b, 0x3d, 0x46, 0x52, 0x8c, 0x03, 0x09, 0xbf, 0x88, 0x52, 0x56, 0xae, + 0x3b, 0x3d, 0x46, 0x52, 0x8c, 0x03, 0x09, 0xbe, 0x48, 0x52, 0x56, 0xae, 0xa3, 0xde, 0x64, 0x6f, 0x3d, 0x8e, 0x84, 0x63, 0x0c, 0xdc, 0x25, 0xfd, 0x2a, 0x01, 0x43, 0xab, 0xff, 0x62, 0x0c, 0xee, 0x3e, 0xc6, 0x1c, 0xbf, 0xfd, 0xa5, 0x54, 0xf2, 0x6c, 0x73, 0x8a, 0x04, 0xe5, 0xff, 0x23, 0x61, - 0xee, 0x79, 0xa6, 0x1c, 0xa8, 0x44, 0x47, 0x53, 0x6f, 0x85, 0xfe, 0xf1, + 0xee, 0x79, 0xa6, 0x1c, 0xa8, 0x44, 0x47, 0x53, 0x6f, 0x85, 0xf9, 0xf1, 0xcb, 0xd8, 0x3f, 0x9c, 0xbe, 0xcf, 0x4d, 0x23, 0x97, 0xff, 0x70, 0x0c, 0x70, 0x6d, 0xc5, 0x4f, 0xf6, 0x72, 0xba, 0x7d, 0xce, 0x47, 0x7f, 0xec, 0xf4, 0x6b, 0x7d, 0x81, 0xf1, 0xe2, 0x08, 0x5f, 0xd9, 0xa5, 0xbb, 0xac, - 0xd1, 0x04, 0x39, 0x9e, 0x55, 0xe8, 0x0a, 0x1c, 0xa8, 0x3e, 0x7d, 0xa6, + 0xd1, 0x04, 0x3e, 0x9e, 0x55, 0xe8, 0x0a, 0x1c, 0xa8, 0x3e, 0x7d, 0xa6, 0x5e, 0xe3, 0x0c, 0x39, 0x7f, 0x3f, 0x75, 0xa4, 0x6c, 0xe5, 0xfc, 0xd6, 0x16, 0xdc, 0x64, 0x72, 0xb0, 0xff, 0x44, 0x78, 0x05, 0xd7, 0xff, 0xa6, 0x92, 0x0f, 0xa3, 0xf9, 0x85, 0x26, 0x39, 0x70, 0xcc, 0x72, 0xd0, 0x13, 0xe3, 0xc4, 0xca, 0x9d, 0x56, 0x92, 0xa4, 0x5d, 0x84, 0x57, 0xf0, 0xd2, 0x18, 0x4f, 0x71, 0x84, 0x85, 0xfd, 0xdc, 0xf7, 0x91, 0x87, 0x2f, 0xef, - 0x29, 0x9d, 0x7f, 0x8e, 0x57, 0xc7, 0xb8, 0x25, 0xb7, 0xf6, 0x7d, 0xed, + 0x29, 0x9d, 0x7e, 0x4e, 0x57, 0x27, 0xb8, 0x25, 0xb7, 0xf6, 0x73, 0xed, 0x6a, 0x0e, 0x5f, 0xfd, 0xb1, 0x7f, 0x3b, 0x14, 0x89, 0xf0, 0xe5, 0x04, 0xfc, 0xb6, 0x5d, 0x50, 0x8b, 0x60, 0x42, 0x52, 0xfe, 0xc5, 0xa9, 0xc7, 0xb8, 0x72, 0xff, 0xfe, 0x41, 0x0e, 0xb1, 0x7d, 0x8e, 0xe6, 0xb5, 0x0a, 0x9c, 0xba, 0x15, 0x39, 0x72, 0x09, 0xcb, 0x36, 0x72, 0x82, 0x69, 0xd4, 0x15, 0xbc, 0x20, 0x9c, 0xe5, 0xfb, 0xaf, 0x2c, 0x13, 0x97, 0xf2, 0x78, - 0x73, 0xa8, 0x72, 0xec, 0xef, 0x23, 0xd1, 0x82, 0x6b, 0x9d, 0xbe, 0x48, + 0x73, 0xa8, 0x72, 0xec, 0xef, 0xc3, 0xd1, 0x82, 0x6b, 0x9d, 0xbf, 0x88, 0xfc, 0xc3, 0xee, 0x91, 0x79, 0xba, 0xa4, 0x9f, 0xbe, 0x13, 0xf4, 0xc0, 0x63, 0x56, 0xbf, 0xb6, 0x81, 0x0e, 0x09, 0xcb, 0xff, 0xfb, 0xdd, 0xcd, 0xef, 0x30, 0x1a, 0x9f, 0x00, 0x3e, 0x39, 0x7f, 0xdd, 0x8d, 0x78, 0x63, - 0x3e, 0x39, 0x7f, 0xff, 0xc9, 0x3c, 0x4b, 0x7a, 0xd2, 0x7d, 0x34, 0x9f, - 0x4c, 0xcf, 0x8e, 0x5f, 0xe8, 0x79, 0xdf, 0x4e, 0xa1, 0xcb, 0xdd, 0xc1, + 0x39, 0x39, 0x7f, 0xff, 0xc9, 0x3c, 0x4b, 0x7a, 0xd2, 0x73, 0x34, 0x9f, + 0x4c, 0xce, 0x4e, 0x5f, 0xe8, 0x79, 0xdf, 0x4e, 0xa1, 0xcb, 0xdd, 0xc1, 0x0a, 0x35, 0x7a, 0x71, 0xe6, 0xaa, 0xc4, 0xe7, 0x10, 0xb3, 0xd1, 0x98, 0x5f, 0xa3, 0x53, 0x6e, 0x73, 0x97, 0xfd, 0xd8, 0xcd, 0x4b, 0x60, 0x61, 0xca, 0x9c, 0xf8, 0xd6, 0x55, 0x72, 0x6c, 0xe5, 0xff, 0x64, 0xef, 0xef, - 0xd4, 0x19, 0x1c, 0xbf, 0x9f, 0xdc, 0xa2, 0x4a, 0x9c, 0xbf, 0x94, 0x66, - 0xdb, 0x7f, 0x8e, 0x54, 0x26, 0xdb, 0x90, 0x98, 0x54, 0x8f, 0x42, 0xce, + 0xd4, 0x19, 0x1c, 0xbf, 0x9f, 0xdf, 0x22, 0x4a, 0x9c, 0xbf, 0x94, 0x66, + 0xdb, 0x7e, 0x4e, 0x54, 0x26, 0xdb, 0x90, 0x98, 0x54, 0x8f, 0x42, 0xce, 0x77, 0xe3, 0x0b, 0xda, 0xce, 0x9c, 0xbd, 0xb4, 0x61, 0xca, 0xd1, 0xb8, 0xf0, 0xe5, 0xc9, 0x39, 0xca, 0x83, 0x71, 0xc0, 0x43, 0x7f, 0xf7, 0x52, - 0x07, 0x93, 0x8c, 0x91, 0x87, 0x2f, 0x92, 0x64, 0x6c, 0xe5, 0xff, 0xcc, - 0x7f, 0x94, 0xf2, 0x6a, 0x01, 0xc3, 0x9c, 0xbf, 0xff, 0x02, 0x71, 0x8c, - 0xef, 0x38, 0xf6, 0x74, 0x1a, 0x39, 0x7d, 0xed, 0xa9, 0xbe, 0x49, 0x84, + 0x07, 0xe3, 0x8c, 0x91, 0x87, 0x2f, 0x92, 0x64, 0x6c, 0xe5, 0xff, 0xcc, + 0x7e, 0x54, 0xf2, 0x6a, 0x01, 0xc3, 0x9c, 0xbf, 0xff, 0x02, 0x71, 0x8c, + 0xef, 0xd8, 0xf6, 0x74, 0x1a, 0x39, 0x7d, 0xed, 0xa9, 0xbf, 0x89, 0x84, 0x05, 0x0f, 0x08, 0xd4, 0x4b, 0xbf, 0x6d, 0x99, 0xed, 0x9c, 0xbf, 0xf9, 0x15, 0xcf, 0x27, 0x73, 0xd1, 0xa3, 0x97, 0xe7, 0x90, 0xa4, 0x1c, 0xbf, 0xa1, 0xc7, 0xd8, 0x27, 0x2a, 0x4a, 0x8f, 0xb2, 0x32, 0xb4, 0x59, 0xd1, @@ -3278,77 +3278,77 @@ 0x27, 0x40, 0x72, 0xa0, 0xf6, 0x02, 0x4d, 0x50, 0x8a, 0x86, 0x42, 0x1e, 0xff, 0xde, 0x53, 0xf8, 0x52, 0x3f, 0x8f, 0xce, 0x5f, 0xff, 0xf9, 0x8e, 0x3f, 0xc9, 0x36, 0x06, 0x75, 0x23, 0xdd, 0x03, 0xb0, 0xe5, 0xff, 0xf0, - 0x83, 0xd2, 0x4f, 0xfa, 0xe9, 0xe7, 0x61, 0xcb, 0xb9, 0x35, 0x9c, 0xbf, + 0x83, 0xd2, 0x4f, 0xfa, 0xe9, 0xe7, 0x61, 0xcb, 0xbe, 0x35, 0x9c, 0xbf, 0xff, 0x3a, 0x79, 0x03, 0x81, 0xcf, 0x23, 0x13, 0x47, 0x2f, 0xff, 0x42, 0xc3, 0x8a, 0x79, 0x35, 0x00, 0xe1, 0xce, 0x5e, 0xd3, 0xef, 0x13, 0x0c, - 0xd2, 0x7f, 0x47, 0x05, 0x4a, 0xde, 0x74, 0xf1, 0x41, 0x1b, 0xc5, 0x7c, + 0xd2, 0x7f, 0x47, 0x05, 0x4a, 0xde, 0x74, 0xf1, 0x41, 0x1b, 0xc5, 0x72, 0xa8, 0xdd, 0x25, 0x04, 0x5d, 0x28, 0x39, 0x7f, 0xfa, 0x70, 0xf6, 0x3b, - 0x9f, 0x7f, 0x9e, 0xd9, 0xca, 0x73, 0xe3, 0x00, 0xb5, 0x05, 0x71, 0x67, + 0x9c, 0xff, 0x9e, 0xd9, 0xca, 0x73, 0xe3, 0x00, 0xb5, 0x05, 0x71, 0x67, 0x21, 0x02, 0x90, 0xca, 0x79, 0x4b, 0xc3, 0x08, 0xfb, 0xfb, 0x51, 0x3a, 0x0f, 0x8e, 0x5e, 0x0a, 0x8c, 0x39, 0x7e, 0x18, 0x0e, 0x4c, 0x72, 0xfb, 0x60, 0xd2, 0xa7, 0x2f, 0xd1, 0xdf, 0x44, 0x8e, 0x5f, 0x04, 0x1e, 0xdc, - 0x1f, 0x97, 0xc4, 0xff, 0x92, 0x5f, 0xbf, 0xc6, 0x47, 0x4e, 0x5f, 0xff, - 0xfe, 0xc9, 0xf7, 0x0a, 0xbe, 0xfd, 0x2c, 0x55, 0x5c, 0xfb, 0xda, 0x8c, - 0xf8, 0xe5, 0xfa, 0x39, 0x68, 0x64, 0x72, 0xb6, 0x8a, 0x50, 0x3e, 0x5e, + 0x1f, 0x97, 0x24, 0xff, 0x92, 0x5f, 0xbf, 0xc6, 0x47, 0x4e, 0x5f, 0xff, + 0xfe, 0xc9, 0xf7, 0x0a, 0xbe, 0xfd, 0x2c, 0x55, 0x5c, 0xe7, 0xda, 0x8c, + 0xe4, 0xe5, 0xfa, 0x3e, 0x68, 0x64, 0x72, 0xb6, 0x8a, 0x50, 0x3e, 0x5e, 0xe1, 0xfb, 0x87, 0x28, 0x2a, 0x85, 0xb0, 0xb5, 0x21, 0x20, 0x29, 0x1e, - 0x86, 0x68, 0x08, 0xef, 0x69, 0x4d, 0x9c, 0xbf, 0xee, 0xc7, 0xde, 0x8e, - 0xbb, 0x59, 0xca, 0x39, 0x5c, 0x8f, 0x1f, 0x85, 0xcf, 0x2f, 0xde, 0xf7, + 0x86, 0x68, 0x08, 0xef, 0x69, 0x4d, 0x9c, 0xbf, 0xee, 0xc7, 0x3e, 0x8e, + 0xbb, 0x59, 0xca, 0x39, 0x5f, 0x0f, 0x1f, 0x85, 0xcf, 0x2f, 0xde, 0xf7, 0xb1, 0xb3, 0x95, 0x07, 0xa8, 0x85, 0x77, 0xfe, 0x71, 0x5e, 0x69, 0x6e, 0xeb, 0x34, 0x42, 0x2b, 0xa5, 0x39, 0xca, 0x84, 0xce, 0xbf, 0x85, 0xc8, 0x08, 0x38, 0xa4, 0xdf, 0xb2, 0x7d, 0xfe, 0xe7, 0x2f, 0xff, 0xff, 0x77, - 0x01, 0xa5, 0x7a, 0x9f, 0x47, 0x81, 0xd1, 0xcf, 0xbc, 0x07, 0xd9, 0xcb, - 0xff, 0xb3, 0xe5, 0x3c, 0x82, 0x09, 0x66, 0xce, 0x5f, 0xff, 0xff, 0xff, + 0x01, 0xa5, 0x7a, 0x9c, 0xc7, 0x81, 0xd1, 0xce, 0x7c, 0x07, 0xd9, 0xcb, + 0xff, 0xb3, 0x95, 0x3c, 0x82, 0x09, 0x66, 0xce, 0x5f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xb0, 0x67, 0x17, 0x0c, 0x0c, 0xf1, 0xa0, 0xe0, 0xe7, 0xb6, 0x8b, 0xc1, 0x52, 0x7c, 0xd4, 0x6c, 0x5d, 0x5d, 0xe2, 0x7f, 0xf8, 0x3f, 0x17, 0x0c, 0x0c, 0xf1, 0xa3, 0x95, 0x09, 0xa7, 0xe2, 0x2d, 0xff, 0xde, - 0x71, 0x9f, 0xe9, 0x0c, 0x66, 0xce, 0x5f, 0xff, 0xa3, 0xf9, 0xa5, 0x13, - 0x8b, 0xab, 0xb1, 0x89, 0x1c, 0xbf, 0xf2, 0x99, 0xd7, 0x67, 0x36, 0xdb, + 0x71, 0x9f, 0x99, 0x0c, 0x66, 0xce, 0x5f, 0xff, 0xa3, 0xf9, 0xa5, 0x13, + 0x8b, 0xab, 0xb1, 0x89, 0x1c, 0xbf, 0xf2, 0x99, 0xd7, 0x67, 0xd6, 0xdb, 0x6c, 0xe5, 0xff, 0xfb, 0x17, 0xd8, 0x10, 0x8a, 0x4f, 0x82, 0x8a, 0x9c, 0xb3, 0xce, 0x89, 0x89, 0x22, 0xd4, 0x93, 0x18, 0x78, 0x77, 0xdf, 0xff, 0xd3, 0x0c, 0x7f, 0xb5, 0xf5, 0x35, 0x30, 0xc7, 0xfb, 0x39, 0x7f, 0xff, 0x7b, 0x70, 0xac, 0x93, 0xae, 0x3e, 0x96, 0x6b, 0x0e, 0x5f, 0xf9, 0x37, - 0x81, 0xe4, 0xff, 0xb4, 0xc3, 0x97, 0xfe, 0xea, 0x71, 0xeb, 0xcb, 0x50, + 0x81, 0xf8, 0xff, 0xb4, 0xc3, 0x97, 0xfe, 0xea, 0x71, 0xeb, 0xcb, 0x50, 0xa9, 0xca, 0xc4, 0x6e, 0xad, 0x6b, 0xc8, 0x57, 0xf0, 0x3c, 0x80, 0x15, 0x4e, 0x5f, 0xd8, 0xde, 0x08, 0x3f, 0x39, 0x7e, 0x96, 0x7a, 0x3f, 0x39, - 0x74, 0x32, 0x73, 0xd6, 0xf8, 0xba, 0xff, 0xff, 0xef, 0xd8, 0xf2, 0xeb, + 0x74, 0x32, 0x73, 0xd6, 0xe4, 0xba, 0xff, 0xff, 0xef, 0xd8, 0xf2, 0xeb, 0xa7, 0x90, 0x38, 0x1c, 0xf2, 0x31, 0x34, 0x72, 0xb6, 0x89, 0xf0, 0x17, 0xdf, 0xff, 0x87, 0x37, 0x9d, 0x7e, 0x05, 0xf5, 0x19, 0x0b, 0x39, 0x7e, - 0x9d, 0x90, 0x18, 0x39, 0x52, 0x5e, 0x9d, 0x0c, 0x79, 0x3f, 0x11, 0x4d, + 0x9d, 0x90, 0x18, 0x39, 0x52, 0x5e, 0x9d, 0x0c, 0x79, 0x3c, 0x91, 0x4d, 0x1a, 0xe6, 0x8a, 0x3b, 0x19, 0xde, 0xcb, 0xfd, 0x19, 0x1f, 0x12, 0x35, 0x15, 0xaf, 0xfd, 0x0a, 0xab, 0x03, 0x9e, 0xea, 0x1c, 0xbf, 0xd1, 0xbd, 0xc4, 0xf8, 0xd9, 0xcb, 0xfd, 0xdc, 0x66, 0x74, 0x02, 0x72, 0x82, 0x7c, 0xde, 0x34, 0xbe, 0xcd, 0x2a, 0x87, 0x2a, 0x19, 0x0b, 0x39, 0x3d, 0x8c, 0x90, 0xab, 0x78, 0x52, 0x00, 0x8a, 0xf3, 0x6d, 0xb6, 0x52, 0xff, 0xb3, - 0xf7, 0xd6, 0x71, 0xc0, 0x94, 0xe6, 0x68, 0x2e, 0x6d, 0xb2, 0x97, 0x9b, - 0x6d, 0xb2, 0x97, 0xf3, 0xce, 0x1e, 0xc6, 0xca, 0x73, 0x34, 0x14, 0x28, - 0xc5, 0x6d, 0x31, 0xa1, 0xcd, 0xf9, 0x68, 0x15, 0x18, 0x53, 0x99, 0xb2, - 0xbc, 0xdb, 0x6d, 0x94, 0xbd, 0xb8, 0xd1, 0x4e, 0x66, 0x82, 0xf9, 0xc7, - 0xef, 0x1c, 0xb7, 0xe8, 0x8a, 0xbf, 0x2d, 0xb6, 0x5d, 0x7f, 0x04, 0x62, + 0xf7, 0xd6, 0x71, 0xc0, 0x94, 0xfa, 0x68, 0x2e, 0x6d, 0xb2, 0x97, 0x9b, + 0x6d, 0xb2, 0x97, 0xf3, 0xce, 0x1e, 0xc6, 0xca, 0x7d, 0x34, 0x14, 0x28, + 0xc5, 0x6d, 0x31, 0xa1, 0xcd, 0xf9, 0x68, 0x15, 0x18, 0x53, 0xe9, 0xb2, + 0xbc, 0xdb, 0x6d, 0x94, 0xbd, 0xb8, 0xd1, 0x4f, 0xa6, 0x82, 0xf9, 0xc7, + 0x9f, 0x1c, 0xb7, 0xe8, 0x8a, 0xbf, 0x2d, 0xb6, 0x5d, 0x7f, 0x04, 0x62, 0x4e, 0xb3, 0x97, 0xed, 0x82, 0x76, 0x82, 0x72, 0xfc, 0x14, 0xe3, 0x01, 0x39, 0x7d, 0x83, 0x8d, 0x67, 0x2b, 0x47, 0x98, 0xc2, 0x9a, 0x44, 0x4c, 0xa8, 0xef, 0x7f, 0xf7, 0x5e, 0x42, 0xea, 0xcc, 0x29, 0x31, 0xcb, 0xfe, - 0x9e, 0x3e, 0xda, 0x0e, 0x7e, 0x72, 0xf9, 0xe4, 0x9f, 0x9c, 0xad, 0x1e, + 0x9e, 0x39, 0xda, 0x0e, 0x7e, 0x72, 0xf9, 0xe4, 0x9f, 0x9c, 0xad, 0x1e, 0xe7, 0x4e, 0xaf, 0xfb, 0x17, 0x13, 0x87, 0xb1, 0xb3, 0x95, 0x87, 0xb6, 0xd0, 0x8a, 0xfe, 0xee, 0x71, 0xcf, 0x6c, 0xe5, 0x2d, 0x34, 0xef, 0xe1, 0xf9, 0xe2, 0x3a, 0xd2, 0xa6, 0xde, 0xc3, 0x14, 0x63, 0x71, 0xba, 0x7f, 0x1c, 0xa8, 0x55, 0xf1, 0x92, 0xa9, 0x04, 0xf2, 0xfd, 0x3b, 0x4e, 0xe2, 0xce, 0x5c, 0xd4, 0x1a, 0x93, 0x97, 0xed, 0xcd, 0xb8, 0xf1, 0xca, 0xc3, - 0xf6, 0xf8, 0xaf, 0xc4, 0x57, 0xe5, 0xc7, 0x61, 0x87, 0x2e, 0x7f, 0x1c, + 0xf6, 0xe4, 0xaf, 0xc4, 0x57, 0xe5, 0xc7, 0x61, 0x87, 0x2e, 0x7f, 0x1c, 0xbf, 0x63, 0x5b, 0x8f, 0xf8, 0x6f, 0x44, 0x9e, 0xff, 0xa0, 0x64, 0x21, 0xec, 0x4e, 0x72, 0xfe, 0x0e, 0x69, 0xa3, 0x02, 0x72, 0xf7, 0x52, 0x62, - 0x95, 0xa3, 0xcd, 0xd9, 0x85, 0xff, 0x3f, 0xde, 0xc9, 0x81, 0xa5, 0x4e, - 0x59, 0x68, 0x7b, 0xc0, 0x22, 0xbf, 0xc3, 0x9f, 0x4b, 0x68, 0xa9, 0xcb, + 0x95, 0xa3, 0xcd, 0xd9, 0x85, 0xff, 0x3f, 0x3e, 0xc9, 0x81, 0xa5, 0x4e, + 0x59, 0x68, 0x7b, 0xc0, 0x22, 0xbf, 0xc3, 0x9c, 0xcb, 0x68, 0xa9, 0xcb, 0xe7, 0x7d, 0x2a, 0x72, 0xca, 0x9c, 0xbf, 0xfb, 0x17, 0xd8, 0xee, 0x6b, - 0x50, 0xa9, 0xcb, 0xc9, 0xfe, 0xe0, 0xf5, 0xb4, 0x25, 0x5c, 0x91, 0xbf, - 0x39, 0xa0, 0xbc, 0x5f, 0xf6, 0x62, 0xff, 0x8c, 0xfa, 0x47, 0x2f, 0xa1, + 0x50, 0xa9, 0xcb, 0xc9, 0xfe, 0xe0, 0xf5, 0xb4, 0x25, 0x5f, 0x11, 0xbf, + 0x39, 0xa0, 0xbc, 0x5f, 0xf6, 0x62, 0xff, 0x8c, 0xe6, 0x47, 0x2f, 0xa1, 0xd9, 0xc4, 0xa5, 0xff, 0xdd, 0x47, 0xff, 0xf8, 0xfe, 0x3b, 0xb3, 0x97, 0xf7, 0x71, 0x8c, 0x79, 0x1c, 0xbc, 0xdb, 0x6d, 0x94, 0xbf, 0xc3, 0xee, - 0xa4, 0x0c, 0xe5, 0x39, 0x9a, 0x0b, 0xd1, 0xfe, 0x49, 0x12, 0x38, 0x9b, + 0xa4, 0x0c, 0xe5, 0x3e, 0x9a, 0x0b, 0xd1, 0xfe, 0x49, 0x12, 0x38, 0x9b, 0x5e, 0x4c, 0x29, 0x48, 0x6b, 0xdb, 0x16, 0x9a, 0xbb, 0x23, 0x2d, 0xbf, 0xbf, 0x8f, 0xe3, 0xbb, 0x39, 0x7f, 0xa1, 0x4d, 0x69, 0x3d, 0xb3, 0x95, - 0x0b, 0x9c, 0xf2, 0x6c, 0x54, 0xfb, 0xe8, 0x71, 0xa4, 0x60, 0xd3, 0x19, + 0x0b, 0x9c, 0xf2, 0x6c, 0x54, 0xfb, 0x98, 0x71, 0xa4, 0x60, 0xd3, 0x19, 0x76, 0x39, 0x0f, 0xcb, 0xc4, 0xbe, 0xfd, 0xfe, 0x27, 0x55, 0x39, 0x7f, - 0xfd, 0x8b, 0x81, 0x7f, 0x6c, 0x20, 0x7d, 0x48, 0xe5, 0x7c, 0x7e, 0xec, + 0xfd, 0x8b, 0x81, 0x7f, 0x6c, 0x20, 0x7d, 0x48, 0xe5, 0x72, 0x7e, 0xec, 0x29, 0xbf, 0xa0, 0x56, 0xd5, 0x35, 0x16, 0xac, 0xe5, 0xfa, 0x19, 0xa8, 0xe2, 0x72, 0xff, 0xf6, 0xa1, 0x7e, 0x18, 0x6f, 0x3d, 0xbd, 0x9c, 0xbf, 0xff, 0xf8, 0x5d, 0x91, 0xa5, 0x87, 0xb1, 0xb0, 0x3a, 0x4b, 0x7d, 0x79, @@ -3359,42 +3359,42 @@ 0xe1, 0x76, 0xf0, 0x5d, 0x53, 0x97, 0xff, 0x67, 0xb6, 0xa6, 0xd8, 0x31, 0xa8, 0x39, 0x7b, 0x8e, 0x08, 0x4f, 0xd9, 0x86, 0x57, 0xff, 0x37, 0x1a, 0x17, 0x9e, 0x35, 0x12, 0x39, 0x48, 0x7f, 0x1d, 0x34, 0xbf, 0xff, 0xe0, - 0xf5, 0x1b, 0xce, 0x04, 0x63, 0xfb, 0x60, 0x96, 0x7d, 0xe3, 0x95, 0x88, + 0xf5, 0x1b, 0xce, 0x04, 0x63, 0xfb, 0x60, 0x96, 0x73, 0xe3, 0x95, 0x88, 0x8c, 0x72, 0x1b, 0xfe, 0x99, 0x7d, 0x46, 0x46, 0x95, 0x39, 0x7e, 0x9f, - 0x90, 0x22, 0x63, 0x96, 0x91, 0xcb, 0xca, 0x0c, 0xc7, 0x2a, 0x46, 0xbf, + 0xe0, 0x22, 0x63, 0x96, 0x91, 0xcb, 0xca, 0x0c, 0xc7, 0x2a, 0x46, 0xbf, 0xf1, 0x1a, 0xc4, 0x5c, 0x39, 0xde, 0xd6, 0xea, 0x1f, 0x2b, 0xe2, 0x79, 0x5c, 0x92, 0x9c, 0x29, 0x0c, 0xb5, 0x3c, 0xa7, 0xcc, 0xab, 0x0e, 0x15, 0xc3, 0x11, 0x25, 0x7a, 0x4d, 0x2d, 0xeb, 0x52, 0xd2, 0xd9, 0x2c, 0x27, 0xb3, 0xa0, 0x6f, 0x29, 0xd7, 0xf8, 0xe6, 0x86, 0x91, 0x3d, 0xb9, 0xd1, 0x6f, 0x4e, 0xc9, 0x82, 0x59, 0xf3, 0x71, 0xfd, 0x29, 0x0d, 0x9b, 0xdc, - 0x60, 0x4e, 0x5f, 0xff, 0x60, 0xf3, 0xf2, 0xa9, 0xf6, 0xfb, 0x9f, 0xb9, + 0x60, 0x4e, 0x5f, 0xff, 0x60, 0xfd, 0xf2, 0xa9, 0xce, 0xfb, 0x9f, 0xb9, 0xca, 0x91, 0xf8, 0x04, 0x76, 0xf3, 0xbb, 0x67, 0x2e, 0xfe, 0x0e, 0x5f, 0x97, 0x9e, 0xea, 0x1c, 0xb3, 0x84, 0xf6, 0x90, 0x70, 0x45, 0xef, 0xff, 0xfb, 0x3a, 0xea, 0x6f, 0x15, 0x71, 0xfe, 0x06, 0x26, 0xec, 0x1c, 0xb4, 0x1c, 0xbf, 0xff, 0x46, 0xbb, 0x0c, 0xe0, 0x04, 0x0c, 0x4d, 0xd8, 0x39, - 0x7e, 0x4d, 0x4d, 0x1d, 0xd2, 0x33, 0x7f, 0x66, 0x11, 0x0a, 0xf9, 0x3c, + 0x7e, 0x4d, 0x4d, 0x1d, 0xd2, 0x33, 0x7f, 0x66, 0x11, 0x0a, 0xe5, 0x3c, 0x86, 0x3e, 0x29, 0x0f, 0xfb, 0x70, 0xb9, 0xcb, 0xff, 0x7b, 0xaf, 0x2f, - 0x4c, 0x30, 0xc3, 0x97, 0xfe, 0x71, 0xff, 0x90, 0x40, 0xfa, 0x91, 0xcb, + 0x4c, 0x30, 0xc3, 0x97, 0xfe, 0x71, 0xff, 0xe0, 0x40, 0xfa, 0x91, 0xcb, 0xe4, 0x19, 0xe0, 0xe5, 0xef, 0x6a, 0x0e, 0x5f, 0xf0, 0xc3, 0x10, 0x71, 0x90, 0x72, 0xe4, 0x0e, 0x1e, 0x8c, 0xc3, 0x94, 0xd6, 0x8e, 0x0d, 0x20, - 0x8b, 0x95, 0xff, 0xc3, 0xed, 0xf5, 0xe5, 0xcb, 0x3e, 0xf1, 0xca, 0x6a, + 0x8b, 0x95, 0xff, 0xc3, 0xed, 0xf5, 0xe5, 0xf3, 0x39, 0xf1, 0xca, 0x6a, 0x29, 0xd8, 0x40, 0xc6, 0x46, 0x3e, 0x03, 0x2b, 0xfe, 0x76, 0xb9, 0xb7, 0x1d, 0x76, 0xb3, 0x97, 0xa0, 0x67, 0x39, 0x7c, 0x9d, 0x46, 0x1c, 0xb7, 0x50, 0xde, 0xcc, 0x39, 0x7f, 0x42, 0xe3, 0x7e, 0x43, 0x97, 0xfd, 0x1e, - 0xeb, 0xfe, 0xff, 0x6c, 0xe5, 0x04, 0xf9, 0x84, 0xb2, 0xff, 0xff, 0x08, - 0x1d, 0x7b, 0x03, 0xa4, 0xa0, 0x57, 0x9f, 0x78, 0xe5, 0xff, 0xb5, 0xff, - 0x2e, 0xa2, 0xc1, 0xaf, 0xce, 0x5e, 0x98, 0x1a, 0x39, 0x7f, 0xe7, 0x4d, - 0x67, 0xdc, 0xdb, 0x6d, 0xb3, 0x95, 0x08, 0xa6, 0x74, 0x4d, 0x8f, 0x5f, - 0xff, 0x0c, 0x4b, 0x92, 0x9e, 0x41, 0x04, 0xb3, 0x67, 0x2b, 0x15, 0x19, + 0xeb, 0xfe, 0xfc, 0xec, 0xe5, 0x04, 0xf9, 0x84, 0xb2, 0xff, 0xff, 0x08, + 0x1d, 0x7b, 0x03, 0xa4, 0xa0, 0x57, 0x9c, 0xf8, 0xe5, 0xff, 0xb5, 0xff, + 0xce, 0xa2, 0xc1, 0xaf, 0xce, 0x5e, 0x98, 0x1a, 0x39, 0x7f, 0xe7, 0x4d, + 0x67, 0x3f, 0x5b, 0x6d, 0xb3, 0x95, 0x08, 0xa6, 0x74, 0x4d, 0x8f, 0x5f, + 0xff, 0x0c, 0x4b, 0xe2, 0x9e, 0x41, 0x04, 0xb3, 0x67, 0x2b, 0x15, 0x19, 0x2e, 0x11, 0xac, 0x21, 0xec, 0x60, 0xbf, 0x97, 0x5e, 0xfd, 0xd8, 0x72, 0xec, 0xfc, 0xe5, 0x41, 0xb4, 0xc1, 0xdb, 0xcf, 0x8c, 0x39, 0x70, 0xc8, 0x4d, 0xd7, 0x00, 0xfd, 0xfe, 0x6f, 0x63, 0x81, 0x17, 0x39, 0x72, 0xd0, - 0xe5, 0xf8, 0x62, 0x78, 0xf8, 0xe5, 0xb6, 0xb3, 0x7c, 0x82, 0xd5, 0x08, + 0xe5, 0xf8, 0x62, 0x78, 0xe4, 0xe5, 0xb6, 0xb3, 0x7c, 0x82, 0xd5, 0x08, 0xc4, 0x42, 0xe7, 0x70, 0xbf, 0x6b, 0x63, 0x13, 0x9c, 0xbf, 0xfe, 0x6f, 0x17, 0xbc, 0xf4, 0xd8, 0xa8, 0xe7, 0xe7, 0x2b, 0x0f, 0xe9, 0x0a, 0x2f, 0xfb, 0x1b, 0xcd, 0x2d, 0xdd, 0x66, 0x8c, 0x39, 0x7e, 0xf7, 0x5c, 0x7f, 0x39, 0x53, 0x9f, 0x6b, 0xa2, 0xdf, 0xf9, 0xfd, 0x93, 0x3c, 0x0c, 0x4c, - 0x72, 0xff, 0xdd, 0x4c, 0x53, 0x26, 0x6e, 0x3e, 0x39, 0x64, 0xd2, 0x28, + 0x72, 0xff, 0xdd, 0x4c, 0x53, 0x26, 0x6e, 0x39, 0x39, 0x64, 0xd2, 0x28, 0x3a, 0x45, 0xb3, 0xdb, 0x96, 0xb3, 0x46, 0x08, 0xa9, 0x27, 0x0c, 0xb8, 0xcb, 0x7f, 0x35, 0xbf, 0xcd, 0x4e, 0xc2, 0x39, 0xde, 0x10, 0xe5, 0xd8, 0x27, 0x2f, 0xff, 0x7a, 0x05, 0x79, 0xee, 0xa6, 0xbf, 0x59, 0xcb, 0xf0, @@ -3402,214 +3402,214 @@ 0xb2, 0x7a, 0x0a, 0x35, 0xf0, 0x54, 0x10, 0x9c, 0xbf, 0xd0, 0xcd, 0xed, 0xc6, 0x73, 0x97, 0xfd, 0xfe, 0xe4, 0x9d, 0x74, 0x9c, 0xe5, 0xf6, 0xf0, 0x7c, 0x72, 0xf7, 0x04, 0x68, 0xe5, 0x21, 0xfd, 0x39, 0xd0, 0x08, 0x6f, - 0x79, 0xda, 0xce, 0x5f, 0xef, 0x75, 0x39, 0xfe, 0xe8, 0x72, 0xff, 0x2b, + 0x79, 0xda, 0xce, 0x5f, 0xef, 0x75, 0x3e, 0xfe, 0xe8, 0x72, 0xff, 0x2b, 0xd8, 0x90, 0x1f, 0x47, 0x2c, 0x27, 0x29, 0x0f, 0x10, 0x06, 0x97, 0x29, 0x87, 0x2a, 0x75, 0x5e, 0x41, 0x8c, 0x53, 0xa6, 0x83, 0x0a, 0xdf, 0x16, 0x80, 0x7d, 0xa3, 0xca, 0x84, 0x37, 0xe5, 0x7f, 0x49, 0xb6, 0x72, 0xfb, 0xa8, 0xf2, 0x39, 0x78, 0x2f, 0x23, 0x95, 0x06, 0xf7, 0x08, 0x6c, 0x08, - 0x44, 0x3f, 0xed, 0x17, 0xff, 0xb9, 0x0b, 0xfa, 0x34, 0x09, 0x6a, 0x24, + 0x44, 0x3f, 0xed, 0x17, 0xff, 0xbe, 0x0b, 0xfa, 0x34, 0x09, 0x6a, 0x24, 0x72, 0xef, 0x6c, 0xe5, 0xf9, 0xd5, 0x6e, 0x34, 0x72, 0x91, 0x11, 0x6e, 0x96, 0x22, 0xf7, 0xff, 0x22, 0xc7, 0x19, 0x13, 0x06, 0x27, 0x39, 0x7f, 0xcb, 0xcf, 0x47, 0x14, 0x1f, 0xce, 0x5f, 0xff, 0xc0, 0x8f, 0x6f, 0x07, - 0x96, 0xa1, 0x02, 0x2f, 0x23, 0x97, 0xe5, 0xf7, 0xe7, 0x6b, 0x39, 0x7f, + 0xe6, 0xa1, 0x02, 0x2f, 0x23, 0x97, 0xe5, 0xf7, 0x97, 0x6b, 0x39, 0x7f, 0xf2, 0x04, 0x41, 0xed, 0xc0, 0xc6, 0xce, 0x52, 0xd3, 0x46, 0x44, 0x41, 0x3a, 0x02, 0xd7, 0x12, 0xcb, 0xff, 0x3e, 0xb3, 0x8e, 0x07, 0x42, 0xd9, 0xcb, 0xff, 0xf9, 0x00, 0x32, 0xc1, 0xf2, 0x34, 0xcf, 0x0b, 0xc8, 0xe5, - 0x7e, 0x89, 0x9f, 0x20, 0x5f, 0xff, 0xc3, 0x9b, 0x07, 0x2c, 0xeb, 0x8e, - 0x4d, 0x28, 0xf8, 0xe5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0x06, 0x5f, 0xcf, + 0x7e, 0x89, 0x9f, 0x20, 0x5f, 0xff, 0xc3, 0x9b, 0x07, 0xcc, 0xeb, 0x8e, + 0x4d, 0x28, 0xe4, 0xe5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0x06, 0x5f, 0xcf, 0x3f, 0xee, 0x21, 0x25, 0x60, 0xf5, 0xec, 0xd8, 0x30, 0xfc, 0x1a, 0x1a, - 0x5e, 0xeb, 0xcb, 0x92, 0x60, 0x03, 0x0c, 0xcb, 0xfe, 0xea, 0x60, 0xe2, + 0x5e, 0xeb, 0xcb, 0xe2, 0x60, 0x03, 0x0c, 0xcb, 0xfe, 0xea, 0x60, 0xe2, 0xc3, 0x87, 0x29, 0x89, 0xca, 0xfa, 0x32, 0x4e, 0x27, 0x77, 0xbc, 0x08, 0x39, 0x7d, 0xfe, 0xb7, 0xb3, 0x97, 0xfb, 0xff, 0x24, 0xec, 0x85, 0x9c, - 0xaf, 0x8f, 0xd5, 0xc7, 0x04, 0x92, 0xfc, 0x16, 0xad, 0xc2, 0xd5, 0x9c, - 0xbf, 0xff, 0x3c, 0xb6, 0x81, 0xe5, 0x99, 0xf7, 0xee, 0x3e, 0x39, 0x50, + 0xae, 0x4f, 0xd5, 0xc7, 0x04, 0x92, 0xfc, 0x16, 0xad, 0xc2, 0xd5, 0x9c, + 0xbf, 0xff, 0x3c, 0xb6, 0x81, 0xf9, 0x99, 0xcf, 0xee, 0x3e, 0x39, 0x50, 0xaf, 0x7b, 0x25, 0x3c, 0xa4, 0x2b, 0x9c, 0xb8, 0x06, 0x57, 0x24, 0x8e, - 0x5f, 0xdf, 0x78, 0x39, 0x8a, 0x9c, 0xa0, 0x9e, 0x2e, 0x0b, 0x5f, 0xd9, - 0xe8, 0x14, 0xfc, 0xe5, 0xfe, 0xd0, 0xbb, 0x6a, 0x7c, 0xd9, 0xcb, 0xbf, + 0x5f, 0xdc, 0xf8, 0x39, 0x8a, 0x9c, 0xa0, 0x9e, 0x2e, 0x0b, 0x5f, 0xd9, + 0xe8, 0x14, 0xfc, 0xe5, 0xfe, 0xd0, 0xbb, 0x6a, 0x72, 0xd9, 0xcb, 0xbf, 0xe2, 0x72, 0x82, 0x7a, 0x3d, 0x37, 0xbc, 0xfa, 0x9c, 0xd1, 0x82, 0xaf, - 0xfc, 0xfa, 0xc1, 0xff, 0x7e, 0xdf, 0xc7, 0x2f, 0xff, 0xff, 0xec, 0xf7, - 0x5c, 0x55, 0xe5, 0xbd, 0x3b, 0xfb, 0x8e, 0x07, 0x96, 0x31, 0xc7, 0xe9, - 0x1e, 0x20, 0xb5, 0xff, 0x9d, 0xd5, 0x5b, 0x87, 0x92, 0xad, 0x9e, 0x20, - 0xb5, 0xff, 0xdd, 0x4e, 0xa4, 0x0f, 0xb9, 0x2a, 0xd9, 0xe2, 0x0b, 0x5f, - 0xe8, 0x41, 0xf7, 0x25, 0x5b, 0x3c, 0x41, 0x6b, 0xf9, 0x98, 0x1e, 0x4a, - 0xb6, 0x78, 0x82, 0xd7, 0xff, 0xfc, 0xe2, 0x28, 0xce, 0x5b, 0x5f, 0x53, - 0x48, 0xac, 0xf8, 0xd9, 0xe2, 0x0b, 0x5d, 0xf7, 0x20, 0xa7, 0x38, 0xb5, + 0xfc, 0xfa, 0xc1, 0xff, 0x7e, 0xdf, 0x27, 0x2f, 0xff, 0xff, 0xec, 0xf7, + 0x5c, 0x55, 0xf9, 0xbd, 0x3b, 0xfb, 0x8e, 0x07, 0xe6, 0x31, 0xc7, 0x99, + 0x1e, 0x20, 0xb5, 0xff, 0x9d, 0xd5, 0x5b, 0x87, 0xe2, 0xad, 0x9e, 0x20, + 0xb5, 0xff, 0xdd, 0x4e, 0xa4, 0x0f, 0xbe, 0x2a, 0xd9, 0xe2, 0x0b, 0x5f, + 0xe8, 0x41, 0xf7, 0xc5, 0x5b, 0x3c, 0x41, 0x6b, 0xf9, 0x98, 0x1f, 0x8a, + 0xb6, 0x78, 0x82, 0xd7, 0xff, 0xfc, 0xe2, 0x28, 0xcf, 0x9b, 0x5f, 0x53, + 0x48, 0xac, 0xf8, 0xd9, 0xe2, 0x0b, 0x5d, 0xcf, 0xc0, 0xa7, 0x38, 0xb5, 0x0d, 0x2a, 0x3a, 0x18, 0x9f, 0xd4, 0x2a, 0xcf, 0xea, 0x00, 0xca, 0x37, - 0xbf, 0xc9, 0x0a, 0xef, 0xdb, 0xf8, 0xe5, 0xf3, 0xeb, 0xf7, 0x39, 0x7f, - 0xf7, 0x53, 0xa9, 0x03, 0xee, 0x4a, 0xb6, 0x78, 0x82, 0xd7, 0xfd, 0x36, - 0xd6, 0x93, 0xf2, 0x55, 0xb3, 0xc4, 0x16, 0xbf, 0x7b, 0x70, 0xce, 0x4b, - 0x45, 0x0a, 0x8a, 0x97, 0xff, 0xb9, 0x2f, 0xa8, 0xb8, 0xf6, 0xf9, 0x2a, - 0xd9, 0xe2, 0x0b, 0x5f, 0xff, 0xfc, 0x22, 0x8c, 0xe4, 0x0c, 0xe5, 0xb5, - 0xf5, 0x34, 0x8a, 0xcf, 0x8d, 0x9e, 0x20, 0xb5, 0x62, 0x64, 0xbf, 0x21, + 0xbf, 0xc9, 0x0a, 0xef, 0xdb, 0xe4, 0xe5, 0xf3, 0xeb, 0xf7, 0x39, 0x7f, + 0xf7, 0x53, 0xa9, 0x03, 0xef, 0x8a, 0xb6, 0x78, 0x82, 0xd7, 0xfd, 0x36, + 0xd6, 0x93, 0xfc, 0x55, 0xb3, 0xc4, 0x16, 0xbf, 0x7b, 0x70, 0xcf, 0x8b, + 0x45, 0x0a, 0x8a, 0x97, 0xff, 0xbe, 0x2f, 0xa8, 0xb8, 0xf6, 0xfe, 0x2a, + 0xd9, 0xe2, 0x0b, 0x5f, 0xff, 0xfc, 0x22, 0x8c, 0xf8, 0x0c, 0xf9, 0xb5, + 0xf5, 0x34, 0x8a, 0xcf, 0x8d, 0x9e, 0x20, 0xb5, 0x62, 0x64, 0xbc, 0xa1, 0xba, 0xf5, 0xff, 0x75, 0x34, 0x8a, 0xcf, 0x8d, 0x9e, 0x20, 0xb5, 0xff, - 0xf3, 0xbf, 0xd2, 0xdf, 0x50, 0x21, 0x8d, 0x41, 0x4b, 0xff, 0x64, 0xa4, + 0xf3, 0xbf, 0x32, 0xdf, 0x50, 0x21, 0x8d, 0x41, 0x4b, 0xff, 0x64, 0xa4, 0x0d, 0xe8, 0x67, 0x68, 0x78, 0x82, 0xd4, 0xb4, 0x73, 0x69, 0x23, 0x69, - 0xf7, 0xfe, 0x5a, 0x6b, 0xcf, 0xfe, 0xf9, 0x36, 0x78, 0x82, 0xd7, 0xf7, - 0x53, 0xbd, 0x4f, 0xcd, 0x00, 0x5a, 0xfd, 0x9f, 0xf2, 0x55, 0xb3, 0xc4, - 0x16, 0xbb, 0x3c, 0xb3, 0xf5, 0xe9, 0xdd, 0x7c, 0x8f, 0x2d, 0xc3, 0x16, - 0xfe, 0x66, 0x07, 0x92, 0xad, 0x9e, 0x20, 0xb5, 0xff, 0x97, 0xd4, 0xd2, - 0x2b, 0x3e, 0x36, 0x78, 0x82, 0xd7, 0x67, 0x27, 0x44, 0x6e, 0xcf, 0xef, - 0xf0, 0x11, 0x8e, 0x3f, 0x48, 0xf1, 0x05, 0xaf, 0xfd, 0x89, 0xc7, 0x07, + 0xf7, 0xfe, 0x5a, 0x6b, 0xcf, 0xfe, 0xfe, 0x36, 0x78, 0x82, 0xd7, 0xf7, + 0x53, 0xbd, 0x4f, 0xcd, 0x00, 0x5a, 0xfd, 0x9f, 0xfc, 0x55, 0xb3, 0xc4, + 0x16, 0xbb, 0x3c, 0xb3, 0xf5, 0xe9, 0xdd, 0x72, 0x8f, 0x2d, 0xc3, 0x16, + 0xfe, 0x66, 0x07, 0xe2, 0xad, 0x9e, 0x20, 0xb5, 0xff, 0x97, 0xd4, 0xd2, + 0x2b, 0x3e, 0x36, 0x78, 0x82, 0xd7, 0x67, 0xc7, 0x44, 0x6e, 0xcf, 0xef, + 0xf0, 0x11, 0x8e, 0x3c, 0xc8, 0xf1, 0x05, 0xaf, 0xfd, 0x89, 0xc7, 0x07, 0x02, 0xf2, 0x3c, 0x41, 0x66, 0x1e, 0x05, 0x05, 0x78, 0x33, 0x46, 0xff, 0x9a, 0x8c, 0x7d, 0x1b, 0x8c, 0x5b, 0xd1, 0x91, 0x02, 0x16, 0xcd, 0xb7, - 0xdd, 0xfc, 0x1a, 0x20, 0xb7, 0x34, 0x46, 0x5c, 0xeb, 0x39, 0x6d, 0xad, + 0xdd, 0xfc, 0x1a, 0x20, 0xb7, 0xd4, 0x46, 0x5c, 0xeb, 0x39, 0x6d, 0xad, 0x93, 0xbf, 0xfd, 0x26, 0x47, 0xc7, 0x17, 0x4b, 0x80, 0xe5, 0xe8, 0x97, - 0x01, 0xca, 0x83, 0x72, 0x23, 0x55, 0x3b, 0x2c, 0xec, 0x24, 0x3f, 0x3e, - 0xff, 0x4a, 0x01, 0x17, 0xdb, 0xff, 0xb2, 0x43, 0x9e, 0xea, 0x67, 0xde, - 0x39, 0x7f, 0xa3, 0xa8, 0xdf, 0xd2, 0xd9, 0xcb, 0xf4, 0x7b, 0x7d, 0x43, - 0x97, 0xfe, 0xd6, 0x2b, 0xdc, 0x60, 0x35, 0x39, 0xcb, 0xfe, 0xf8, 0x71, + 0x01, 0xca, 0x83, 0x72, 0x23, 0x55, 0x3b, 0x2c, 0xec, 0x24, 0x3c, 0xbe, + 0xff, 0x4a, 0x01, 0x17, 0xdb, 0xff, 0xb2, 0x43, 0x9e, 0xea, 0x67, 0x3e, + 0x39, 0x7f, 0xa3, 0xa8, 0xdf, 0x32, 0xd9, 0xcb, 0xf4, 0x7b, 0x7d, 0x43, + 0x97, 0xfe, 0xd6, 0x2b, 0xdc, 0x60, 0x35, 0x39, 0xcb, 0xfe, 0xe4, 0x71, 0x19, 0x83, 0xf9, 0xcb, 0xff, 0x6e, 0x69, 0x00, 0x33, 0x48, 0x01, 0x39, - 0x53, 0xa6, 0x31, 0x23, 0x50, 0x93, 0xe2, 0x0f, 0x8e, 0x2f, 0xfe, 0x8f, - 0xa4, 0xa3, 0x37, 0xe8, 0xf9, 0xb3, 0x97, 0xe9, 0x70, 0x70, 0x02, 0x73, - 0x96, 0xea, 0x1f, 0xcb, 0xa4, 0xdf, 0xb5, 0x1f, 0x4b, 0x67, 0x2a, 0x47, + 0x53, 0xa6, 0x31, 0x23, 0x50, 0x93, 0xe2, 0x0f, 0x8e, 0x2f, 0xfe, 0x8e, + 0x64, 0xa3, 0x37, 0xe8, 0xe5, 0xb3, 0x97, 0xe9, 0x70, 0x70, 0x02, 0x73, + 0x96, 0xea, 0x1f, 0xcb, 0xa4, 0xdf, 0xb5, 0x1c, 0xcb, 0x67, 0x2a, 0x47, 0x9f, 0xa2, 0x6b, 0xcc, 0x7f, 0x1c, 0xbf, 0xf0, 0x36, 0xd3, 0x35, 0xfb, - 0x13, 0x67, 0x2f, 0xfe, 0xe3, 0xc6, 0x36, 0xfd, 0xfa, 0x59, 0xe3, 0x95, + 0x13, 0x67, 0x2f, 0xfe, 0xe3, 0xc6, 0x36, 0xfd, 0xe6, 0x59, 0xe3, 0x95, 0xfa, 0x22, 0xd4, 0x42, 0xbf, 0xdf, 0x83, 0xc3, 0x1e, 0xd9, 0xca, 0x92, 0x60, 0x1f, 0xc2, 0x9f, 0x64, 0xb5, 0x0a, 0x9b, 0x32, 0x31, 0x37, 0x8c, - 0x8a, 0xfe, 0x79, 0x47, 0x17, 0xe9, 0xcb, 0xff, 0xb3, 0xef, 0x6d, 0x06, + 0x8a, 0xfe, 0x79, 0x47, 0x17, 0xe9, 0xcb, 0xff, 0xb3, 0x9f, 0x6d, 0x06, 0x3f, 0x76, 0x1c, 0xbf, 0xf7, 0x0f, 0x82, 0x38, 0xa4, 0x0f, 0xe7, 0x2a, - 0x74, 0x43, 0x01, 0x12, 0xfb, 0xed, 0xc7, 0xc7, 0x2f, 0xfd, 0x2c, 0xfa, + 0x74, 0x43, 0x01, 0x12, 0xfb, 0x9d, 0xc7, 0x27, 0x2f, 0xfd, 0x2c, 0xe6, 0x5a, 0x8f, 0x3f, 0x8e, 0x5e, 0x64, 0x48, 0xe5, 0xfb, 0x03, 0xd0, 0x36, - 0x72, 0xb9, 0x22, 0xa2, 0x62, 0x47, 0x3f, 0x11, 0xcb, 0xc1, 0x7f, 0x1c, + 0x72, 0xbe, 0x22, 0xa2, 0x62, 0x47, 0x3f, 0x11, 0xcb, 0xc1, 0x7f, 0x1c, 0xbf, 0xf6, 0xe0, 0x62, 0x5e, 0xee, 0x09, 0xca, 0xd2, 0x25, 0x9c, 0xfb, - 0x63, 0x97, 0x91, 0xa6, 0x1c, 0xbc, 0xfa, 0xfc, 0xe5, 0xbe, 0x83, 0x75, + 0x63, 0x97, 0x91, 0xa6, 0x1c, 0xbc, 0xfa, 0xfc, 0xe5, 0xb9, 0x83, 0x75, 0xe1, 0xdb, 0xe6, 0xf3, 0xae, 0x72, 0xf9, 0x5d, 0x23, 0x67, 0x2f, 0xd3, 0xbf, 0x61, 0xac, 0xe5, 0x35, 0x27, 0x9f, 0x84, 0x95, 0x0a, 0xcf, 0x72, 0x16, 0x89, 0x1b, 0x13, 0xb4, 0xfe, 0x4e, 0x2e, 0x37, 0xff, 0x0c, 0x4e, 0xce, 0xa6, 0xb4, 0xf2, 0x39, 0x47, 0x28, 0x4f, 0x3d, 0xa2, 0x25, 0xfe, - 0x9e, 0x78, 0x1f, 0xb3, 0xc7, 0x2b, 0x0f, 0x61, 0x08, 0xef, 0xfe, 0xd0, - 0x83, 0xef, 0x0e, 0x4e, 0xe2, 0x72, 0xff, 0xfe, 0x0f, 0x41, 0x3a, 0x66, - 0xb5, 0x91, 0xf4, 0x91, 0x87, 0x2f, 0x3e, 0xa7, 0x39, 0x77, 0xf0, 0x72, + 0x9e, 0x78, 0x1e, 0x73, 0xc7, 0x2b, 0x0f, 0x61, 0x08, 0xef, 0xfe, 0xd0, + 0x83, 0x9f, 0x0e, 0x4e, 0xe2, 0x72, 0xff, 0xfe, 0x0f, 0x41, 0x3a, 0x66, + 0xb5, 0x91, 0xcc, 0x91, 0x87, 0x2f, 0x3e, 0xa7, 0x39, 0x77, 0xf0, 0x72, 0xf9, 0x21, 0x98, 0x72, 0x8e, 0x5f, 0xce, 0xaf, 0xa3, 0x5f, 0x9c, 0xa0, 0x9b, 0xa1, 0x0b, 0xbf, 0xff, 0xd0, 0x81, 0x18, 0x02, 0xfd, 0x8b, 0x0c, 0x2d, 0x46, 0x1c, 0xbb, 0xf8, 0x39, 0x74, 0x2a, 0x72, 0xff, 0xb3, 0xdb, 0x86, 0x29, 0x93, 0x1c, 0xbf, 0xdb, 0xce, 0xa6, 0xc1, 0x39, 0xcb, 0x9b, 0x6c, 0xa5, 0xff, 0x0e, 0x71, 0x79, 0x6d, 0x02, 0x72, 0x96, 0x9f, 0xe2, 0x0e, 0xe8, 0x5d, 0x8b, 0x5d, 0x20, 0xfd, 0x83, 0x87, 0x17, 0x11, 0x7d, - 0x9d, 0x36, 0x68, 0xa0, 0xcd, 0xe6, 0xdb, 0x6c, 0xa5, 0x98, 0x53, 0x99, - 0xa0, 0xbe, 0x99, 0xdf, 0x45, 0x39, 0xa3, 0x89, 0x48, 0x5f, 0xd4, 0xea, + 0x9d, 0x36, 0x68, 0xa0, 0xcd, 0xe6, 0xdb, 0x6c, 0xa5, 0x98, 0x53, 0xe9, + 0xa0, 0xbe, 0x99, 0xdf, 0x45, 0x3e, 0xa3, 0x89, 0x48, 0x5f, 0xd4, 0xea, 0xf1, 0xd6, 0x88, 0xf2, 0xce, 0xaf, 0xef, 0x46, 0x77, 0x27, 0x39, 0x76, - 0x30, 0xe5, 0x7c, 0x78, 0x7b, 0x2d, 0xa8, 0x75, 0x78, 0x92, 0x8f, 0xa0, - 0x29, 0x19, 0x2a, 0xb9, 0x58, 0xe2, 0x7e, 0x94, 0x5a, 0x92, 0xca, 0xb5, + 0x30, 0xe5, 0x72, 0x78, 0x7b, 0x2d, 0xa8, 0x75, 0x78, 0x92, 0x8f, 0xa0, + 0x29, 0x19, 0x2a, 0xb9, 0x58, 0xe2, 0x79, 0x94, 0x5a, 0x92, 0xca, 0xb5, 0x18, 0x43, 0x21, 0x69, 0xd9, 0xd5, 0x17, 0xa5, 0xea, 0x7e, 0xb2, 0x32, 0xf1, 0xf7, 0x2d, 0xe3, 0xd1, 0x83, 0x82, 0x5f, 0x3f, 0x17, 0xcb, 0xfb, 0x3f, 0xfd, 0x35, 0x23, 0x97, 0x2f, 0x0e, 0x50, 0x4f, 0x15, 0xcb, 0xee, 0xc6, 0xce, 0x5d, 0x1e, 0x39, 0x53, 0x9a, 0xd5, 0x8b, 0xd9, 0x87, 0x2b, 0x0d, 0x9f, 0x88, 0xaf, 0xf4, 0x90, 0x71, 0x80, 0xe9, 0xcb, 0xff, 0x67, - 0xb7, 0xd4, 0x63, 0xe6, 0x8e, 0x54, 0x1f, 0x78, 0x99, 0x5f, 0xb3, 0x96, - 0x7f, 0xe3, 0x97, 0xdc, 0xbd, 0x1c, 0x4e, 0x5f, 0x63, 0x33, 0xc7, 0x2f, - 0x79, 0xd5, 0x39, 0x7c, 0xec, 0x79, 0x8e, 0x5f, 0x85, 0xfd, 0xf6, 0xce, - 0x5f, 0xff, 0xf9, 0xe6, 0x04, 0x80, 0xbe, 0x5d, 0x4f, 0x7a, 0x3e, 0x89, + 0xb7, 0xd4, 0x63, 0xe6, 0x8e, 0x54, 0x1f, 0x78, 0x99, 0x5f, 0xb3, 0xe6, + 0x7f, 0xe3, 0x97, 0xdf, 0x3d, 0x1c, 0x4e, 0x5f, 0x63, 0x33, 0xc7, 0x2f, + 0x79, 0xd5, 0x39, 0x7c, 0xec, 0x79, 0x8e, 0x5f, 0x85, 0xfd, 0xce, 0xce, + 0x5f, 0xff, 0xf9, 0xe6, 0x04, 0x80, 0xbf, 0x9d, 0x4f, 0x7a, 0x39, 0x89, 0xe3, 0x67, 0x2f, 0xc2, 0xed, 0x73, 0xcc, 0x72, 0xfa, 0x6d, 0xc7, 0x8e, 0x52, 0xd1, 0x81, 0x33, 0x88, 0x0b, 0x2f, 0xff, 0xf9, 0xac, 0x5d, 0xf8, - 0xc4, 0xbb, 0x1a, 0x9e, 0x3d, 0xb7, 0x91, 0xcb, 0xc9, 0xf4, 0xc7, 0x2f, + 0xc4, 0xbb, 0x1a, 0x9e, 0x3d, 0xb7, 0x91, 0xcb, 0xc9, 0xcc, 0xc7, 0x2f, 0x81, 0xc3, 0xb1, 0x0e, 0x5f, 0xb3, 0x27, 0x06, 0xce, 0x5f, 0x68, 0x53, - 0xf3, 0x97, 0xc8, 0xb7, 0xd1, 0xcb, 0xa3, 0xf3, 0x97, 0xc0, 0x9c, 0x1c, - 0xfa, 0x6e, 0x14, 0x21, 0xa4, 0x44, 0xbf, 0x56, 0xae, 0x6b, 0xfc, 0xe5, - 0xf9, 0xe3, 0xec, 0x59, 0xcb, 0xfe, 0xeb, 0xef, 0xa9, 0x3b, 0x89, 0xcb, + 0xf3, 0x97, 0xc8, 0xb7, 0xd1, 0xcb, 0xa3, 0xf3, 0x97, 0xc0, 0x9c, 0x1f, + 0x7a, 0x6e, 0x14, 0x21, 0xa4, 0x44, 0xbf, 0x56, 0xae, 0x6b, 0xfc, 0xe5, + 0xf9, 0xe3, 0x9c, 0x59, 0xcb, 0xfe, 0xeb, 0xef, 0xa9, 0x3b, 0x89, 0xcb, 0xe7, 0x9d, 0x49, 0x1c, 0xae, 0x19, 0x74, 0x9e, 0x21, 0x03, 0x28, 0x47, - 0x84, 0x83, 0x0a, 0xbe, 0x26, 0x42, 0x16, 0xb1, 0xd9, 0x88, 0xb5, 0x0e, + 0x84, 0x83, 0x0a, 0xb9, 0x26, 0x42, 0x16, 0xb1, 0xd9, 0x88, 0xb5, 0x0e, 0x87, 0x31, 0xfd, 0xab, 0x87, 0x1e, 0xd9, 0x3f, 0xa1, 0x7e, 0x02, 0x26, 0xc6, 0xd4, 0x27, 0xe0, 0x38, 0xbf, 0x84, 0x01, 0x63, 0xc8, 0xe5, 0xe4, - 0x9c, 0x07, 0x2f, 0xd1, 0xfa, 0x7d, 0x87, 0x2e, 0x67, 0x13, 0x96, 0x0c, - 0x1e, 0x08, 0x94, 0x5f, 0xfe, 0x90, 0xc7, 0x26, 0x0c, 0x2b, 0xe4, 0x9c, - 0xe5, 0xf9, 0xd9, 0x9d, 0x61, 0xca, 0xf8, 0xfc, 0xfc, 0x99, 0x7b, 0xda, + 0x9c, 0x07, 0x2f, 0xd1, 0xfa, 0x73, 0x87, 0x2e, 0x67, 0x13, 0x96, 0x0c, + 0x1e, 0x08, 0x94, 0x5f, 0xfe, 0x90, 0xc7, 0xc6, 0x0c, 0x2b, 0xe4, 0x9c, + 0xe5, 0xf9, 0xd9, 0x9d, 0x61, 0xca, 0xe4, 0xfc, 0xfc, 0x99, 0x7b, 0xda, 0x83, 0x97, 0xfb, 0x7e, 0xe3, 0x83, 0x81, 0x39, 0x7f, 0x66, 0xf2, 0x49, 0xa3, 0x97, 0xbb, 0x1c, 0x4e, 0x5e, 0xdc, 0xa7, 0x39, 0x58, 0x6f, 0x14, 0x1e, 0xa8, 0x54, 0x41, 0x22, 0xdc, 0x5e, 0x48, 0x4c, 0xb0, 0x8d, 0xc7, - 0x04, 0xd3, 0xcd, 0x17, 0x9f, 0x92, 0x87, 0x2f, 0x4c, 0x9d, 0x39, 0x7f, + 0x04, 0xd3, 0xcd, 0x17, 0x9f, 0xe2, 0x87, 0x2f, 0x4c, 0x9d, 0x39, 0x7f, 0x46, 0x9e, 0x64, 0xe9, 0xcb, 0xf6, 0xc3, 0x03, 0x3b, 0x9e, 0x56, 0xc7, - 0x6f, 0xf6, 0xb2, 0x78, 0xef, 0x60, 0xe5, 0xe6, 0x43, 0x0e, 0x57, 0xc8, - 0x8d, 0xd1, 0xf3, 0x0c, 0xef, 0xff, 0x86, 0x5c, 0xb0, 0x29, 0xbf, 0xbc, + 0x6f, 0xf6, 0xb2, 0x78, 0xef, 0x60, 0xe5, 0xe6, 0x43, 0x0e, 0x57, 0x28, + 0x8d, 0xd1, 0xf3, 0x0c, 0xef, 0xff, 0x86, 0x5f, 0x30, 0x29, 0xbe, 0x7c, 0x07, 0xd9, 0xcb, 0xf7, 0x40, 0x31, 0xc4, 0xe5, 0xfc, 0x2f, 0xe9, 0x42, - 0xa7, 0x2a, 0x0f, 0x59, 0x42, 0x9b, 0xec, 0xcf, 0xa4, 0x72, 0xf6, 0xd2, + 0xa7, 0x2a, 0x0f, 0x59, 0x42, 0x9b, 0xec, 0xce, 0x64, 0x72, 0xf6, 0xd2, 0x63, 0x96, 0x54, 0x4d, 0xfe, 0xc8, 0xaf, 0xfb, 0x49, 0x1e, 0xce, 0x2e, - 0x13, 0x97, 0xff, 0x3c, 0xe3, 0x1f, 0x20, 0x46, 0x27, 0x39, 0x5a, 0x45, - 0x27, 0x49, 0xc4, 0xe6, 0xfd, 0xcb, 0xb1, 0xa9, 0x1c, 0xae, 0x4a, 0xcb, + 0x13, 0x97, 0xff, 0x3c, 0xe3, 0x1c, 0xa0, 0x46, 0x27, 0x39, 0x5a, 0x45, + 0x27, 0x49, 0xc4, 0xe6, 0xfd, 0xf3, 0xb1, 0xa9, 0x1c, 0xaf, 0x8a, 0xcb, 0x62, 0x1e, 0xd8, 0x62, 0xb8, 0x54, 0x3c, 0x60, 0xad, 0x97, 0xde, 0x66, 0xe0, 0xe5, 0xfd, 0x3c, 0xd2, 0xe1, 0xb5, 0x39, 0xcb, 0xe6, 0x63, 0xf4, 0xe5, 0xa7, 0x39, 0x7e, 0xf7, 0x51, 0x9a, 0x39, 0x52, 0x37, 0x5a, 0x12, 0xbd, 0xd0, 0xa1, 0xcb, 0xf7, 0x71, 0x25, 0xb3, 0x97, 0xff, 0xdd, 0x85, - 0x39, 0xf8, 0x5f, 0xfd, 0xee, 0x3f, 0x29, 0x7e, 0xcf, 0x38, 0x38, 0x73, - 0x97, 0xed, 0x2d, 0xdd, 0x67, 0x88, 0x11, 0x7b, 0x71, 0xf1, 0xcb, 0x7f, - 0x87, 0xa3, 0xf1, 0xa5, 0xef, 0x24, 0xe7, 0x2f, 0x4e, 0xe2, 0x72, 0xa4, - 0x9a, 0xd0, 0x49, 0xfe, 0x54, 0xd3, 0xeb, 0x0a, 0x7c, 0x3b, 0x7f, 0x0a, + 0x3e, 0xf8, 0x5f, 0xfd, 0xee, 0x3f, 0x29, 0x7e, 0xcf, 0x38, 0x38, 0x73, + 0x97, 0xed, 0x2d, 0xdd, 0x67, 0x88, 0x11, 0x7b, 0x71, 0xc9, 0xcb, 0x7f, + 0x87, 0xa3, 0xc9, 0xa5, 0xef, 0x24, 0xe7, 0x2f, 0x4e, 0xe2, 0x72, 0xa4, + 0x9a, 0xd0, 0x49, 0xf9, 0x54, 0xd3, 0xeb, 0x0a, 0x7c, 0x3b, 0x7f, 0x0a, 0xdd, 0x5e, 0xa1, 0xcb, 0xb8, 0x24, 0x72, 0xfb, 0xd3, 0xb8, 0x9c, 0xbc, 0x2e, 0xa9, 0xcb, 0xfc, 0xae, 0x4e, 0x0f, 0x71, 0xf1, 0xcb, 0xfe, 0x79, 0x6a, 0x27, 0x7d, 0x2c, 0xe5, 0xe5, 0x53, 0xc7, 0x2f, 0x6d, 0xfc, 0x72, - 0x95, 0x37, 0x3f, 0x0e, 0xdd, 0xcb, 0xa7, 0x2f, 0xe6, 0x79, 0x02, 0x08, + 0x95, 0x37, 0x3c, 0x8e, 0xdd, 0xf3, 0xa7, 0x2f, 0xe6, 0x79, 0x02, 0x08, 0x39, 0x79, 0x9e, 0x59, 0xcb, 0x7a, 0x0f, 0x2b, 0x0b, 0x6f, 0xe8, 0x66, 0x2b, 0x1b, 0x39, 0x53, 0xa7, 0xb7, 0x83, 0x4b, 0x22, 0xd0, 0xe3, 0x0e, 0x3a, 0xe5, 0xf9, 0x18, 0xb1, 0xf8, 0x9a, 0xed, 0x00, 0xe5, 0xfe, 0x17, - 0x6f, 0x7b, 0x8f, 0xce, 0x5f, 0xf6, 0xb4, 0x9f, 0x4b, 0xcf, 0xf1, 0xcb, + 0x6f, 0x7b, 0x8f, 0xce, 0x5f, 0xf6, 0xb4, 0x9c, 0xcb, 0xcf, 0xc9, 0xcb, 0xcd, 0x1d, 0x53, 0x97, 0xfd, 0x0c, 0x96, 0x4f, 0x80, 0xe1, 0xce, 0x5f, 0xf4, 0x7e, 0x92, 0xea, 0x0f, 0xe7, 0x2d, 0x39, 0xcb, 0x9f, 0xda, 0x3c, 0xbe, 0x1c, 0xe6, 0xb1, 0x1b, 0x48, 0x3e, 0xf0, 0x89, 0xbc, 0xdc, 0x28, - 0x72, 0xf3, 0x6d, 0xb6, 0x7a, 0xbe, 0x97, 0x9c, 0x42, 0x5a, 0xbe, 0xae, - 0x66, 0xb6, 0xfa, 0x40, 0x85, 0x4e, 0x5b, 0xf3, 0x95, 0x86, 0xd5, 0xc8, + 0x72, 0xf3, 0x6d, 0xb6, 0x7a, 0xbe, 0x97, 0x9c, 0x42, 0x5a, 0xbe, 0xaf, + 0xa6, 0xb6, 0xfa, 0x40, 0x85, 0x4e, 0x5b, 0xf3, 0x95, 0x86, 0xd5, 0xc8, 0xea, 0x15, 0x36, 0x04, 0x5d, 0x0d, 0x35, 0x18, 0xaf, 0x4c, 0xbf, 0x4b, 0xf3, 0x85, 0xfe, 0xf7, 0x72, 0x5d, 0x4e, 0x27, 0x2f, 0x99, 0xa0, 0x4e, - 0x72, 0xff, 0xf8, 0x51, 0x5e, 0x7b, 0xf7, 0x40, 0xf2, 0x94, 0x1c, 0xa8, + 0x72, 0xff, 0xf8, 0x51, 0x5f, 0xbb, 0xf7, 0x40, 0xf2, 0x94, 0x1c, 0xa8, 0x3f, 0x6c, 0x24, 0xa9, 0xd3, 0x36, 0x93, 0x5a, 0xb0, 0xab, 0xbe, 0xc0, 0xbc, 0x8e, 0x5f, 0x9c, 0x45, 0x18, 0x72, 0xf6, 0x71, 0x50, 0xe5, 0xc9, 0xd3, 0x97, 0x82, 0xf2, 0x39, 0x7c, 0xec, 0xc6, 0x1c, 0xbe, 0x46, 0x43, - 0x59, 0xcb, 0x93, 0x5c, 0x8f, 0x17, 0x08, 0x68, 0x28, 0xa5, 0xc1, 0x6e, - 0xb0, 0xdf, 0x91, 0x8e, 0x38, 0x72, 0xb9, 0x32, 0x97, 0x5a, 0xa1, 0xc8, + 0x59, 0xcb, 0x93, 0x5f, 0x0f, 0x17, 0x08, 0x68, 0x28, 0xa5, 0xc1, 0x6e, + 0xb0, 0xdf, 0x91, 0x8e, 0x38, 0x72, 0xbe, 0x32, 0x97, 0x5a, 0xa1, 0xc8, 0x37, 0x92, 0xd8, 0x48, 0x72, 0x37, 0x65, 0x56, 0x52, 0x50, 0x43, 0xce, 0x10, 0xfe, 0x70, 0x24, 0x3b, 0x25, 0x04, 0x31, 0x1a, 0x17, 0xdf, 0xd9, 0xdc, 0x58, 0x30, 0xe5, 0xf9, 0x3d, 0x1e, 0xd9, 0x4b, 0xe5, 0xc7, 0xb6, 0x52, 0xe6, 0xdb, 0x29, 0x52, 0x3e, 0x2c, 0x27, 0x6c, 0x8a, 0xcd, 0x94, - 0xe6, 0x6b, 0xef, 0x38, 0xfe, 0x72, 0xb0, 0xf0, 0x15, 0x24, 0xbe, 0x98, + 0xfa, 0x6b, 0xef, 0x38, 0xfe, 0x72, 0xb0, 0xf0, 0x15, 0x24, 0xbe, 0x98, 0x5d, 0xb3, 0x97, 0xa6, 0xea, 0x1c, 0xbf, 0xfe, 0xf4, 0x2f, 0x30, 0x7d, 0xd4, 0x81, 0x9c, 0xe5, 0x1c, 0xac, 0x3d, 0x8d, 0xa6, 0xd4, 0xc9, 0xec, - 0x7f, 0x0f, 0xd1, 0x22, 0xd9, 0x1b, 0x6e, 0xb7, 0xff, 0x86, 0x3e, 0xff, + 0x7f, 0x0f, 0xd1, 0x22, 0xd9, 0x1b, 0x6e, 0xb7, 0xff, 0x86, 0x39, 0xff, 0x06, 0x25, 0xad, 0x41, 0xcb, 0xff, 0x7b, 0x78, 0xbe, 0xb8, 0xfb, 0x67, - 0x2f, 0x20, 0xfe, 0x73, 0x91, 0xbe, 0xb4, 0x31, 0x16, 0xbc, 0x61, 0x0f, + 0x2f, 0x20, 0xfe, 0x73, 0xe1, 0xbe, 0xb4, 0x31, 0x16, 0xbc, 0x61, 0x0f, 0x7f, 0xa7, 0x8e, 0xc7, 0x62, 0x73, 0x97, 0x3e, 0xce, 0x5b, 0xb0, 0x79, 0x4e, 0x69, 0x7e, 0x97, 0x41, 0x1a, 0x39, 0x7f, 0xf3, 0xb3, 0x51, 0xc5, - 0x38, 0x88, 0x36, 0x72, 0xbe, 0x3e, 0xfe, 0x94, 0x5f, 0xb0, 0x0c, 0x8d, + 0x38, 0x88, 0x36, 0x72, 0xb9, 0x3e, 0xfe, 0x94, 0x5f, 0xb0, 0x0c, 0x8d, 0x9c, 0xa3, 0x97, 0x64, 0xda, 0x36, 0x5b, 0x27, 0xbf, 0xe4, 0x07, 0x0f, - 0xd8, 0x50, 0x67, 0x39, 0x7f, 0xd1, 0x3c, 0x7d, 0xe1, 0xc9, 0xce, 0x56, + 0xd8, 0x50, 0x67, 0x39, 0x7f, 0xd1, 0x3c, 0x73, 0xe1, 0xc9, 0xce, 0x56, 0x22, 0x99, 0x65, 0xa8, 0x7f, 0x7f, 0xf2, 0x9b, 0x4d, 0xcc, 0x81, 0xc1, - 0xfc, 0xe5, 0xf3, 0x06, 0x3e, 0x39, 0x41, 0x3e, 0x87, 0x46, 0xa9, 0x93, + 0xfc, 0xe5, 0xf3, 0x06, 0x39, 0x39, 0x41, 0x3e, 0x87, 0x46, 0xa9, 0x93, 0xb2, 0xd4, 0x3e, 0xfb, 0x09, 0x6b, 0xec, 0xee, 0x4e, 0x72, 0xf4, 0x9f, 0x47, 0x2f, 0xef, 0xd8, 0xf2, 0xc0, 0x9c, 0xbe, 0xcf, 0x60, 0x4a, 0x5f, 0x3a, 0xbf, 0xb6, 0x72, 0xa4, 0x78, 0xc2, 0x43, 0x7d, 0x02, 0x30, 0x72, 0xa6, 0x46, 0x86, 0x87, 0x3c, 0xe8, 0xa1, 0x0d, 0xf7, 0xfb, 0x66, 0x8e, - 0x52, 0xa9, 0xaa, 0xa4, 0x3c, 0xbc, 0x7f, 0x7f, 0xc3, 0x9d, 0xce, 0x5d, - 0xc9, 0xce, 0x5f, 0xff, 0xfd, 0xfc, 0x0a, 0xdf, 0xcf, 0xf7, 0xff, 0x79, + 0x52, 0xa9, 0xaa, 0xa4, 0x3c, 0xbc, 0x7f, 0x7f, 0xc3, 0x9d, 0xcf, 0x9d, + 0xc9, 0xce, 0x5f, 0xff, 0xfd, 0xfc, 0x0a, 0xdf, 0xcf, 0xcf, 0xfc, 0xf9, 0x19, 0xbe, 0xc2, 0x82, 0x72, 0xfe, 0x07, 0x0e, 0x9a, 0xd6, 0x1c, 0xbe, 0xf2, 0xb9, 0xd3, 0x97, 0xfe, 0x1c, 0xf7, 0x81, 0x3f, 0xb1, 0x67, 0x2f, 0xc1, 0x03, 0xea, 0x47, 0x2d, 0xb3, 0x97, 0x27, 0xe7, 0x2e, 0xea, 0x1c, - 0xb8, 0x1b, 0xe4, 0x6b, 0x66, 0x17, 0xa7, 0x3e, 0xef, 0xcf, 0xae, 0xfe, - 0x0e, 0x5d, 0xfc, 0x1c, 0xbf, 0x02, 0x58, 0x3c, 0xd0, 0xd7, 0x7e, 0x2f, + 0xb8, 0x1b, 0xf8, 0x6b, 0x66, 0x17, 0xa7, 0x3e, 0xef, 0xcf, 0xae, 0xfe, + 0x0e, 0x5d, 0xfc, 0x1c, 0xbf, 0x02, 0x58, 0x3f, 0x50, 0xd7, 0x7e, 0x2f, 0x50, 0x9c, 0x3a, 0xa4, 0x68, 0x7f, 0xfc, 0x25, 0x85, 0x42, 0xff, 0xfb, - 0x05, 0xfe, 0xda, 0xaa, 0xbf, 0x25, 0xb3, 0xf3, 0x97, 0xff, 0x7b, 0xb8, - 0xc5, 0x23, 0xfc, 0xfb, 0xc7, 0x2f, 0xf7, 0xcb, 0x4d, 0x29, 0x01, 0x39, - 0x7d, 0xfb, 0x1e, 0x5c, 0x91, 0xa3, 0xb5, 0x5f, 0x23, 0xdc, 0x0f, 0x1c, - 0xbf, 0xbf, 0x62, 0x9b, 0x52, 0x73, 0x97, 0xf6, 0xd0, 0x46, 0x3e, 0x39, - 0x76, 0x7c, 0x72, 0xbe, 0x3f, 0x6f, 0x19, 0xb4, 0x2c, 0xbe, 0xff, 0x49, - 0xa3, 0x95, 0x09, 0x96, 0x49, 0x29, 0xe1, 0x1a, 0xd9, 0x95, 0xe0, 0x7d, + 0x05, 0xf9, 0xda, 0xaa, 0xbf, 0xc5, 0xb3, 0xf3, 0x97, 0xff, 0x7b, 0xb8, + 0xc5, 0x23, 0xfc, 0xe7, 0xc7, 0x2f, 0xf7, 0x2b, 0x4d, 0x29, 0x01, 0x39, + 0x7d, 0xfb, 0x1e, 0x5f, 0x11, 0xa3, 0xb5, 0x5f, 0x23, 0xdc, 0x0f, 0x1c, + 0xbf, 0xbf, 0x62, 0x9b, 0x52, 0x73, 0x97, 0xf6, 0xd0, 0x46, 0x39, 0x39, + 0x76, 0x72, 0x72, 0xb9, 0x3f, 0x6f, 0x19, 0xb4, 0x2c, 0xbe, 0xff, 0x49, + 0xa3, 0x95, 0x09, 0x96, 0x49, 0x29, 0xe1, 0x1a, 0xd9, 0x95, 0xe0, 0x73, 0xe3, 0x96, 0x73, 0x95, 0xb3, 0x5d, 0xe1, 0xeb, 0xb1, 0xb3, 0x97, 0xfd, - 0x1f, 0x67, 0xf1, 0xc7, 0x27, 0x39, 0x7f, 0x0e, 0x7b, 0x6f, 0xf9, 0xca, + 0x1c, 0xe7, 0xf1, 0xc7, 0x27, 0x39, 0x7f, 0x0e, 0x7b, 0x6f, 0xf9, 0xca, 0xd2, 0x20, 0x3f, 0x17, 0xd9, 0xe5, 0xff, 0x44, 0xfb, 0xd6, 0x2e, 0x27, 0x39, 0x7f, 0xb0, 0x67, 0xc0, 0xbf, 0x4e, 0x54, 0xc7, 0xd8, 0xd9, 0xd5, 0xfd, 0x8c, 0xc0, 0xa3, 0x67, 0x2e, 0x64, 0x1c, 0xa6, 0x1e, 0x1b, 0x96, 0xdf, 0xc3, 0x93, 0x75, 0x3c, 0x72, 0xfb, 0x33, 0xbb, 0x39, 0x58, 0x8d, 0x67, 0x67, 0xf1, 0x0f, 0x01, 0x6d, 0xe6, 0xdb, 0x6c, 0xa5, 0xfb, 0x15, - 0x10, 0x6c, 0xa7, 0x33, 0x41, 0x7d, 0xcd, 0xb6, 0xdb, 0x39, 0x76, 0x7e, + 0x10, 0x6c, 0xa7, 0xd3, 0x41, 0x7d, 0xf5, 0xb6, 0xdb, 0x39, 0x76, 0x7e, 0x72, 0xb0, 0xdf, 0xf8, 0xa2, 0xa1, 0x13, 0x3e, 0x79, 0xbf, 0xfe, 0x49, 0x3e, 0xd8, 0xc7, 0x93, 0xab, 0xd4, 0x39, 0x7c, 0x9a, 0xff, 0x67, 0x2f, 0xfb, 0x7a, 0x80, 0x78, 0x53, 0x89, 0xcb, 0xff, 0x0e, 0x6d, 0x7d, 0x45, - 0xc0, 0x9c, 0xbf, 0xff, 0xca, 0xb6, 0xfa, 0x57, 0x9e, 0xf2, 0x42, 0x07, + 0xc0, 0x9c, 0xbf, 0xff, 0xca, 0xb6, 0xfa, 0x57, 0xee, 0xf2, 0x42, 0x07, 0xde, 0x09, 0xca, 0x84, 0x6d, 0x61, 0xd2, 0x1e, 0x5f, 0xda, 0x02, 0xfa, - 0x9b, 0x39, 0x7c, 0xdb, 0x8c, 0x8e, 0x5f, 0xf7, 0xa3, 0xef, 0xdf, 0xbd, + 0x9b, 0x39, 0x7c, 0xdb, 0x8c, 0x8e, 0x5f, 0xf7, 0xa3, 0x9f, 0xdf, 0xbd, 0x43, 0x96, 0xe9, 0xca, 0xc3, 0xcb, 0x59, 0xd5, 0xf6, 0xd1, 0x90, 0x72, 0xfc, 0x39, 0xe8, 0xd1, 0xcb, 0xcd, 0xb6, 0xd9, 0x4b, 0xf3, 0xab, 0xd4, - 0xf1, 0x4e, 0x66, 0x82, 0xa1, 0x10, 0x08, 0x8d, 0x7b, 0x8c, 0x30, 0xe5, - 0xef, 0x23, 0x67, 0x2f, 0x6d, 0xf4, 0x72, 0xbe, 0x37, 0x3e, 0x1d, 0xbd, + 0xf1, 0x4f, 0xa6, 0x82, 0xa1, 0x10, 0x08, 0x8d, 0x7b, 0x8c, 0x30, 0xe5, + 0xef, 0x23, 0x67, 0x2f, 0x6d, 0xf4, 0x72, 0xb9, 0x37, 0x3e, 0x1d, 0xbd, 0xd8, 0x09, 0xca, 0xc4, 0x4a, 0xa2, 0xbb, 0x91, 0x5f, 0xb3, 0xfc, 0xc9, - 0x8e, 0x5b, 0x7c, 0x93, 0xcd, 0xf8, 0x87, 0x50, 0xa1, 0xec, 0x2d, 0x84, + 0x8e, 0x5b, 0x7f, 0x13, 0xcd, 0xe4, 0x87, 0x50, 0xa1, 0xec, 0x2d, 0x84, 0xb6, 0xd2, 0x0a, 0xa9, 0x7c, 0x94, 0x75, 0x5c, 0x32, 0xaf, 0x60, 0x4a, 0xc5, 0xbf, 0x70, 0xfd, 0x89, 0xc0, 0x72, 0xff, 0xe4, 0xf4, 0x6b, 0x07, 0xce, 0xe2, 0x72, 0xa6, 0x5c, 0xbf, 0xec, 0x3f, 0x46, 0x59, 0x18, 0x0c, @@ -3617,136 +3617,136 @@ 0x6e, 0xf0, 0xc7, 0x13, 0x97, 0xff, 0x6a, 0x17, 0xd1, 0x7f, 0x0c, 0x36, 0x72, 0xee, 0x1d, 0x0e, 0x5c, 0x9d, 0x39, 0x53, 0x9b, 0x1d, 0x0d, 0xd4, 0x22, 0x59, 0xdd, 0x2f, 0xbd, 0xb0, 0x35, 0x9c, 0xbf, 0xd0, 0x32, 0x14, - 0x8f, 0x8e, 0x54, 0x36, 0x99, 0x12, 0x8c, 0x1c, 0x2f, 0x39, 0x29, 0x1d, - 0x58, 0xe4, 0x56, 0x6d, 0xf1, 0xd2, 0x3a, 0xea, 0x3b, 0x9e, 0xca, 0x4c, + 0x8e, 0x4e, 0x54, 0x36, 0x99, 0x12, 0x8c, 0x1c, 0x2f, 0x39, 0x29, 0x1d, + 0x58, 0xe4, 0x56, 0x6d, 0xc9, 0xd2, 0x3a, 0xea, 0x3b, 0x9e, 0xca, 0x4c, 0x77, 0x0f, 0xe1, 0x42, 0x31, 0xb9, 0xee, 0x1e, 0xfe, 0x9d, 0xa8, 0xe2, 0x70, 0xd2, 0x16, 0x6a, 0x10, 0xf0, 0x13, 0x5f, 0x92, 0x69, 0x20, 0x9c, 0xb9, 0xa9, 0x43, 0x97, 0xfd, 0x37, 0xb8, 0x37, 0x13, 0x03, 0x47, 0x2f, 0xf0, 0x60, 0x59, 0x01, 0x83, 0x95, 0x07, 0xe0, 0xe7, 0xf7, 0xff, 0x08, - 0xbf, 0xde, 0xec, 0x2f, 0x26, 0x39, 0x7f, 0x4f, 0x02, 0x8c, 0xc3, 0x97, - 0xff, 0x62, 0x76, 0x03, 0xd0, 0x47, 0xdb, 0x39, 0x78, 0x2a, 0xfe, 0x72, - 0xfc, 0xcd, 0x69, 0xfc, 0x72, 0xb9, 0x1e, 0x3c, 0x0f, 0xdf, 0xfd, 0x33, + 0xbf, 0x3e, 0xec, 0x2f, 0x26, 0x39, 0x7f, 0x4f, 0x02, 0x8c, 0xc3, 0x97, + 0xff, 0x62, 0x76, 0x03, 0xd0, 0x47, 0x3b, 0x39, 0x78, 0x2a, 0xfe, 0x72, + 0xfc, 0xcd, 0x69, 0xfc, 0x72, 0xbe, 0x1e, 0x3c, 0x0f, 0xdf, 0xfd, 0x33, 0xaf, 0xb1, 0x2f, 0x0e, 0x30, 0xe5, 0xfd, 0xac, 0x11, 0x79, 0xce, 0x52, - 0xcf, 0xc1, 0x11, 0x2f, 0xfe, 0x86, 0xfe, 0x96, 0xf9, 0x67, 0x70, 0x4e, - 0x5f, 0xff, 0x23, 0x3e, 0x96, 0xf9, 0x60, 0x8e, 0x27, 0xe7, 0x2f, 0x27, - 0x40, 0x72, 0xb9, 0x2b, 0x35, 0x6a, 0x89, 0xe5, 0x08, 0xbc, 0x20, 0x44, + 0xcf, 0xc1, 0x11, 0x2f, 0xfe, 0x86, 0xf9, 0x96, 0xfe, 0x67, 0x70, 0x4e, + 0x5f, 0xff, 0x23, 0x39, 0x96, 0xfe, 0x60, 0x8e, 0x27, 0xe7, 0x2f, 0x27, + 0x40, 0x72, 0xbe, 0x2b, 0x35, 0x6a, 0x89, 0xe5, 0x08, 0xbc, 0x20, 0x44, 0x4d, 0x16, 0x76, 0x11, 0x6f, 0x09, 0x31, 0x21, 0xf2, 0x3f, 0x15, 0x1b, - 0x73, 0x6a, 0xa5, 0x06, 0x5c, 0x35, 0x30, 0x8f, 0xe1, 0x21, 0xb6, 0xd5, + 0x7d, 0x6a, 0xa5, 0x06, 0x5c, 0x35, 0x30, 0x8f, 0xe1, 0x21, 0xb6, 0xd5, 0xc6, 0x93, 0xc3, 0x42, 0x93, 0x85, 0xe3, 0x6c, 0x6a, 0x31, 0x91, 0xb5, 0x03, 0xbe, 0x15, 0x0a, 0x18, 0xad, 0x1f, 0x27, 0x9e, 0xf5, 0x95, 0x33, 0x30, 0x34, 0xde, 0xec, 0xbc, 0x86, 0x75, 0x67, 0x16, 0xd7, 0x58, 0x24, - 0x7d, 0x4c, 0xdf, 0x4a, 0x71, 0xf3, 0x5c, 0x79, 0xb3, 0x56, 0x24, 0x1a, + 0x73, 0x4c, 0xdf, 0x4a, 0x71, 0xf3, 0x5c, 0x79, 0xb3, 0x56, 0x24, 0x1a, 0xac, 0xb3, 0x99, 0x4b, 0xba, 0xed, 0xa1, 0x4a, 0x7b, 0x49, 0x25, 0xfd, 0x36, 0x0f, 0x87, 0x8c, 0x84, 0x6b, 0xf6, 0xbd, 0xde, 0x6d, 0x17, 0xad, 0x7c, 0xb0, 0x27, 0xac, 0x38, 0xcb, 0x48, 0x6e, 0x5d, 0x03, 0x4a, 0x56, - 0x32, 0x95, 0xbc, 0x1f, 0x04, 0xe3, 0xed, 0x73, 0x94, 0x20, 0x87, 0x2d, + 0x32, 0x95, 0xbc, 0x1f, 0x04, 0xe3, 0xed, 0x7d, 0x94, 0x20, 0x87, 0x2d, 0x41, 0xa1, 0x57, 0x99, 0x9e, 0x39, 0x7f, 0x9d, 0x91, 0xe4, 0xda, 0x1c, - 0xbf, 0x66, 0x94, 0xf6, 0xce, 0x5b, 0x9f, 0xe7, 0xec, 0x23, 0x9b, 0x31, - 0xbf, 0xdc, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0xe3, 0x5f, 0xee, 0x79, 0xa5, - 0xbb, 0xac, 0xd1, 0x75, 0xaf, 0xfe, 0xe6, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, + 0xbf, 0x66, 0x94, 0xf6, 0xce, 0x5b, 0xef, 0xe7, 0xec, 0x23, 0x9b, 0x31, + 0xbf, 0xdf, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0xe3, 0x5f, 0xef, 0xb9, 0xa5, + 0xbb, 0xac, 0xd1, 0x75, 0xaf, 0xfe, 0xfa, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0x8a, 0xa2, 0x50, 0xb8, 0x4c, 0xa1, 0x4e, 0x12, 0xa5, 0x61, 0x26, 0xb2, 0x94, 0x95, 0x04, 0xd7, 0x09, 0xc7, 0xd4, 0x21, 0x3b, 0xfc, - 0x2d, 0x36, 0x6f, 0xe4, 0x1e, 0x04, 0x1b, 0xff, 0xdc, 0xd8, 0xf2, 0xe7, + 0x2d, 0x36, 0x6f, 0xe4, 0x1e, 0x04, 0x1b, 0xff, 0xdf, 0x58, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0xd2, 0xff, 0xb8, 0x5b, 0xa8, 0xd6, 0xf1, - 0xf7, 0x01, 0xcb, 0xf6, 0x96, 0xee, 0xb3, 0x44, 0x6e, 0xbf, 0xe4, 0xd2, + 0xcf, 0x01, 0xcb, 0xf6, 0x96, 0xee, 0xb3, 0x44, 0x6e, 0xbf, 0xe4, 0xd2, 0x70, 0xeb, 0xec, 0x36, 0x72, 0xff, 0xff, 0xfb, 0x88, 0xe6, 0xf6, 0x18, - 0xcd, 0x2d, 0xdd, 0x7c, 0xe4, 0x9e, 0x8f, 0x6c, 0xd1, 0x87, 0xad, 0xd8, - 0x46, 0x52, 0x1f, 0x5f, 0xb5, 0x0d, 0xb0, 0x27, 0x2f, 0xfc, 0xf2, 0xe7, + 0xcd, 0x2d, 0xdd, 0x7f, 0x64, 0x9e, 0x8f, 0x6c, 0xd1, 0x87, 0xad, 0xd8, + 0x46, 0x52, 0x1f, 0x5f, 0xb5, 0x0d, 0xb0, 0x27, 0x2f, 0xfc, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0xfa, 0xfe, 0x8f, 0x29, 0xd7, 0xf1, 0xcb, 0xf9, 0x4d, 0x2b, 0xd0, 0x6c, 0xe5, 0xe8, 0xd4, 0x1c, 0xac, 0x3c, 0xc4, 0x31, 0xbf, 0xee, 0xe2, 0x6a, 0x5d, 0x46, 0xce, 0x5f, 0x03, 0xa9, 0xa3, - 0x97, 0xa6, 0xde, 0x8e, 0x5b, 0x9b, 0x50, 0x55, 0xe7, 0x88, 0xcb, 0x87, + 0x97, 0xa6, 0xde, 0x8e, 0x5b, 0xeb, 0x50, 0x55, 0xe7, 0x88, 0xcb, 0x87, 0xf6, 0x89, 0xd8, 0x53, 0xd4, 0xc1, 0x7a, 0xf1, 0x03, 0x43, 0x95, 0x08, - 0xaf, 0xff, 0x7d, 0x2f, 0x24, 0xdc, 0xc2, 0x9c, 0x60, 0x27, 0x2f, 0xf7, - 0x3c, 0xd2, 0xdd, 0xd6, 0x68, 0xaa, 0xd7, 0x27, 0x01, 0xcb, 0xb3, 0x47, + 0xaf, 0xff, 0x73, 0x2f, 0x24, 0xdf, 0x42, 0x9c, 0x60, 0x27, 0x2f, 0xf7, + 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0xaa, 0xd7, 0x27, 0x01, 0xcb, 0xb3, 0x47, 0x2f, 0x91, 0x8f, 0xc4, 0xe5, 0x2a, 0x7a, 0x4e, 0x33, 0xe1, 0x6b, 0xc3, 0xc0, 0xd9, 0xcb, 0xfb, 0xb1, 0xc4, 0x01, 0xc3, 0x97, 0xf3, 0xf6, 0x61, 0x80, 0x9c, 0xbf, 0xfb, 0xdd, 0x8d, 0x8b, 0x83, 0x87, 0x4d, 0x1c, 0xbd, - 0x12, 0xc3, 0x95, 0x24, 0x5f, 0x84, 0xbf, 0xe2, 0xd9, 0x92, 0x2f, 0xf9, - 0x5c, 0x1c, 0xfb, 0xce, 0xc3, 0x97, 0xb8, 0x23, 0xc7, 0x2f, 0xf6, 0xa1, - 0x8a, 0x40, 0xac, 0xe5, 0xef, 0x9f, 0xe3, 0x97, 0xcf, 0xe7, 0xf8, 0xe5, - 0xc1, 0x43, 0x97, 0xf6, 0x69, 0x6e, 0xeb, 0x34, 0x48, 0x0a, 0xe4, 0x79, - 0xfc, 0xc5, 0xaf, 0xdb, 0x71, 0x7f, 0x8e, 0x5c, 0x08, 0x39, 0x52, 0x3e, - 0x3f, 0x89, 0xb4, 0x4f, 0x7f, 0xa5, 0x1a, 0x9e, 0x35, 0x39, 0xcb, 0xfd, + 0x12, 0xc3, 0x95, 0x24, 0x5f, 0x84, 0xbf, 0x92, 0xd9, 0x92, 0x2f, 0xf9, + 0x5c, 0x1c, 0xe7, 0xce, 0xc3, 0x97, 0xb8, 0x23, 0xc7, 0x2f, 0xf6, 0xa1, + 0x8a, 0x40, 0xac, 0xe5, 0xee, 0x5f, 0x93, 0x97, 0xcf, 0xe7, 0xe4, 0xe5, + 0xc1, 0x43, 0x97, 0xf6, 0x69, 0x6e, 0xeb, 0x34, 0x48, 0x0a, 0xf8, 0x79, + 0xff, 0x45, 0xaf, 0xdb, 0x71, 0x7e, 0x4e, 0x5c, 0x08, 0x39, 0x52, 0x3e, + 0x3e, 0x49, 0xb4, 0x4f, 0x7f, 0xa5, 0x1a, 0x9e, 0x35, 0x39, 0xcb, 0xfd, 0xa9, 0xd9, 0x03, 0x2d, 0x9c, 0xa8, 0x3e, 0x9c, 0x35, 0xbd, 0x3b, 0x84, - 0xe5, 0xfe, 0x5a, 0x63, 0x60, 0x1f, 0x1c, 0xac, 0x3d, 0x0f, 0x87, 0x6e, + 0xe5, 0xfe, 0x5a, 0x63, 0x60, 0x1f, 0x1c, 0xac, 0x3d, 0x0e, 0x47, 0x6e, 0xe1, 0x3a, 0x72, 0xff, 0xf6, 0x4d, 0xd7, 0x67, 0xbb, 0x1e, 0x03, 0x0e, 0x54, 0xeb, 0x8b, 0x81, 0x2f, 0xc8, 0x6f, 0xaa, 0x7e, 0xd6, 0x73, 0x30, 0xfb, 0x0c, 0xfa, 0x3c, 0xf0, 0xd4, 0x18, 0x4c, 0xf9, 0xc1, 0xa1, 0x12, 0x83, 0x97, 0xe8, 0x11, 0xcf, 0x1c, 0xbe, 0xd6, 0x91, 0x67, 0x2f, 0x87, - 0x27, 0xe6, 0xd0, 0xf1, 0xd4, 0x25, 0xbf, 0xdc, 0xfa, 0xec, 0xc8, 0x09, - 0xca, 0xe6, 0x9c, 0x1e, 0xa3, 0x11, 0x68, 0x7d, 0x7f, 0xb9, 0xe6, 0x96, - 0xee, 0xb3, 0x45, 0x90, 0xbf, 0xdc, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0xd7, - 0x5f, 0xfe, 0xc5, 0x22, 0x7e, 0x79, 0x37, 0x83, 0x02, 0x72, 0xff, 0x73, + 0x27, 0xfa, 0xd0, 0xf1, 0xd4, 0x25, 0xbf, 0xdf, 0x7a, 0xec, 0xc8, 0x09, + 0xca, 0xfa, 0x9c, 0x1e, 0xa3, 0x11, 0x68, 0x7d, 0x7f, 0xbe, 0xe6, 0x96, + 0xee, 0xb3, 0x45, 0x90, 0xbf, 0xdf, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0xd7, + 0x5f, 0xfe, 0xc5, 0x22, 0x7f, 0xb9, 0x37, 0x83, 0x02, 0x72, 0xff, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x8b, 0x91, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0xbb, - 0x17, 0xfe, 0x79, 0x73, 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x39, 0x6e, 0x78, + 0x17, 0xfe, 0x79, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x8a, 0x39, 0x6f, 0xb8, 0x88, 0x06, 0x1a, 0x5f, 0x0c, 0x49, 0x87, 0x2f, 0xfd, 0xc3, 0x70, 0x8c, 0x8d, 0x4b, 0x13, 0x89, 0xcb, 0x48, 0xe5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0x95, 0x5f, 0xf2, 0xfa, 0x93, 0x76, 0x27, 0xc3, 0x97, 0xff, 0xbb, 0x13, - 0xc7, 0x53, 0x8b, 0x87, 0xa8, 0x73, 0x99, 0xba, 0xba, 0x5c, 0xf1, 0x19, - 0x73, 0x37, 0x57, 0xc9, 0x86, 0xbc, 0x37, 0x2f, 0xfc, 0xe9, 0xe9, 0x00, - 0x2e, 0x3f, 0x9c, 0xb7, 0x30, 0xa7, 0xbf, 0xf1, 0x0b, 0x23, 0x57, 0xe9, - 0x4d, 0x4e, 0xce, 0xd1, 0x94, 0xb4, 0xdc, 0x85, 0x0f, 0xca, 0x09, 0x3c, + 0xc7, 0x53, 0x8b, 0x87, 0xa8, 0x73, 0xe9, 0xba, 0xba, 0x5f, 0x71, 0x19, + 0x73, 0x37, 0x57, 0x29, 0x86, 0xbc, 0x37, 0x2f, 0xfc, 0xe9, 0xe9, 0x00, + 0x2e, 0x3f, 0x9c, 0xb7, 0xd0, 0xa7, 0xbf, 0xc9, 0x0b, 0x23, 0x57, 0xe9, + 0x4d, 0x4e, 0xce, 0xd1, 0x94, 0xb4, 0xdc, 0x85, 0x0f, 0x2a, 0x09, 0x3c, 0xe4, 0xc3, 0xbf, 0xd0, 0x45, 0x07, 0x69, 0xbe, 0x86, 0x0f, 0x19, 0x41, - 0x37, 0xfd, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x1c, 0x2f, 0xf9, 0x39, - 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x6a, 0xb7, 0x37, 0x44, 0x6f, 0x91, 0xef, - 0xff, 0x73, 0x63, 0xcb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x4b, 0x6b, 0xc0, - 0xd7, 0xe7, 0x2e, 0xcf, 0x8e, 0x5f, 0xe0, 0xe3, 0x19, 0x09, 0xb3, 0x97, - 0xb8, 0x82, 0x47, 0x29, 0x68, 0x86, 0xf8, 0x79, 0x05, 0xf8, 0x99, 0x5e, - 0xe8, 0x64, 0x72, 0xff, 0xb3, 0xe1, 0xcf, 0xff, 0x79, 0x1c, 0xb9, 0x8b, - 0x39, 0x7f, 0xb1, 0x3e, 0xd8, 0x70, 0x4e, 0x54, 0x22, 0x0e, 0x47, 0x5a, - 0x17, 0xbe, 0x18, 0xfa, 0x47, 0x2f, 0xe9, 0xe1, 0x6f, 0xaf, 0xce, 0x5f, - 0xff, 0x9f, 0xef, 0xc3, 0xd7, 0x96, 0x6c, 0x40, 0xea, 0x1c, 0xbe, 0xff, + 0x37, 0xfd, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x1c, 0x2f, 0xf9, 0x3e, + 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x6a, 0xb7, 0xd7, 0x44, 0x6f, 0x91, 0xef, + 0xff, 0x7d, 0x63, 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x4b, 0x6b, 0xc0, + 0xd7, 0xe7, 0x2e, 0xce, 0x4e, 0x5f, 0xe0, 0xe3, 0x19, 0x09, 0xb3, 0x97, + 0xb8, 0x82, 0x47, 0x29, 0x68, 0x86, 0xe4, 0x79, 0x05, 0xf8, 0x99, 0x5e, + 0xe8, 0x64, 0x72, 0xff, 0xb3, 0x91, 0xcf, 0xff, 0x79, 0x1c, 0xb9, 0x8b, + 0x39, 0x7f, 0xb1, 0x39, 0xd8, 0x70, 0x4e, 0x54, 0x22, 0x0e, 0x47, 0x5a, + 0x17, 0xbe, 0x18, 0xe6, 0x47, 0x2f, 0xe9, 0xe1, 0x6f, 0xaf, 0xce, 0x5f, + 0xff, 0x9f, 0x9f, 0xc3, 0xd7, 0x96, 0x6c, 0x40, 0xea, 0x1c, 0xbe, 0xff, 0x35, 0x31, 0xca, 0x5a, 0x33, 0x34, 0x45, 0xd2, 0xff, 0xd5, 0xec, 0xa9, 0xcb, 0xf9, 0x34, 0x29, 0xed, 0x9c, 0xbf, 0x69, 0xc7, 0x20, 0xe5, 0x1a, 0x21, 0xb2, 0x1f, 0x1f, 0x44, 0x9c, 0xb2, 0xe8, 0x13, 0x97, 0xb1, 0x02, 0x72, 0xf0, 0x71, 0x87, 0x2e, 0x41, 0x09, 0xb7, 0x41, 0xba, 0x83, 0xf6, - 0x92, 0x65, 0xf6, 0x4d, 0x2c, 0x39, 0x7f, 0xe7, 0x97, 0x3c, 0xd2, 0xdd, + 0x92, 0x65, 0xf6, 0x4d, 0x2c, 0x39, 0x7f, 0xe7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x98, 0x17, 0x9b, 0x4f, 0xce, 0x5f, 0x6d, 0xc7, 0xf3, 0x95, - 0x31, 0xe0, 0x7e, 0x3d, 0x7f, 0x81, 0xf6, 0x92, 0x19, 0x87, 0x2f, 0xdd, + 0x31, 0xe0, 0x7e, 0x3d, 0x7f, 0x81, 0xce, 0x92, 0x19, 0x87, 0x2f, 0xdd, 0x48, 0x19, 0xce, 0x5f, 0xf4, 0x4f, 0xe1, 0x80, 0x7b, 0x67, 0x2d, 0xee, - 0xa2, 0x4f, 0x66, 0x6d, 0x09, 0xef, 0xbe, 0x5a, 0x2a, 0x72, 0xb0, 0xf7, + 0xa2, 0x4f, 0x66, 0x6d, 0x09, 0xef, 0xb9, 0x5a, 0x2a, 0x72, 0xb0, 0xf7, 0x3c, 0x71, 0x7f, 0x27, 0xb1, 0x91, 0xd3, 0x97, 0xff, 0x46, 0x93, 0xf9, 0xfb, 0x1b, 0x06, 0xce, 0x56, 0x8f, 0xcb, 0xc5, 0x97, 0xfe, 0xc6, 0x66, - 0xb3, 0xe9, 0x67, 0x8e, 0x5f, 0xc9, 0xd4, 0x66, 0x2a, 0x72, 0xba, 0x7d, + 0xb3, 0x99, 0x67, 0x8e, 0x5f, 0xc9, 0xd4, 0x66, 0x2a, 0x72, 0xba, 0x7d, 0x7b, 0x3e, 0xbf, 0xfc, 0xf3, 0xf5, 0x20, 0x72, 0x64, 0xd2, 0x1c, 0xac, 0x47, 0xbf, 0xa1, 0x1a, 0xd9, 0x15, 0xcb, 0xc3, 0x97, 0x03, 0xf2, 0x94, 0x86, 0xbb, 0x42, 0xd7, 0xe5, 0x62, 0x58, 0x13, 0x97, 0xfb, 0x02, 0x39, 0xee, 0xe1, 0xcb, 0xb8, 0x65, 0x9e, 0x30, 0xa5, 0xf9, 0x46, 0x8e, 0x3f, 0x9c, 0xbf, 0xb3, 0xae, 0xa0, 0xf8, 0xe5, 0x4e, 0x7b, 0x01, 0x2b, 0xbf, 0xb3, 0xde, 0x8d, 0x6c, 0xe5, 0xfc, 0xe3, 0xfc, 0xff, 0xf8, 0xe5, 0x42, - 0x20, 0x04, 0x8d, 0xa1, 0x6d, 0xb9, 0xc3, 0x22, 0xae, 0x73, 0xf0, 0xc2, - 0x83, 0x21, 0xf6, 0xb8, 0x50, 0xfd, 0x0b, 0x7d, 0x10, 0xb0, 0x89, 0xe1, + 0x20, 0x04, 0x8d, 0xa1, 0x6d, 0xbe, 0xc3, 0x22, 0xae, 0x73, 0xf0, 0xc2, + 0x83, 0x21, 0xf6, 0xb8, 0x50, 0xf3, 0x0b, 0x7d, 0x10, 0xb0, 0x89, 0xe1, 0x18, 0x31, 0x89, 0xee, 0x38, 0xaf, 0x31, 0x80, 0x83, 0x89, 0x43, 0x66, - 0x2a, 0x46, 0x03, 0x79, 0x80, 0xd1, 0x4b, 0xff, 0x3c, 0xb9, 0xe6, 0x96, - 0xee, 0xb3, 0x44, 0xc6, 0xbe, 0x8d, 0x47, 0x01, 0xcb, 0x73, 0x44, 0x46, - 0xb0, 0x77, 0xa9, 0x97, 0xfc, 0x14, 0xe3, 0xcf, 0xef, 0xd4, 0x91, 0xcb, + 0x2a, 0x46, 0x03, 0x79, 0x80, 0xd1, 0x4b, 0xff, 0x3c, 0xbe, 0xe6, 0x96, + 0xee, 0xb3, 0x44, 0xc6, 0xbe, 0x8d, 0x47, 0x01, 0xcb, 0x7d, 0x44, 0x46, + 0xb0, 0x77, 0xa9, 0x97, 0xfc, 0x14, 0xe3, 0xf7, 0x9f, 0xd4, 0x91, 0xcb, 0xe8, 0x9e, 0x34, 0x72, 0xf7, 0xa2, 0x63, 0x97, 0xec, 0x89, 0x91, 0x87, 0x29, 0x0f, 0x9a, 0x62, 0x2d, 0x0e, 0xdf, 0xc1, 0x64, 0x67, 0xb6, 0x72, 0xff, 0x76, 0x35, 0x3a, 0x80, 0xfc, 0xe5, 0xf0, 0x27, 0x71, 0x39, 0x73, - 0xec, 0xe5, 0xf7, 0x2f, 0x67, 0x4e, 0x5a, 0x3a, 0x6e, 0xb6, 0x2d, 0x7a, + 0xec, 0xe5, 0xf7, 0xcf, 0x67, 0x4e, 0x5a, 0x3a, 0x6e, 0xb6, 0x2d, 0x7a, 0x06, 0x73, 0x97, 0xff, 0xff, 0xd2, 0xdf, 0x70, 0x0d, 0xef, 0xb8, 0xbc, - 0xdf, 0x2c, 0xfa, 0x5b, 0x41, 0x43, 0x97, 0x9d, 0xd6, 0x68, 0xac, 0x57, + 0xdf, 0xcc, 0xe6, 0x5b, 0x41, 0x43, 0x97, 0x9d, 0xd6, 0x68, 0xac, 0x57, 0xce, 0xa4, 0x2a, 0x72, 0x96, 0x79, 0x7a, 0x28, 0xbf, 0xf3, 0x4c, 0xf0, 0xe0, 0x20, 0x7c, 0x72, 0xff, 0x0e, 0x6f, 0xfc, 0xc0, 0x9c, 0xa5, 0x53, - 0x9f, 0x59, 0x37, 0xc3, 0x9a, 0x86, 0x5f, 0x88, 0xb8, 0x9f, 0x5f, 0xfc, + 0x9f, 0x59, 0x37, 0x23, 0x9a, 0x86, 0x5f, 0x88, 0xb8, 0x9f, 0x5f, 0xfc, 0xa8, 0x3d, 0xb1, 0xce, 0x23, 0x9b, 0x39, 0x7f, 0xf0, 0xf9, 0x50, 0x40, - 0xe2, 0xe3, 0x47, 0x2f, 0xf6, 0xa7, 0xf6, 0xdf, 0xe5, 0x9c, 0xa8, 0x3f, + 0xe2, 0xe3, 0x47, 0x2f, 0xf6, 0xa7, 0xf6, 0xdf, 0x95, 0x9c, 0xa8, 0x3f, 0x97, 0x43, 0xbf, 0xe9, 0x67, 0xb0, 0x61, 0xb6, 0x87, 0x2f, 0xdc, 0x1e, - 0xcf, 0xa6, 0x39, 0x7f, 0xff, 0xff, 0x9f, 0xde, 0xce, 0xed, 0xe4, 0x83, + 0xce, 0x66, 0x39, 0x7f, 0xff, 0xff, 0x9f, 0xde, 0xce, 0xed, 0xe4, 0x83, 0xe9, 0x66, 0xb3, 0x79, 0xd7, 0x9c, 0x62, 0x47, 0x2a, 0x11, 0x71, 0xb2, - 0xdb, 0xf8, 0x0d, 0x17, 0xd4, 0xe1, 0xce, 0x5f, 0xd9, 0xbf, 0xa5, 0x1d, + 0xdb, 0xf8, 0x0d, 0x17, 0xd4, 0xe1, 0xce, 0x5f, 0xd9, 0xbe, 0x65, 0x1d, 0x39, 0x74, 0x71, 0x39, 0x5d, 0x3c, 0x61, 0x2e, 0xbf, 0xd3, 0x3e, 0x24, - 0x94, 0x61, 0xca, 0x09, 0xea, 0xa1, 0x0d, 0xff, 0x47, 0xd2, 0x9a, 0x4f, + 0x94, 0x61, 0xca, 0x09, 0xea, 0xa1, 0x0d, 0xff, 0x47, 0x32, 0x9a, 0x4f, 0xa9, 0xce, 0x54, 0x26, 0x5b, 0x90, 0xd0, 0x42, 0x1b, 0xd1, 0x2f, 0x1c, - 0xbf, 0xf6, 0x07, 0x48, 0x09, 0xff, 0xdc, 0x8e, 0x5f, 0x31, 0xfe, 0xf1, - 0xcb, 0xff, 0xa7, 0x8f, 0x72, 0x51, 0x6a, 0x70, 0x29, 0xb3, 0x97, 0xfd, + 0xbf, 0xf6, 0x07, 0x48, 0x09, 0xff, 0xdc, 0x8e, 0x5f, 0x31, 0xf9, 0xf1, + 0xcb, 0xff, 0xa7, 0x8f, 0x7c, 0x51, 0x6a, 0x70, 0x29, 0xb3, 0x97, 0xfd, 0xa8, 0xdb, 0xe8, 0x62, 0x47, 0x2b, 0x48, 0x86, 0xe2, 0x9f, 0x7a, 0x4f, - 0x39, 0xcb, 0xdc, 0xa7, 0x61, 0xcb, 0x83, 0xe3, 0x95, 0xc3, 0x26, 0x45, - 0x90, 0xa9, 0xf8, 0x95, 0x07, 0x44, 0x82, 0xff, 0xc2, 0xe1, 0xec, 0x71, - 0xeb, 0x89, 0xcb, 0xff, 0xff, 0x02, 0x7c, 0x5f, 0x21, 0x07, 0x07, 0x2c, - 0xfa, 0x58, 0x01, 0xff, 0x67, 0x2f, 0xff, 0x4f, 0x9f, 0x7b, 0x68, 0x31, - 0xfb, 0xb0, 0xe5, 0xfe, 0xf8, 0x70, 0x3d, 0x76, 0xce, 0x56, 0x1f, 0xfb, + 0x39, 0xcb, 0xdf, 0x27, 0x61, 0xcb, 0x83, 0xe3, 0x95, 0xc3, 0x26, 0x45, + 0x90, 0xa9, 0xe4, 0x95, 0x07, 0x44, 0x82, 0xff, 0xc2, 0xe1, 0xec, 0x71, + 0xeb, 0x89, 0xcb, 0xff, 0xff, 0x02, 0x7c, 0x5f, 0xc1, 0x07, 0x07, 0xcc, + 0xe6, 0x58, 0x01, 0xff, 0x67, 0x2f, 0xff, 0x4f, 0x9c, 0xfb, 0x68, 0x31, + 0xfb, 0xb0, 0xe5, 0xfe, 0xe4, 0x70, 0x3d, 0x76, 0xce, 0x56, 0x1f, 0xfb, 0xa5, 0xd0, 0x53, 0x53, 0x13, 0xed, 0xc3, 0xd6, 0xfe, 0x9e, 0x69, 0x70, 0xda, 0x9c, 0xe5, 0xf0, 0x8e, 0x78, 0xe5, 0xf9, 0x1a, 0xf5, 0xa4, 0x39, 0x4d, 0x52, 0x20, 0x60, 0xdf, 0xa4, 0x17, 0xf4, 0xea, 0x34, 0x71, 0xfc, @@ -3754,20 +3754,20 @@ 0x1c, 0xac, 0x3e, 0x39, 0x89, 0x2f, 0xfe, 0xcc, 0x55, 0x90, 0x9a, 0xd2, 0x36, 0x72, 0xff, 0x92, 0x49, 0xd0, 0x31, 0x88, 0x72, 0xec, 0xf1, 0xca, 0x84, 0xd2, 0x72, 0x12, 0xba, 0x22, 0xf2, 0x23, 0x43, 0x8b, 0xc2, 0xfc, - 0x07, 0x2f, 0x75, 0x39, 0xc3, 0x30, 0x22, 0x72, 0xf9, 0x16, 0x84, 0xdf, - 0x23, 0xfb, 0x55, 0x85, 0x70, 0xbf, 0xf8, 0x83, 0x50, 0xf2, 0xec, 0x69, + 0x07, 0x2f, 0x75, 0x3e, 0xc3, 0x30, 0x22, 0x72, 0xf9, 0x16, 0x84, 0xdf, + 0x23, 0xfb, 0x55, 0x85, 0x70, 0xbf, 0xe4, 0x83, 0x50, 0xf2, 0xec, 0x69, 0xee, 0x66, 0x23, 0x9b, 0x8d, 0x8f, 0xd1, 0xd3, 0x34, 0x85, 0xb2, 0x91, 0xbe, 0xf0, 0x28, 0x5e, 0xe1, 0x66, 0x8d, 0x51, 0xcb, 0xa4, 0x27, 0x2f, 0xed, 0x6a, 0x03, 0x8c, 0x39, 0x7d, 0x3e, 0xa2, 0x73, 0x97, 0x29, 0xf9, 0xcb, 0xbf, 0xd9, 0xcb, 0xdd, 0x46, 0x1c, 0xb4, 0xc7, 0x29, 0x0f, 0x19, 0xc6, 0x00, 0x39, 0x7e, 0x71, 0x9c, 0x1b, 0x39, 0x7f, 0xd0, 0x1e, 0xe0, 0x74, 0xeb, 0x39, 0x48, 0x99, 0xeb, 0x96, 0xfe, 0x48, 0x2b, 0xfb, 0x2d, - 0xf1, 0x45, 0xba, 0x72, 0xf6, 0xd4, 0xd9, 0xcb, 0xef, 0xa7, 0x85, 0x4e, - 0x54, 0xe7, 0xa8, 0x11, 0x10, 0x0f, 0x5d, 0xe8, 0x39, 0x7f, 0xbe, 0xd4, + 0xf1, 0x45, 0xba, 0x72, 0xf6, 0xd4, 0xd9, 0xcb, 0xee, 0x67, 0x85, 0x4e, + 0x54, 0xe7, 0xa8, 0x11, 0x10, 0x0f, 0x5d, 0xe8, 0x39, 0x7f, 0xb9, 0xd4, 0x24, 0x9f, 0x67, 0x2f, 0xb0, 0x62, 0x47, 0x2b, 0x0f, 0x4d, 0x86, 0x76, 0x68, 0x72, 0xff, 0x67, 0xfb, 0xcf, 0x26, 0x8e, 0x5f, 0x03, 0xd9, 0xb3, - 0x97, 0x0b, 0x59, 0xcb, 0xda, 0x71, 0x39, 0x6f, 0x8e, 0x54, 0x1a, 0xd0, - 0x0d, 0xdf, 0xb3, 0x52, 0x86, 0x1c, 0xbf, 0xcf, 0xa9, 0x7e, 0x9f, 0x6c, + 0x97, 0x0b, 0x59, 0xcb, 0xda, 0x71, 0x39, 0x6e, 0x4e, 0x54, 0x1a, 0xd0, + 0x0d, 0xdf, 0xb3, 0x52, 0x86, 0x1c, 0xbf, 0xcf, 0xa9, 0x7e, 0x9c, 0xec, 0xe5, 0xf6, 0xf7, 0x1f, 0x9c, 0xa8, 0x4d, 0xb8, 0x24, 0x38, 0x26, 0x86, 0x6c, 0x22, 0xea, 0x33, 0x90, 0x00, 0x9d, 0xb3, 0x5b, 0xf9, 0x04, 0x73, 0x8b, 0x9c, 0xbd, 0x25, 0x3c, 0x72, 0xfa, 0x5f, 0x82, 0x47, 0x2f, 0xb4, @@ -3776,57 +3776,57 @@ 0x4b, 0xd8, 0xa1, 0xcb, 0xcb, 0x8f, 0xce, 0x5e, 0xd4, 0x30, 0xe5, 0x39, 0xee, 0x00, 0x8d, 0xb1, 0xdb, 0xe9, 0xd4, 0xc9, 0x8e, 0x5e, 0x8d, 0x4e, 0x72, 0xa0, 0xf0, 0x90, 0x96, 0xf4, 0x0c, 0x8e, 0x5f, 0x78, 0x53, 0x80, - 0xe5, 0x05, 0x53, 0x0f, 0xc5, 0x93, 0x33, 0x68, 0x81, 0x86, 0xbd, 0x16, + 0xe5, 0x05, 0x53, 0x0f, 0x25, 0x93, 0x33, 0x68, 0x81, 0x86, 0xbd, 0x16, 0x18, 0x4a, 0x6d, 0xc7, 0xc4, 0x00, 0x1b, 0xbf, 0xdd, 0x79, 0x70, 0x70, - 0x02, 0x73, 0x97, 0x75, 0xa1, 0xcb, 0xff, 0x46, 0x6f, 0x94, 0x20, 0x54, + 0x02, 0x73, 0x97, 0x75, 0xa1, 0xcb, 0xff, 0x46, 0x6f, 0xe4, 0x20, 0x54, 0x91, 0xcb, 0xf9, 0x1b, 0xdc, 0xf8, 0xd9, 0xca, 0x13, 0xf0, 0xf2, 0x05, 0xfa, 0x03, 0xec, 0x59, 0xcb, 0xd0, 0x2b, 0x39, 0x7f, 0xff, 0x3b, 0x61, 0x77, 0xd4, 0xfd, 0x7f, 0x75, 0x35, 0x23, 0x95, 0xd3, 0xf7, 0x11, 0xba, 0x92, 0x38, 0x36, 0x43, 0xe8, 0x4f, 0x5f, 0x38, 0xbc, 0xc7, 0x2f, 0xc9, 0xe1, 0xc9, 0x1c, 0xbe, 0x86, 0xe2, 0x63, 0x97, 0x28, 0xc3, 0x97, 0xf7, - 0x85, 0xff, 0xc1, 0x39, 0x7e, 0x17, 0xff, 0x04, 0xe5, 0x81, 0xc8, 0xf4, + 0x85, 0xff, 0xc1, 0x39, 0x7e, 0x17, 0xff, 0x04, 0xe5, 0x81, 0xf0, 0xf4, 0xbc, 0x59, 0x53, 0xa3, 0xf9, 0x52, 0x14, 0x26, 0xe9, 0x18, 0xb5, 0x5f, - 0xe8, 0x6c, 0x20, 0x7d, 0x48, 0xe5, 0xfc, 0x9a, 0xfb, 0x71, 0x23, 0x96, + 0xe8, 0x6c, 0x20, 0x7d, 0x48, 0xe5, 0xfc, 0x9a, 0xe7, 0x71, 0x23, 0x96, 0xe2, 0x72, 0xb4, 0x7e, 0xbd, 0x34, 0xe0, 0x2e, 0xbc, 0x28, 0xa9, 0xcb, 0xec, 0x0a, 0x71, 0x39, 0x74, 0x33, 0x0d, 0xfb, 0x8e, 0x5f, 0xf6, 0x36, - 0xff, 0x76, 0x14, 0x13, 0x96, 0xd9, 0xca, 0x43, 0xf5, 0xd1, 0x53, 0x9d, - 0x5b, 0xe3, 0x97, 0x7f, 0x05, 0x2e, 0x6d, 0xb2, 0x94, 0x86, 0xc1, 0xb1, - 0x7b, 0xfa, 0x43, 0x9e, 0xea, 0x14, 0xe6, 0x68, 0x68, 0x28, 0xa1, 0x76, - 0x3b, 0xdd, 0x86, 0xce, 0x5e, 0x7f, 0xb6, 0x72, 0xdb, 0x39, 0x7c, 0xa7, - 0x5f, 0xc7, 0x2a, 0x73, 0xee, 0x08, 0xef, 0xc3, 0xbe, 0x11, 0xbd, 0x03, + 0xfc, 0xf6, 0x14, 0x13, 0x96, 0xd9, 0xca, 0x43, 0xf5, 0xd1, 0x53, 0x9d, + 0x5b, 0x93, 0x97, 0x7f, 0x05, 0x2e, 0x6d, 0xb2, 0x94, 0x86, 0xc1, 0xb1, + 0x7b, 0xfa, 0x43, 0x9e, 0xea, 0x14, 0xfa, 0x68, 0x68, 0x28, 0xa1, 0x76, + 0x3b, 0xdd, 0x86, 0xce, 0x5e, 0x7e, 0x76, 0x72, 0xdb, 0x39, 0x7c, 0xa7, + 0x5f, 0xc7, 0x2a, 0x73, 0xee, 0x08, 0xef, 0x23, 0xbe, 0x11, 0xbd, 0x03, 0x31, 0xcb, 0x86, 0x0e, 0x5a, 0x63, 0x95, 0x31, 0xe1, 0xe8, 0x71, 0xc5, - 0x6f, 0xfe, 0x55, 0x05, 0x7b, 0x86, 0x3f, 0xde, 0x39, 0x7b, 0xfc, 0xe0, + 0x6f, 0xfe, 0x55, 0x05, 0x7b, 0x86, 0x3f, 0x3e, 0x39, 0x7b, 0xfc, 0xe0, 0x39, 0x4a, 0x9f, 0x2e, 0x91, 0x6f, 0x99, 0xb0, 0x30, 0xe5, 0x95, 0x39, 0x66, 0x87, 0x2e, 0xd2, 0xa7, 0x2a, 0x0f, 0x81, 0x08, 0xc0, 0x24, 0xa0, 0x9d, 0xff, 0xf7, 0x72, 0x5b, 0x8f, 0x4b, 0x1a, 0xdc, 0x7f, 0x39, 0x7f, - 0xc9, 0xee, 0xe7, 0xde, 0x04, 0x1c, 0xbe, 0x52, 0x35, 0xf9, 0xca, 0x91, + 0xc9, 0xee, 0xe7, 0x3e, 0x04, 0x1c, 0xbe, 0x52, 0x35, 0xf9, 0xca, 0x91, 0xee, 0xf4, 0xe6, 0xec, 0xd9, 0xca, 0x83, 0x71, 0x22, 0x2a, 0xda, 0x60, 0xfe, 0x87, 0x3d, 0xbf, 0x39, 0x7e, 0x48, 0x64, 0x30, 0xe5, 0xb0, 0xe5, 0x21, 0xf8, 0xb9, 0x4e, 0xc4, 0x9a, 0x13, 0x59, 0x53, 0x95, 0x0a, 0xe6, 0x72, 0x10, 0x29, 0x09, 0x4e, 0xc2, 0x0d, 0xe3, 0xb3, 0xe0, 0x3c, 0xbd, 0xb8, 0x98, 0xe5, 0xfd, 0x81, 0xce, 0x29, 0xa3, 0x94, 0x72, 0xcc, 0x39, - 0x5e, 0x2f, 0x38, 0x85, 0xdf, 0x05, 0xdf, 0xe3, 0x97, 0xef, 0xd3, 0x48, - 0xa9, 0xcb, 0x9d, 0x53, 0x97, 0x67, 0xc7, 0x2a, 0x64, 0xc0, 0x98, 0x3b, + 0x5e, 0x2f, 0x38, 0x85, 0xdf, 0x05, 0xdf, 0x93, 0x97, 0xef, 0xd3, 0x48, + 0xa9, 0xcb, 0x9d, 0x53, 0x97, 0x67, 0x27, 0x2a, 0x64, 0xc0, 0x98, 0x3b, 0xd4, 0xa7, 0x22, 0xfc, 0x88, 0x4a, 0x5a, 0x0b, 0xdd, 0x9a, 0x39, 0x77, 0xa0, 0xe5, 0xfa, 0x3b, 0x9c, 0x5c, 0xe5, 0x30, 0xf5, 0x1c, 0x5b, 0xf1, 0x6b, 0xf9, 0x3d, 0x9d, 0x75, 0x4e, 0x5f, 0xdd, 0x03, 0xcf, 0xd4, 0x39, - 0x79, 0xb6, 0xdb, 0x29, 0x7f, 0xc1, 0x89, 0xd4, 0xce, 0xbf, 0xc5, 0x39, + 0x79, 0xb6, 0xdb, 0x29, 0x7f, 0xc1, 0x89, 0xd4, 0xce, 0xbf, 0x25, 0x3e, 0x9a, 0x0b, 0xb2, 0x73, 0x97, 0xa5, 0x0c, 0x39, 0x41, 0x46, 0x72, 0xd3, 0x91, 0x36, 0x61, 0x7b, 0xd0, 0xc4, 0x39, 0x58, 0x7b, 0x0b, 0x3d, 0xbe, - 0x4d, 0x70, 0x04, 0xe5, 0xfb, 0xb1, 0xf3, 0xb5, 0x9c, 0xbf, 0xfe, 0x8f, - 0x6c, 0x39, 0xe4, 0xe8, 0x33, 0xef, 0x1c, 0xae, 0x9f, 0xdf, 0x8a, 0xed, + 0x4d, 0x70, 0x04, 0xe5, 0xfb, 0xb1, 0xcb, 0xb5, 0x9c, 0xbf, 0xfe, 0x8f, + 0x6c, 0x39, 0xe4, 0xe8, 0x33, 0x9f, 0x1c, 0xae, 0x9f, 0xdf, 0x8a, 0xed, 0xa3, 0x97, 0xfb, 0x31, 0x6a, 0x71, 0xee, 0x1c, 0xbf, 0xe8, 0x1f, 0x0e, - 0x7a, 0x1b, 0x39, 0x7f, 0xb1, 0xbd, 0xa0, 0xfd, 0x23, 0x94, 0x87, 0xd7, + 0x7a, 0x1b, 0x39, 0x7f, 0xb1, 0xbd, 0xa0, 0xf3, 0x23, 0x94, 0x87, 0xd7, 0xa3, 0x7b, 0xde, 0xd0, 0x0e, 0x5b, 0x67, 0x28, 0x4d, 0x70, 0x07, 0x6f, - 0xff, 0xd8, 0x18, 0xcf, 0x94, 0xf2, 0x08, 0x25, 0x9b, 0x39, 0x73, 0x3f, + 0xff, 0xd8, 0x18, 0xce, 0x54, 0xf2, 0x08, 0x25, 0x9b, 0x39, 0x73, 0x3f, 0x39, 0x73, 0x89, 0xca, 0xe9, 0xad, 0x71, 0x8b, 0xf3, 0x13, 0xdf, 0xb9, 0xca, 0x9d, 0x55, 0x66, 0x42, 0x81, 0xac, 0x8a, 0x61, 0x1d, 0x42, 0x81, 0xd3, 0xc4, 0x83, 0xd0, 0x82, 0x01, 0x05, 0xda, 0x54, 0xe5, 0xf7, 0x7c, 0x93, 0x9c, 0xbf, 0xcb, 0x4d, 0x8e, 0x71, 0x73, 0x97, 0xd1, 0x3b, 0xc8, 0xe5, 0xf7, 0xb7, 0xd4, 0x39, 0x7f, 0x0b, 0xfa, 0x7c, 0x6c, 0xe5, 0x1c, - 0xa1, 0x37, 0x3e, 0x2e, 0xa8, 0x3f, 0xbc, 0x5b, 0xbf, 0x64, 0xe3, 0x9f, - 0x1c, 0xbe, 0xf2, 0x0e, 0xce, 0x5f, 0x97, 0xcb, 0x3e, 0xf1, 0xca, 0xc3, - 0xcc, 0x42, 0x1a, 0x84, 0xef, 0xf0, 0x63, 0xe2, 0x3d, 0x19, 0xf6, 0x13, + 0xa1, 0x37, 0x3e, 0x2e, 0xa8, 0x3f, 0xbc, 0x5b, 0xbf, 0x64, 0xe3, 0x9c, + 0x9c, 0xbe, 0xf2, 0x0e, 0xce, 0x5f, 0x97, 0xf3, 0x39, 0xf1, 0xca, 0xc3, + 0xcc, 0x42, 0x1a, 0x84, 0xef, 0xf0, 0x63, 0x92, 0x3d, 0x19, 0xf6, 0x13, 0xa2, 0x41, 0xb7, 0x4b, 0xca, 0x01, 0x43, 0x97, 0x85, 0x1a, 0xce, 0x5f, 0x05, 0xa3, 0xaa, 0x72, 0xa0, 0xf0, 0xf0, 0x7a, 0xf7, 0x60, 0x27, 0x2e, 0xd6, 0xce, 0x51, 0xc4, 0x2d, 0xef, 0xf4, 0x0c, 0x9d, 0x98, 0x13, 0x97, @@ -3834,16 +3834,16 @@ 0xcb, 0xd2, 0x4e, 0x9c, 0xbe, 0xf0, 0xe4, 0x8e, 0x5f, 0x03, 0x87, 0xdb, 0x9c, 0xbf, 0x4e, 0x17, 0x76, 0xce, 0x56, 0x1e, 0x80, 0x09, 0xef, 0xff, 0x26, 0xfb, 0x81, 0x1c, 0xe2, 0x39, 0xb3, 0x95, 0x24, 0xe4, 0x55, 0x31, - 0xf8, 0x8e, 0x64, 0x6d, 0x0e, 0x0b, 0x8f, 0x88, 0x69, 0xaa, 0x6f, 0x42, + 0xe4, 0x8e, 0x64, 0x6d, 0x0e, 0x0b, 0x8f, 0x88, 0x69, 0xaa, 0x6f, 0x42, 0x78, 0x62, 0xb8, 0x8d, 0x4e, 0x78, 0x55, 0x48, 0xc0, 0x31, 0xeb, 0xe4, - 0xad, 0xd5, 0x61, 0x26, 0xb3, 0xbf, 0xa3, 0x69, 0x48, 0xcc, 0xe6, 0x85, + 0xad, 0xd5, 0x61, 0x26, 0xb3, 0xbe, 0x63, 0x69, 0x48, 0xcc, 0xe6, 0x85, 0xfe, 0xa1, 0xcc, 0xc8, 0x67, 0x76, 0x70, 0xa5, 0xe3, 0x6f, 0xfe, 0x17, 0x7c, 0x39, 0x78, 0xc6, 0xa7, 0xb9, 0x59, 0xbe, 0x94, 0xa0, 0x06, 0x8e, - 0x2c, 0x4d, 0x90, 0x34, 0x33, 0x52, 0x3a, 0xab, 0xfe, 0xe7, 0xe4, 0xce, - 0x0d, 0x82, 0x0e, 0x5f, 0xff, 0xf0, 0x23, 0x9f, 0xb6, 0x9d, 0x74, 0xf6, - 0x6b, 0xf6, 0x3c, 0x8e, 0x57, 0x35, 0x4f, 0xf3, 0xc7, 0xb4, 0x13, 0xdb, - 0xf6, 0x96, 0xee, 0xb3, 0x45, 0x6e, 0xbf, 0xf3, 0xcb, 0x9e, 0x69, 0x6e, - 0xeb, 0x34, 0x4e, 0x0b, 0x73, 0xc4, 0x40, 0x30, 0xd2, 0xee, 0x18, 0x27, + 0x2c, 0x4d, 0x90, 0x34, 0x33, 0x52, 0x3a, 0xab, 0xfe, 0xfb, 0xe4, 0xce, + 0x0d, 0x82, 0x0e, 0x5f, 0xff, 0xf0, 0x23, 0xef, 0xb6, 0x9d, 0x74, 0xf6, + 0x6b, 0xf6, 0x3c, 0x8e, 0x57, 0xd5, 0x4f, 0xf3, 0xc7, 0xb4, 0x13, 0xdb, + 0xf6, 0x96, 0xee, 0xb3, 0x45, 0x6e, 0xbf, 0xf3, 0xcb, 0xee, 0x69, 0x6e, + 0xeb, 0x34, 0x4e, 0x0b, 0x7d, 0xc4, 0x40, 0x30, 0xd2, 0xee, 0x18, 0x27, 0x2d, 0xd3, 0x96, 0xd9, 0xca, 0x01, 0xa2, 0x68, 0x23, 0x7e, 0xc6, 0xf6, 0x8d, 0x9c, 0xbe, 0x5b, 0xba, 0xcd, 0x16, 0x8a, 0xff, 0xf6, 0x07, 0xae, 0xac, 0xd3, 0x26, 0xc0, 0xc3, 0x95, 0xa3, 0xfb, 0xe9, 0x75, 0xf2, 0xdc, @@ -3851,17 +3851,17 @@ 0x40, 0x1c, 0x39, 0x7f, 0xf0, 0xe7, 0x1d, 0xe7, 0x70, 0x54, 0x09, 0xcb, 0xfd, 0x9a, 0xff, 0x26, 0x53, 0x67, 0x2c, 0xa9, 0xcb, 0xfe, 0xc8, 0x9f, 0x26, 0xd2, 0x6c, 0xe5, 0x21, 0xe5, 0xcc, 0x25, 0x7f, 0xfe, 0x9e, 0x3d, - 0x01, 0xd4, 0x75, 0xf6, 0x39, 0xf9, 0xcb, 0xff, 0x47, 0xce, 0xd7, 0xd1, + 0x01, 0xd4, 0x75, 0xf6, 0x39, 0xf9, 0xcb, 0xff, 0x47, 0x2e, 0xd7, 0xd1, 0x76, 0xb9, 0xce, 0x5f, 0xfa, 0x35, 0xfe, 0x26, 0x6b, 0xc0, 0x39, 0x50, 0x8d, 0x8e, 0xaa, 0xed, 0x16, 0xd8, 0x14, 0xfb, 0xd1, 0x16, 0x68, 0x40, 0xee, 0x1f, 0x57, 0x23, 0x67, 0x2e, 0x49, 0x1c, 0xbf, 0xdd, 0xe8, 0x15, 0x64, 0x6c, 0xe5, 0xff, 0xf9, 0x36, 0x39, 0xc5, 0xfc, 0x39, 0xbe, 0xbc, 0xc7, 0x2f, 0xd1, 0xed, 0xa9, 0xd3, 0x95, 0x08, 0xc9, 0xc1, 0x69, 0x8d, - 0x45, 0x56, 0xfb, 0x3f, 0x7e, 0x9c, 0xbb, 0xbb, 0x39, 0x6e, 0x7c, 0x22, + 0x45, 0x56, 0xfb, 0x3f, 0x7e, 0x9c, 0xbb, 0xbb, 0x39, 0x6f, 0xbc, 0x22, 0xea, 0x0b, 0x56, 0x7d, 0x39, 0x1e, 0x42, 0x91, 0x64, 0x53, 0x11, 0x30, 0xf7, 0xb2, 0x86, 0xb6, 0x9b, 0xe8, 0x70, 0x34, 0x3b, 0x50, 0x8a, 0xf6, - 0xd9, 0xb3, 0x97, 0xff, 0xfe, 0xec, 0x7e, 0xc7, 0x97, 0x2f, 0x77, 0x19, - 0x8b, 0x8e, 0xc3, 0x0e, 0x5f, 0xc9, 0x3f, 0x27, 0x1f, 0xce, 0x5f, 0x2d, + 0xd9, 0xb3, 0x97, 0xff, 0xfe, 0xec, 0x7e, 0xc7, 0x97, 0xcf, 0x77, 0x19, + 0x8b, 0x8e, 0xc3, 0x0e, 0x5f, 0xc9, 0x3f, 0xc7, 0x1f, 0xce, 0x5f, 0x2d, 0xdd, 0x66, 0x8b, 0x69, 0x7f, 0xff, 0x43, 0xfa, 0x3b, 0x1b, 0x44, 0x92, 0x6b, 0x02, 0x72, 0xfe, 0xec, 0x32, 0x10, 0x27, 0x29, 0x13, 0x4f, 0x99, 0xbb, 0x46, 0x1b, 0x2e, 0xf2, 0xbd, 0xff, 0xba, 0x81, 0x79, 0x07, 0xa8, @@ -3869,453 +3869,453 @@ 0x39, 0x66, 0xa4, 0xe5, 0xff, 0xd9, 0xe8, 0x60, 0xba, 0xa3, 0x9f, 0x9c, 0xb7, 0xe7, 0x2a, 0x63, 0xeb, 0x11, 0x6f, 0x21, 0xdf, 0xf8, 0x11, 0xff, 0x62, 0x71, 0xcd, 0x9c, 0xbf, 0xe8, 0x94, 0x6a, 0x78, 0xd4, 0xe7, 0x2f, - 0xff, 0xf4, 0x20, 0xbf, 0x81, 0xec, 0x0c, 0x30, 0x3d, 0x8f, 0x8e, 0x5f, + 0xff, 0xf4, 0x20, 0xbf, 0x81, 0xec, 0x0c, 0x30, 0x3d, 0x8e, 0x4e, 0x5f, 0xff, 0x0a, 0x71, 0x4f, 0x76, 0x3d, 0xb8, 0xe3, 0x07, 0x2b, 0x48, 0xb0, - 0x02, 0xfd, 0xce, 0x13, 0x97, 0xfd, 0x1a, 0xe5, 0xb8, 0xeb, 0xa1, 0xcb, + 0x02, 0xfd, 0xce, 0x13, 0x97, 0xfd, 0x1a, 0xf9, 0xb8, 0xeb, 0xa1, 0xcb, 0xfd, 0xd4, 0x79, 0x79, 0x27, 0x39, 0x7e, 0x0c, 0x60, 0xa1, 0xca, 0x6a, 0x57, 0x37, 0xb2, 0x36, 0xc5, 0xa5, 0xcc, 0x7d, 0xa3, 0xa6, 0x42, 0x37, 0xa5, 0xe2, 0x7f, 0xb8, 0x75, 0x78, 0x8d, 0xb1, 0x66, 0x87, 0x2a, 0x19, - 0xdf, 0xca, 0xbe, 0x82, 0x01, 0x39, 0x7f, 0xd1, 0xe4, 0x5a, 0x07, 0xe1, - 0x39, 0x78, 0x1f, 0x48, 0xe5, 0xfc, 0x2d, 0x13, 0x58, 0xa9, 0xcb, 0xf2, - 0x4e, 0xc8, 0x59, 0xcb, 0xf3, 0xfd, 0x25, 0x36, 0x72, 0xff, 0xc9, 0x36, - 0xf8, 0xb8, 0xce, 0x00, 0x9c, 0xb7, 0x35, 0x53, 0x47, 0xd1, 0x77, 0x4e, - 0x04, 0x7b, 0xc5, 0xfc, 0x4a, 0x14, 0x2a, 0xae, 0x6a, 0xa1, 0x3f, 0x94, + 0xdf, 0xca, 0xbe, 0x82, 0x01, 0x39, 0x7f, 0xd1, 0xe4, 0x5a, 0x07, 0x91, + 0x39, 0x78, 0x1c, 0xc8, 0xe5, 0xfc, 0x2d, 0x13, 0x58, 0xa9, 0xcb, 0xf2, + 0x4e, 0xc8, 0x59, 0xcb, 0xf3, 0xf3, 0x25, 0x36, 0x72, 0xff, 0xc9, 0x36, + 0xf8, 0xb8, 0xce, 0x00, 0x9c, 0xb7, 0xd5, 0x53, 0x47, 0xd1, 0x77, 0x4e, + 0x04, 0x7b, 0xc5, 0xfc, 0x4a, 0x14, 0x2a, 0xaf, 0xaa, 0xa1, 0x3f, 0x94, 0x29, 0x73, 0x3a, 0x72, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x72, 0xaf, 0xe7, - 0x0f, 0x60, 0x67, 0x39, 0x6e, 0x61, 0x3f, 0x8c, 0x17, 0xe9, 0xa5, 0xfb, + 0x0f, 0x60, 0x67, 0x39, 0x6f, 0xa1, 0x3f, 0x8c, 0x17, 0xe9, 0xa5, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0xed, 0x5e, 0x9f, 0x1b, 0x39, 0x7f, 0xc9, 0x29, - 0x20, 0xff, 0x12, 0x39, 0x7c, 0x9a, 0x7f, 0xce, 0x5b, 0x9e, 0x22, 0xb1, + 0x20, 0xff, 0x12, 0x39, 0x7c, 0x9a, 0x7f, 0xce, 0x5b, 0xee, 0x22, 0xb1, 0x86, 0x8e, 0x3d, 0xb3, 0x8a, 0x87, 0xc9, 0x14, 0x9c, 0xaa, 0x54, 0x98, 0xb0, 0xc7, 0x3f, 0x86, 0xea, 0xd3, 0x2b, 0xd2, 0xd0, 0x5b, 0xb5, 0xc2, 0xef, 0xb3, 0xad, 0x63, 0x48, 0x31, 0xdc, 0x29, 0xfd, 0x0e, 0x2b, 0xfd, - 0xcf, 0x34, 0xb7, 0x75, 0x9a, 0x2a, 0x75, 0xf8, 0x79, 0xeb, 0x7b, 0x39, - 0x74, 0xec, 0x39, 0x7e, 0xf9, 0x8e, 0xe2, 0x72, 0x82, 0x6f, 0xc0, 0x31, - 0x6f, 0x1c, 0xbf, 0xe8, 0x79, 0xf9, 0x7d, 0xb8, 0x09, 0xca, 0x43, 0xcd, - 0x11, 0x1b, 0xe5, 0xbb, 0xac, 0xd1, 0x5c, 0xaf, 0xf7, 0x3c, 0xd2, 0xdd, - 0xd6, 0x68, 0xb3, 0x97, 0x3c, 0x8e, 0x5f, 0xd2, 0xf7, 0xcb, 0x4d, 0x9c, + 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x2a, 0x75, 0xf8, 0x7e, 0xeb, 0x7b, 0x39, + 0x74, 0xec, 0x39, 0x7e, 0xe5, 0x8e, 0xe2, 0x72, 0x82, 0x6f, 0xc0, 0x31, + 0x6f, 0x1c, 0xbf, 0xe8, 0x79, 0xfe, 0x73, 0xb8, 0x09, 0xca, 0x43, 0xcd, + 0x11, 0x1b, 0xe5, 0xbb, 0xac, 0xd1, 0x5c, 0xaf, 0xf7, 0xdc, 0xd2, 0xdd, + 0xd6, 0x68, 0xb3, 0x97, 0x3c, 0x8e, 0x5f, 0xd2, 0xf7, 0x2b, 0x4d, 0x9c, 0xa7, 0x3c, 0x50, 0x0b, 0x5f, 0xc9, 0xbc, 0x17, 0x6c, 0xe5, 0x69, 0x30, - 0x1e, 0x97, 0x0c, 0x21, 0xbc, 0x43, 0x7f, 0xfb, 0xd1, 0xbe, 0x40, 0xdf, + 0x1e, 0x97, 0x0c, 0x21, 0xbc, 0x43, 0x7f, 0xfb, 0xd1, 0xbf, 0x80, 0xdf, 0xa2, 0x69, 0x90, 0xe5, 0xfc, 0x8c, 0x9c, 0x1a, 0x91, 0xcb, 0xf3, 0x32, 0x67, 0xfc, 0xe5, 0xf4, 0xfd, 0x7f, 0x1c, 0xa7, 0x3c, 0xc0, 0x14, 0xdf, - 0xe8, 0xef, 0x26, 0x35, 0x7c, 0x27, 0x8e, 0x56, 0x26, 0x55, 0xd4, 0xe1, + 0xe8, 0xef, 0xc6, 0x35, 0x7c, 0x27, 0x8e, 0x56, 0x26, 0x55, 0xd4, 0xe1, 0x7b, 0xe2, 0x43, 0x7f, 0xc3, 0x0c, 0xd8, 0x24, 0xea, 0x9c, 0xbf, 0x6b, 0x3c, 0x8c, 0x39, 0x7c, 0xe3, 0x01, 0x39, 0x7e, 0x9a, 0x19, 0x0a, 0x1c, - 0xba, 0x4c, 0x39, 0x58, 0x78, 0x02, 0x53, 0x7f, 0xfb, 0xa9, 0xcb, 0xae, + 0xba, 0x4c, 0x39, 0x58, 0x78, 0x02, 0x53, 0x7f, 0xfb, 0xa9, 0xf3, 0xae, 0x9e, 0x8c, 0x0a, 0x1c, 0xbf, 0x69, 0x6e, 0xeb, 0x34, 0x48, 0x4b, 0xff, - 0xfb, 0x69, 0xa5, 0xf7, 0x39, 0x6b, 0x58, 0xdb, 0x48, 0x61, 0xcb, 0xff, - 0x63, 0x31, 0xf5, 0x3f, 0x2f, 0x98, 0x72, 0xff, 0x7d, 0xbf, 0x0c, 0x33, - 0x67, 0x2f, 0xff, 0x38, 0xaf, 0x90, 0x45, 0xe5, 0xd7, 0x91, 0xca, 0x43, - 0xfe, 0x01, 0xa5, 0xfd, 0x82, 0x9f, 0xee, 0x0e, 0x5b, 0x9c, 0x93, 0xea, - 0xc4, 0x9f, 0x8d, 0x3a, 0xc1, 0xfc, 0x30, 0x36, 0x43, 0x72, 0x74, 0xe5, - 0xff, 0x9d, 0x49, 0x85, 0x3c, 0x31, 0xf9, 0xca, 0x92, 0x2e, 0xfe, 0x66, - 0xf0, 0xb5, 0xff, 0xdd, 0x46, 0x66, 0xf9, 0x7d, 0x2c, 0xf1, 0xcb, 0xe9, + 0xfb, 0x69, 0xa5, 0xf7, 0x3e, 0x6b, 0x58, 0xdb, 0x48, 0x61, 0xcb, 0xff, + 0x63, 0x31, 0xf5, 0x3f, 0xce, 0x58, 0x72, 0xff, 0x73, 0xbf, 0x0c, 0x33, + 0x67, 0x2f, 0xff, 0x38, 0xaf, 0xe0, 0x45, 0xe5, 0xd7, 0x91, 0xca, 0x43, + 0xfe, 0x01, 0xa5, 0xfd, 0x82, 0x9f, 0xee, 0x0e, 0x5b, 0xec, 0x93, 0xea, + 0xc4, 0x9e, 0x4d, 0x3a, 0xc1, 0xfc, 0x30, 0x36, 0x43, 0x72, 0x74, 0xe5, + 0xff, 0x9d, 0x49, 0x85, 0x3c, 0x31, 0xf9, 0xca, 0x92, 0x2e, 0xf9, 0x66, + 0xf0, 0xb5, 0xff, 0xdd, 0x46, 0x66, 0xfe, 0x73, 0x2c, 0xf1, 0xcb, 0xe9, 0x75, 0x4d, 0x9c, 0xa8, 0x3e, 0xbc, 0x47, 0xbe, 0x6a, 0xfb, 0x0c, 0x39, 0x7f, 0x77, 0x7b, 0xcd, 0x4e, 0x72, 0xe8, 0x6c, 0xe5, 0xff, 0x7f, 0x81, 0x17, 0xfe, 0x38, 0x9c, 0xac, 0x44, 0x0a, 0x17, 0xb8, 0xbd, 0xe6, 0x71, - 0x91, 0xcb, 0xff, 0xdd, 0x8f, 0xd8, 0xf2, 0xdf, 0xb3, 0x18, 0x72, 0xdc, - 0xe7, 0x64, 0x5c, 0x05, 0xbb, 0x23, 0x21, 0x48, 0xdb, 0x26, 0x3e, 0xd1, + 0x91, 0xcb, 0xff, 0xdd, 0x8f, 0xd8, 0xf2, 0xdf, 0xb3, 0x18, 0x72, 0xdf, + 0x67, 0x64, 0x5c, 0x05, 0xbb, 0x23, 0x21, 0x48, 0xdb, 0x26, 0x3e, 0xd1, 0xcb, 0x09, 0xfa, 0xc0, 0xf2, 0xb1, 0x46, 0x13, 0x9b, 0x20, 0xf4, 0x2a, - 0x00, 0x5a, 0xa0, 0xfd, 0xff, 0xec, 0xfb, 0x98, 0x40, 0xfa, 0x97, 0x5b, - 0x73, 0x97, 0xff, 0x73, 0xeb, 0xec, 0x73, 0xde, 0x8f, 0xce, 0x5f, 0xfe, - 0xe6, 0xc7, 0x97, 0x3c, 0xd2, 0xdd, 0xd6, 0x68, 0x9f, 0x14, 0xb6, 0x59, + 0x00, 0x5a, 0xa0, 0xfd, 0xff, 0xec, 0xe7, 0xe8, 0x40, 0xfa, 0x97, 0x5b, + 0x73, 0x97, 0xff, 0x7d, 0xeb, 0xec, 0x73, 0xde, 0x8f, 0xce, 0x5f, 0xfe, + 0xfa, 0xc7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x9f, 0x14, 0xb6, 0x59, 0xba, 0x20, 0xb5, 0xd2, 0x48, 0x75, 0x0e, 0x76, 0x27, 0x75, 0x1a, 0xff, - 0xfe, 0x00, 0xba, 0xbc, 0xbc, 0xac, 0x0c, 0xb3, 0xa8, 0xc3, 0x97, 0x27, - 0xc7, 0x2f, 0xff, 0xa5, 0x3f, 0x0a, 0x86, 0xae, 0x75, 0xeb, 0x97, 0x2e, + 0xfe, 0x00, 0xba, 0xbf, 0x3c, 0xac, 0x0c, 0xb3, 0xa8, 0xc3, 0x97, 0x27, + 0x27, 0x2f, 0xff, 0xa5, 0x3f, 0x0a, 0x86, 0xae, 0x75, 0xeb, 0xe7, 0xce, 0xb4, 0x39, 0x52, 0x3f, 0xcf, 0xc5, 0xef, 0xff, 0x0c, 0xfd, 0x84, 0xf6, - 0xd0, 0x7e, 0x91, 0xcb, 0xff, 0x79, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2f, - 0xf9, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2f, 0x80, 0x2e, 0xaf, 0x23, 0xf6, + 0xd0, 0x79, 0x91, 0xcb, 0xff, 0x79, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2f, + 0xf9, 0x58, 0x19, 0x67, 0x51, 0x87, 0x2f, 0x80, 0x2e, 0xaf, 0xc3, 0xf6, 0xf1, 0xf5, 0xfb, 0x5f, 0xa7, 0x60, 0xe5, 0x30, 0xf8, 0xc0, 0x77, 0x7e, - 0xcd, 0x66, 0x4c, 0x72, 0xdc, 0xd8, 0xa9, 0xa3, 0xb0, 0xd9, 0x72, 0x3d, + 0xcd, 0x66, 0x4c, 0x72, 0xdf, 0x58, 0xa9, 0xa3, 0xb0, 0xd9, 0x72, 0x3d, 0xc6, 0x46, 0xa1, 0x15, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0xb2, 0x5f, 0xf9, - 0xe5, 0xcf, 0x34, 0xb7, 0x75, 0x9a, 0x26, 0xe5, 0xb9, 0xe2, 0x20, 0x18, + 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x26, 0xe5, 0xbe, 0xe2, 0x20, 0x18, 0x69, 0x4b, 0x4c, 0x25, 0x21, 0xbf, 0x7c, 0xb7, 0x75, 0x9a, 0x25, 0x65, 0xff, 0xf6, 0xa7, 0x18, 0xd3, 0x84, 0x5f, 0x51, 0xc4, 0xe5, 0x68, 0xff, 0x80, 0x5d, 0x7e, 0x18, 0x0b, 0xf4, 0xe5, 0xfe, 0x84, 0x18, 0x94, 0x70, - 0x1c, 0xbf, 0x73, 0x63, 0xcb, 0x9e, 0x1f, 0xda, 0x11, 0x6c, 0x9a, 0xff, - 0xde, 0xce, 0x79, 0xa4, 0x9d, 0xd8, 0x72, 0xff, 0xf3, 0x52, 0xd5, 0x70, + 0x1c, 0xbf, 0x7d, 0x63, 0xcb, 0xee, 0x1f, 0xda, 0x11, 0x6c, 0x9a, 0xff, + 0xde, 0xcf, 0xb9, 0xa4, 0x9d, 0xd8, 0x72, 0xff, 0xf3, 0x52, 0xd5, 0x70, 0x9b, 0xc7, 0x92, 0x66, 0xb0, 0xe5, 0xff, 0x93, 0x60, 0x60, 0xa7, 0x10, 0x39, 0xcb, 0xfa, 0x05, 0xd6, 0xed, 0x67, 0x2a, 0x47, 0xda, 0xc3, 0xfb, 0x83, 0xa3, 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x89, 0x71, 0x7f, 0xc8, 0xf2, 0xf0, 0xc3, 0x36, 0x72, 0xfd, 0x26, 0x89, 0xd7, 0x39, 0x7a, 0x1a, 0x41, - 0xcb, 0xff, 0xfb, 0x00, 0xbe, 0xc0, 0xc4, 0x9c, 0x31, 0xf6, 0x90, 0xe5, + 0xcb, 0xff, 0xfb, 0x00, 0xbe, 0xc0, 0xc4, 0x9c, 0x31, 0xce, 0x90, 0xe5, 0xe4, 0x18, 0x39, 0x52, 0x45, 0xc8, 0x4a, 0x5a, 0xc7, 0x78, 0xac, 0xdf, 0xfc, 0x09, 0x0a, 0x4a, 0x3c, 0x20, 0x91, 0xcb, 0xf4, 0x6f, 0xf6, 0x78, 0xe5, 0xcf, 0xe4, 0x3e, 0xce, 0xa1, 0xdf, 0xd2, 0xee, 0x0e, 0x2c, 0xe5, 0xe9, 0x77, 0xc7, 0x2e, 0xec, 0x21, 0xe4, 0xf4, 0xb2, 0xff, 0xe1, 0x4f, 0xf7, 0xa8, 0x49, 0x3e, 0xce, 0x56, 0x1f, 0x7a, 0x16, 0x5f, 0xda, 0x46, - 0x0b, 0xc8, 0xe5, 0xff, 0xbe, 0x96, 0x7b, 0x34, 0xb8, 0xc3, 0x97, 0x9e, - 0x5c, 0xda, 0x8a, 0xe1, 0xec, 0x43, 0x12, 0x44, 0x58, 0x2f, 0xd3, 0x47, + 0x0b, 0xc8, 0xe5, 0xff, 0xb9, 0x96, 0x7b, 0x34, 0xb8, 0xc3, 0x97, 0x9e, + 0x5f, 0x5a, 0x8a, 0xe1, 0xec, 0x43, 0x12, 0x44, 0x58, 0x2f, 0xd3, 0x47, 0x87, 0x86, 0xe1, 0x5d, 0xe8, 0x72, 0x00, 0x83, 0x80, 0xb2, 0xff, 0xc0, - 0x67, 0x3d, 0xc0, 0xfb, 0x34, 0x72, 0xff, 0x83, 0x9c, 0xe3, 0x49, 0xd0, - 0x1c, 0xb7, 0x34, 0x5d, 0xb2, 0x64, 0xe3, 0xee, 0xe1, 0x76, 0x04, 0x0b, - 0xff, 0xb9, 0xbc, 0xb9, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0x76, 0xbf, 0xef, - 0x77, 0x25, 0xcd, 0xc7, 0x67, 0x2f, 0xee, 0x18, 0x61, 0x78, 0x27, 0x2e, + 0x67, 0xdd, 0xc0, 0xfb, 0x34, 0x72, 0xff, 0x83, 0x9f, 0x63, 0x49, 0xd0, + 0x1c, 0xb7, 0xd4, 0x5d, 0xb2, 0x64, 0xe3, 0xee, 0xe1, 0x76, 0x04, 0x0b, + 0xff, 0xbe, 0xbc, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0x76, 0xbf, 0xef, + 0x77, 0x25, 0xf5, 0xc7, 0x67, 0x2f, 0xee, 0x18, 0x61, 0x78, 0x27, 0x2e, 0x07, 0x4e, 0x5f, 0xdc, 0x20, 0xe7, 0x5f, 0xc7, 0x2f, 0xff, 0xef, 0x49, - 0x03, 0xd4, 0xe3, 0xcb, 0x03, 0xa4, 0x02, 0xce, 0x5f, 0xec, 0x6f, 0x70, - 0x3e, 0xd9, 0xcb, 0xfb, 0xf1, 0xcf, 0xbd, 0x87, 0x2f, 0xce, 0xaf, 0x73, + 0x03, 0xd4, 0xe3, 0xf3, 0x03, 0xa4, 0x02, 0xce, 0x5f, 0xec, 0x6f, 0x70, + 0x3e, 0xd9, 0xcb, 0xfb, 0xf1, 0xce, 0x7d, 0x87, 0x2f, 0xce, 0xaf, 0x73, 0xf3, 0x97, 0xf0, 0xfe, 0xfa, 0x75, 0x0e, 0x54, 0x22, 0x17, 0x45, 0xce, - 0x53, 0x7f, 0xff, 0xfe, 0xec, 0x77, 0xae, 0x11, 0x7e, 0x5b, 0xec, 0x6f, - 0x90, 0x1f, 0x94, 0xb3, 0x8c, 0x1c, 0xbf, 0xf2, 0x6b, 0x96, 0xc7, 0x19, + 0x53, 0x7f, 0xff, 0xfe, 0xec, 0x77, 0xae, 0x11, 0x7f, 0x9b, 0xec, 0x6f, + 0xe0, 0x1f, 0xe4, 0xb3, 0x8c, 0x1c, 0xbf, 0xf2, 0x6b, 0xe6, 0xc7, 0x19, 0x0b, 0x39, 0x7f, 0x81, 0xe4, 0x7e, 0x2f, 0x23, 0x97, 0xf3, 0xf1, 0x0e, - 0x0a, 0xa7, 0x2d, 0x02, 0x7c, 0x6a, 0x1a, 0x5f, 0xf8, 0x41, 0x2e, 0x58, + 0x0a, 0xa7, 0x2d, 0x02, 0x7c, 0x6a, 0x1a, 0x5f, 0xf8, 0x41, 0x2f, 0x98, 0x83, 0x0c, 0x39, 0x7c, 0xb7, 0x75, 0x9a, 0x2a, 0x15, 0xff, 0x67, 0x70, 0x5f, 0x5a, 0x43, 0x95, 0x24, 0xfd, 0x15, 0x84, 0x4a, 0xe1, 0x44, 0x84, 0xfa, 0x3e, 0xd9, 0x75, 0xe6, 0xb7, 0x83, 0x97, 0x4b, 0x0e, 0x5f, 0xf4, 0xbc, 0x9a, 0x75, 0xa0, 0x9c, 0xbd, 0xfe, 0xf0, 0xe5, 0xfe, 0xd8, 0x26, - 0x70, 0xbc, 0xc7, 0x2a, 0x47, 0xa5, 0xf0, 0xed, 0xfa, 0x43, 0x0c, 0x54, - 0xe5, 0xff, 0xcc, 0xcd, 0x0e, 0x27, 0x14, 0xd3, 0x9c, 0xaf, 0x8f, 0xad, + 0x70, 0xbc, 0xc7, 0x2a, 0x47, 0xa5, 0xc8, 0xed, 0xfa, 0x43, 0x0c, 0x54, + 0xe5, 0xff, 0xcc, 0xcd, 0x0e, 0x27, 0x14, 0xd3, 0x9c, 0xae, 0x4f, 0xad, 0xca, 0x2f, 0xfc, 0x39, 0x37, 0xbb, 0x9a, 0x4d, 0x9c, 0xbf, 0xf9, 0xd9, - 0xc9, 0x8f, 0xee, 0x5d, 0xf6, 0x8e, 0x57, 0x51, 0x0e, 0x27, 0xd7, 0xef, - 0x85, 0x18, 0x87, 0x2f, 0xd1, 0xc3, 0x4f, 0x8d, 0x9c, 0xa8, 0x4c, 0x83, - 0x21, 0x52, 0x84, 0x5a, 0x27, 0xbf, 0xd1, 0xe7, 0xef, 0x20, 0xc1, 0xcb, + 0xf1, 0x8f, 0xef, 0x9d, 0xf6, 0x8e, 0x57, 0x51, 0x0e, 0x27, 0xd7, 0xee, + 0x45, 0x18, 0x87, 0x2f, 0xd1, 0xc3, 0x4f, 0x8d, 0x9c, 0xa8, 0x4c, 0x83, + 0x21, 0x52, 0x84, 0x5a, 0x27, 0xbf, 0xd1, 0xe7, 0xef, 0xc0, 0xc1, 0xcb, 0xfd, 0xed, 0xa0, 0xaf, 0xb0, 0x72, 0xff, 0xd9, 0xed, 0xeb, 0x26, 0xea, - 0x2a, 0x72, 0xff, 0xc3, 0x8a, 0xe3, 0x11, 0xa4, 0x30, 0xe5, 0xff, 0x72, - 0x71, 0xce, 0x0e, 0x5d, 0x01, 0xca, 0x84, 0x78, 0x21, 0x93, 0xa0, 0x00, + 0x2a, 0x72, 0xff, 0xc3, 0x8a, 0xe3, 0x11, 0xa4, 0x30, 0xe5, 0xff, 0x7c, + 0x71, 0xce, 0x0f, 0x9d, 0x01, 0xca, 0x84, 0x78, 0x21, 0x93, 0xa0, 0x00, 0xfe, 0xff, 0x4a, 0x35, 0x3c, 0x6a, 0x73, 0x97, 0xfe, 0xde, 0x0f, 0xb7, - 0x92, 0x4e, 0x9c, 0xbf, 0xb7, 0x9c, 0x46, 0x3e, 0x39, 0x5b, 0x3e, 0xcf, - 0x1e, 0xdf, 0xff, 0x47, 0xf8, 0x3c, 0x9f, 0xdc, 0xbb, 0x9f, 0xb9, 0xcb, + 0x92, 0x4e, 0x9c, 0xbf, 0xb7, 0x9c, 0x46, 0x39, 0x39, 0x5b, 0x3e, 0xcf, + 0x1e, 0xdf, 0xff, 0x47, 0xf8, 0x3f, 0x1f, 0xdf, 0x3b, 0x9f, 0xb9, 0xcb, 0x86, 0x73, 0x95, 0x09, 0x96, 0xe4, 0x28, 0x50, 0x88, 0x54, 0xef, 0xee, - 0x2e, 0xce, 0xb6, 0xe7, 0x2f, 0xff, 0xf2, 0x47, 0x9f, 0xbc, 0xf7, 0xdc, - 0x1f, 0x72, 0xfe, 0x5b, 0x39, 0x48, 0x89, 0x51, 0x30, 0xbd, 0xb0, 0x68, + 0x2e, 0xce, 0xb6, 0xe7, 0x2f, 0xff, 0xf2, 0x47, 0x9f, 0xbf, 0x77, 0xdc, + 0x1f, 0x7c, 0xfe, 0x5b, 0x39, 0x48, 0x89, 0x51, 0x30, 0xbd, 0xb0, 0x68, 0xe5, 0xfd, 0xa7, 0x1f, 0xff, 0x83, 0x95, 0x87, 0xd8, 0x84, 0x2a, 0x0e, 0xde, 0xf6, 0x4e, 0x72, 0xfd, 0x8b, 0x03, 0xce, 0x72, 0xba, 0x78, 0xa2, 0x3b, 0x7f, 0xff, 0xb1, 0x6f, 0xdc, 0x94, 0x6a, 0x3f, 0xd4, 0x28, 0xe2, - 0x72, 0xfd, 0x93, 0xb8, 0xf1, 0x39, 0x7f, 0xff, 0xff, 0xa2, 0x5c, 0xbd, - 0xd4, 0x8d, 0xf2, 0xc0, 0x2e, 0x38, 0xf2, 0xcd, 0x6b, 0x38, 0x81, 0xfa, + 0x72, 0xfd, 0x93, 0xb8, 0xf1, 0x39, 0x7f, 0xff, 0xff, 0xa2, 0x5f, 0x3d, + 0xd4, 0x8d, 0xfc, 0xc0, 0x2e, 0x38, 0xfc, 0xcd, 0x6b, 0x38, 0x81, 0xfa, 0x72, 0xfb, 0xa2, 0xfc, 0x07, 0x2b, 0x13, 0x64, 0xe9, 0x08, 0xaf, 0xec, 0xa7, 0xd0, 0x97, 0xbf, 0xff, 0xe0, 0x3b, 0x5a, 0x4f, 0xd7, 0x4f, 0x47, 0x53, 0xdb, 0xc0, 0x9c, 0xbf, 0xfc, 0x39, 0xc5, 0xe5, 0x82, 0x11, 0x89, - 0x1c, 0xb7, 0x3e, 0x11, 0x9a, 0xbc, 0xd5, 0x98, 0x70, 0xc2, 0xf0, 0x63, - 0x3a, 0xf8, 0x61, 0x71, 0x92, 0x88, 0x95, 0x62, 0x58, 0xf7, 0xc2, 0xc9, + 0x1c, 0xb7, 0xde, 0x11, 0x9a, 0xbc, 0xd5, 0x98, 0x70, 0xc2, 0xf0, 0x63, + 0x3a, 0xf8, 0x61, 0x71, 0x92, 0x88, 0x95, 0x62, 0x58, 0xf7, 0x22, 0xc9, 0x08, 0x9d, 0x47, 0x5c, 0xc4, 0x0e, 0xc6, 0x48, 0x31, 0xb3, 0xee, 0x34, 0x0f, 0x47, 0xae, 0xd1, 0x39, 0x46, 0x8b, 0xe5, 0xbb, 0xac, 0xd1, 0x54, - 0x2f, 0xf6, 0xa3, 0x8f, 0xd2, 0xcf, 0x1c, 0xad, 0x1f, 0x20, 0x0b, 0xaf, - 0xfc, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x13, 0x5a, 0xfa, 0x35, 0x1e, - 0x39, 0x73, 0xf8, 0xe5, 0x04, 0xdb, 0xb0, 0x86, 0xdc, 0xf1, 0x18, 0xcc, + 0x2f, 0xf6, 0xa3, 0x8f, 0x32, 0xcf, 0x1c, 0xad, 0x1f, 0x20, 0x0b, 0xaf, + 0xfc, 0xf2, 0xfb, 0x9a, 0x5b, 0xba, 0xcd, 0x13, 0x5a, 0xfa, 0x35, 0x1e, + 0x39, 0x73, 0xf8, 0xe5, 0x04, 0xdb, 0xb0, 0x86, 0xdf, 0x71, 0x18, 0xcc, 0x22, 0x78, 0x41, 0xdf, 0xb4, 0xb7, 0x75, 0x9a, 0x2a, 0xc5, 0xff, 0x44, - 0xa3, 0x53, 0xc6, 0xa7, 0x39, 0x6e, 0x78, 0x7d, 0xc2, 0x69, 0x7f, 0xdd, - 0x8f, 0xbd, 0x1d, 0x76, 0xb3, 0x97, 0xff, 0x7f, 0x83, 0xce, 0x5f, 0xee, - 0x77, 0x13, 0x95, 0xcd, 0x10, 0x90, 0x79, 0x7e, 0xdc, 0x4d, 0x1f, 0x1c, - 0xbf, 0xe9, 0x73, 0xcd, 0x2d, 0xdd, 0x66, 0x89, 0x11, 0x7f, 0x4f, 0x1a, - 0xeb, 0xa1, 0xcb, 0x73, 0xc4, 0x4e, 0xb9, 0x4e, 0xd1, 0xef, 0xda, 0x5b, - 0xba, 0xcd, 0x16, 0x92, 0xff, 0xcf, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, - 0x3e, 0xad, 0xcf, 0x11, 0x00, 0xc3, 0x4b, 0xff, 0xdc, 0xd8, 0xf2, 0xe7, - 0x9a, 0x5b, 0xba, 0xcd, 0x14, 0x22, 0xff, 0xec, 0x6f, 0x9f, 0x95, 0x7d, + 0xa3, 0x53, 0xc6, 0xa7, 0x39, 0x6f, 0xb8, 0x7d, 0xc2, 0x69, 0x7f, 0xdd, + 0x8e, 0x7d, 0x1d, 0x76, 0xb3, 0x97, 0xff, 0x7f, 0x83, 0xf6, 0x5f, 0xee, + 0x77, 0x13, 0x95, 0xf5, 0x10, 0x90, 0x79, 0x7e, 0xdc, 0x4d, 0x1c, 0x9c, + 0xbf, 0xe9, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x89, 0x11, 0x7f, 0x4f, 0x1a, + 0xeb, 0xa1, 0xcb, 0x7d, 0xc4, 0x4e, 0xb9, 0x4e, 0xd1, 0xef, 0xda, 0x5b, + 0xba, 0xcd, 0x16, 0x92, 0xff, 0xcf, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, + 0x3e, 0xad, 0xf7, 0x11, 0x00, 0xc3, 0x4b, 0xff, 0xdf, 0x58, 0xf2, 0xfb, + 0x9a, 0x5b, 0xba, 0xcd, 0x14, 0x22, 0xff, 0xec, 0x6f, 0xef, 0x95, 0x7d, 0xa7, 0xa0, 0xe5, 0xfb, 0xc0, 0x5b, 0xec, 0xe5, 0xf2, 0x4f, 0x1a, 0x39, 0x4c, 0x3c, 0xae, 0x94, 0x5f, 0xb4, 0xb7, 0x75, 0x9a, 0x28, 0xf5, 0xff, 0x44, 0xa3, 0x53, 0xc6, 0xa7, 0x39, 0x7f, 0xff, 0xff, 0x94, 0x4d, 0x4d, 0x1d, 0xd6, 0x75, 0xd4, 0xde, 0x2a, 0xe3, 0xfc, 0x0c, 0x4d, 0xd8, 0x39, 0x7e, 0x7d, 0xa7, 0xa0, 0xe5, 0xff, 0x44, 0xd0, 0x31, 0x37, 0x60, 0xe5, - 0x42, 0x3b, 0x95, 0x84, 0x80, 0x93, 0x5f, 0xff, 0xd8, 0x1e, 0xc2, 0x9c, - 0xfc, 0x2f, 0xfe, 0xf7, 0x1f, 0x94, 0xbc, 0xf2, 0xe7, 0x0a, 0x84, 0x70, - 0x88, 0x4d, 0x3d, 0x19, 0x43, 0x43, 0x4b, 0xff, 0xb3, 0xbc, 0xfc, 0xab, - 0xed, 0x3d, 0x07, 0x2d, 0xce, 0x75, 0x69, 0x8c, 0x95, 0x45, 0xe6, 0x4a, + 0x42, 0x3b, 0x95, 0x84, 0x80, 0x93, 0x5f, 0xff, 0xd8, 0x1e, 0xc2, 0x9f, + 0x7c, 0x2f, 0xfe, 0xf7, 0x1f, 0x94, 0xbc, 0xf2, 0xfb, 0x0a, 0x84, 0x70, + 0x88, 0x4d, 0x3d, 0x19, 0x43, 0x43, 0x4b, 0xff, 0xb3, 0xbf, 0x7c, 0xab, + 0xed, 0x3d, 0x07, 0x2d, 0xf6, 0x75, 0x69, 0x8c, 0x95, 0x45, 0xe6, 0x4a, 0x86, 0xf6, 0x52, 0x79, 0xe0, 0x09, 0x2a, 0x62, 0xa2, 0xb4, 0xd9, 0x85, - 0xca, 0x76, 0xfa, 0x15, 0x29, 0x0a, 0xc9, 0xa1, 0x83, 0xd8, 0x5b, 0x7e, - 0x55, 0xe9, 0x74, 0xd7, 0xfb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x44, 0x4b, - 0xfb, 0x34, 0xb7, 0x75, 0x9a, 0x22, 0xb5, 0xff, 0x35, 0xf3, 0xcd, 0x2d, - 0xdd, 0x66, 0x8a, 0xe1, 0x5c, 0xd1, 0x06, 0xe7, 0x37, 0xff, 0xbf, 0x81, - 0x5f, 0x37, 0xf7, 0xea, 0x0c, 0x8e, 0x5f, 0x73, 0x9e, 0x66, 0xb3, 0x96, - 0x4f, 0x8f, 0xe3, 0xf4, 0xeb, 0xec, 0xeb, 0xf8, 0xe5, 0xfe, 0xc4, 0xd7, + 0xca, 0x76, 0xe6, 0x15, 0x29, 0x0a, 0xc9, 0xa1, 0x83, 0xd8, 0x5b, 0x7e, + 0x55, 0xe9, 0x74, 0xd7, 0xfb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x44, 0x4b, + 0xfb, 0x34, 0xb7, 0x75, 0x9a, 0x22, 0xb5, 0xff, 0x35, 0xfd, 0xcd, 0x2d, + 0xdd, 0x66, 0x8a, 0xe1, 0x5f, 0x51, 0x06, 0xe7, 0x37, 0xff, 0xbf, 0x81, + 0x5f, 0xd7, 0xf7, 0xea, 0x0c, 0x8e, 0x5f, 0x7d, 0x9e, 0x66, 0xb3, 0x96, + 0x4e, 0x4f, 0xe3, 0xf4, 0xeb, 0xec, 0xeb, 0xf8, 0xe5, 0xfe, 0xc4, 0xd7, 0xff, 0x83, 0x67, 0x2d, 0xc2, 0x09, 0xeb, 0x6c, 0x86, 0xff, 0xfe, 0xf6, 0xd3, 0xae, 0x92, 0x41, 0xf0, 0x3b, 0xac, 0x39, 0x7e, 0xd2, 0xdd, 0xd6, - 0x68, 0xa7, 0x97, 0xf8, 0x3f, 0xf2, 0x86, 0xb8, 0x91, 0xcb, 0xfc, 0xc4, + 0x68, 0xa7, 0x97, 0xf8, 0x3f, 0xfc, 0x86, 0xb8, 0x91, 0xcb, 0xfc, 0xc4, 0x08, 0x1f, 0x52, 0x39, 0x73, 0x10, 0xe5, 0x41, 0xe4, 0xac, 0xce, 0xff, 0xfe, 0x8f, 0x6c, 0x0c, 0x5a, 0x7f, 0x19, 0xd4, 0x02, 0xce, 0x5f, 0xd0, 0xcd, 0xc2, 0x4e, 0x72, 0xa4, 0x88, 0x8f, 0x2d, 0xdf, 0x4a, 0x32, 0x73, 0x97, 0xff, 0xed, 0x03, 0x5a, 0x81, 0xc5, 0x53, 0xbd, 0xc5, 0x0e, 0x57, - 0xc7, 0xf1, 0xa2, 0x2b, 0xff, 0x92, 0x58, 0x3f, 0xc3, 0x13, 0x52, 0x39, - 0x7f, 0xa5, 0x1a, 0x9e, 0x35, 0x39, 0xcb, 0xee, 0x42, 0xf2, 0x39, 0x7e, + 0x27, 0xf1, 0xa2, 0x2b, 0xff, 0x92, 0x58, 0x3f, 0xc3, 0x13, 0x52, 0x39, + 0x7f, 0xa5, 0x1a, 0x9e, 0x35, 0x39, 0xcb, 0xef, 0x82, 0xf2, 0x39, 0x7e, 0x7c, 0xea, 0x30, 0xe5, 0x6c, 0xf2, 0x78, 0x91, 0xd4, 0x22, 0x8b, 0x1f, - 0xaf, 0xfb, 0x8b, 0xb3, 0x90, 0x7a, 0x8c, 0x39, 0x7f, 0xc3, 0x0c, 0x89, + 0xaf, 0xfb, 0x8b, 0xb3, 0xe0, 0x7a, 0x8c, 0x39, 0x7f, 0xc3, 0x0c, 0x89, 0x0e, 0x30, 0xe5, 0x61, 0xf9, 0xa1, 0xed, 0xff, 0x40, 0xaf, 0x38, 0xe7, 0xb6, 0x72, 0xfc, 0xf3, 0xc6, 0x80, 0x72, 0xb8, 0x65, 0xc9, 0xc8, 0x2c, - 0xc5, 0x95, 0x4d, 0x17, 0x08, 0x2f, 0xa1, 0x52, 0x90, 0x9b, 0x72, 0x31, - 0x87, 0x2e, 0xe1, 0x29, 0xc4, 0x81, 0xa1, 0xcd, 0xff, 0xe7, 0x97, 0x30, - 0x8b, 0xb7, 0xbd, 0xc7, 0xe7, 0x2f, 0xff, 0x7f, 0xf8, 0x37, 0xcd, 0x41, - 0x76, 0x0c, 0x1c, 0xbf, 0xf8, 0x73, 0xf7, 0x1f, 0xf9, 0xb1, 0x18, 0x72, - 0xb4, 0x89, 0x4f, 0x27, 0x5f, 0xff, 0xe4, 0x1f, 0xc7, 0x3d, 0xdc, 0xe7, - 0xd7, 0xef, 0x52, 0x63, 0x95, 0xcd, 0x51, 0x68, 0x61, 0x8e, 0x90, 0xe1, + 0xc5, 0x95, 0x4d, 0x17, 0x08, 0x2e, 0x61, 0x52, 0x90, 0x9b, 0x72, 0x31, + 0x87, 0x2e, 0xe1, 0x29, 0xc4, 0x81, 0xa1, 0xcd, 0xff, 0xe7, 0x97, 0xd0, + 0x8b, 0xb7, 0xbd, 0xc7, 0xe7, 0x2f, 0xff, 0x7f, 0xf8, 0x37, 0xf5, 0x41, + 0x76, 0x0c, 0x1c, 0xbf, 0xf8, 0x73, 0xf7, 0x1f, 0xfe, 0xb1, 0x18, 0x72, + 0xb4, 0x89, 0x4f, 0x27, 0x5f, 0xff, 0xe4, 0x1f, 0xc7, 0x3d, 0xdc, 0xfb, + 0xd7, 0xef, 0x52, 0x63, 0x95, 0xf5, 0x51, 0x68, 0x61, 0x8e, 0x90, 0xe1, 0xd9, 0x1d, 0xb0, 0xe5, 0xf8, 0x60, 0x1c, 0x3e, 0xce, 0x5f, 0xca, 0xe9, 0xc2, 0xe2, 0x72, 0x82, 0x7d, 0x38, 0x20, 0xe5, 0x97, 0xff, 0x20, 0x74, - 0xff, 0x73, 0xd6, 0xa2, 0x73, 0x95, 0xcc, 0xfd, 0x7a, 0x5b, 0x70, 0x60, + 0xfc, 0xfd, 0xd6, 0xa2, 0x73, 0x95, 0xf4, 0xfd, 0x7a, 0x5b, 0x70, 0x60, 0xe5, 0xff, 0xfb, 0xb1, 0xac, 0x92, 0x3f, 0xb0, 0x28, 0x05, 0x94, 0xbf, 0x44, 0xbf, 0x04, 0x8e, 0x5f, 0x2d, 0xdd, 0x66, 0x8a, 0xcd, 0x53, 0x1e, 0xbe, 0x8a, 0x6f, 0xbc, 0x8c, 0xd9, 0xcb, 0xca, 0xed, 0x53, 0x97, 0xf7, 0x11, 0x18, 0x6b, 0x98, 0xe5, 0xf9, 0x90, 0x32, 0xd9, 0xca, 0x83, 0xd9, 0x9c, 0xca, 0xfb, 0xdb, 0x53, 0x67, 0x2c, 0xe7, 0x2b, 0x0d, 0xa6, 0xc9, - 0x2e, 0x9d, 0x0e, 0x5f, 0xed, 0xcc, 0x83, 0xdc, 0xf8, 0xe5, 0x41, 0xe5, + 0x2e, 0x9d, 0x0e, 0x5f, 0xed, 0xcc, 0x83, 0xdc, 0xe4, 0xe5, 0x41, 0xe5, 0xe0, 0xbd, 0xfb, 0xdf, 0xa8, 0x32, 0x39, 0x7f, 0xfd, 0x0c, 0xf6, 0x60, 0xfb, 0x7d, 0xcf, 0xdc, 0xe5, 0xe0, 0x3e, 0xce, 0x5f, 0xf6, 0x49, 0x00, 0xd6, 0xd5, 0xfe, 0xc3, 0x96, 0x43, 0x97, 0xf7, 0x70, 0x45, 0xfc, 0x73, 0x65, 0x85, 0xfb, 0x26, 0x9c, 0x1f, 0x9c, 0xbf, 0xbd, 0x1a, 0xfe, 0x26, - 0x39, 0x6e, 0x70, 0xaf, 0x60, 0x22, 0xd9, 0x0a, 0xaf, 0x88, 0xd0, 0x8b, + 0x39, 0x6f, 0xb0, 0xaf, 0x60, 0x22, 0xd9, 0x0a, 0xae, 0x48, 0xd0, 0x8b, 0x4f, 0x0c, 0x56, 0xeb, 0x5b, 0x90, 0x7e, 0x54, 0x29, 0xdb, 0x1c, 0xf2, 0x92, 0x87, 0x5c, 0x05, 0x77, 0xfe, 0xea, 0x79, 0xf5, 0x3c, 0x20, 0x4e, - 0x5f, 0xfb, 0xc0, 0x66, 0x2f, 0x5f, 0x3b, 0x67, 0x2f, 0xf6, 0xa1, 0x5c, - 0x14, 0x54, 0xe5, 0xff, 0xe8, 0x6d, 0x46, 0x0e, 0x7d, 0xe8, 0xc6, 0xce, - 0x5f, 0xbc, 0x83, 0x8c, 0x39, 0x7d, 0x27, 0x1e, 0x78, 0x99, 0x27, 0xc7, - 0xda, 0x41, 0x50, 0xcf, 0x81, 0x32, 0xff, 0xcf, 0x2e, 0x79, 0xa5, 0xbb, - 0xac, 0xd1, 0x22, 0xaf, 0xff, 0xde, 0xee, 0x0f, 0x3f, 0x3b, 0xfd, 0xb5, - 0x55, 0x73, 0x97, 0xfe, 0x7f, 0x73, 0x84, 0xd2, 0x78, 0x07, 0x2b, 0x9a, + 0x5f, 0xfb, 0xc0, 0x66, 0x2f, 0x5c, 0xbb, 0x67, 0x2f, 0xf6, 0xa1, 0x5c, + 0x14, 0x54, 0xe5, 0xff, 0xe8, 0x6d, 0x46, 0x0e, 0x73, 0xe8, 0xc6, 0xce, + 0x5f, 0xbc, 0x83, 0x8c, 0x39, 0x7d, 0x27, 0x1f, 0xb8, 0x99, 0x27, 0x27, + 0xda, 0x41, 0x50, 0xcf, 0x81, 0x32, 0xff, 0xcf, 0x2f, 0xb9, 0xa5, 0xbb, + 0xac, 0xd1, 0x22, 0xaf, 0xff, 0xde, 0xee, 0x0f, 0xdf, 0x3b, 0xf3, 0xb5, + 0x55, 0x73, 0x97, 0xfe, 0x7f, 0x7d, 0x84, 0xd2, 0x78, 0x07, 0x2b, 0xea, 0x39, 0x21, 0x31, 0xd6, 0x6f, 0xec, 0xd2, 0xdd, 0xd6, 0x68, 0xb2, 0x57, 0xe9, 0xd0, 0x65, 0xb3, 0x97, 0xf8, 0x13, 0xf6, 0x3d, 0xb4, 0x39, 0x7e, - 0xf6, 0xd4, 0xdf, 0x3c, 0x3d, 0xcd, 0x14, 0x57, 0x34, 0x6b, 0xe4, 0x25, + 0xf6, 0xd4, 0xdf, 0xdc, 0x3d, 0xcd, 0x14, 0x57, 0xd4, 0x6b, 0xe4, 0x25, 0x6f, 0xf7, 0x02, 0x32, 0x3a, 0xa0, 0x4e, 0x5f, 0xdd, 0x4d, 0x44, 0xb6, 0x72, 0xfe, 0x67, 0x93, 0xae, 0xc3, 0x97, 0xff, 0x93, 0xdd, 0xcf, 0x60, 0xc7, 0xa0, 0x27, 0x2a, 0x0f, 0xd1, 0xcb, 0x6f, 0xf9, 0xd3, 0xc0, 0xd3, - 0xef, 0x9e, 0x23, 0xe1, 0x66, 0xfd, 0x85, 0x0d, 0xfd, 0x9a, 0x5b, 0xba, - 0xcd, 0x16, 0xc2, 0xff, 0xfe, 0xe1, 0x3b, 0xc8, 0x73, 0x5e, 0xdf, 0x66, - 0xe5, 0xcb, 0xad, 0x0e, 0x5e, 0xd0, 0x3a, 0x72, 0xef, 0x73, 0x84, 0x44, - 0x69, 0xae, 0xb9, 0xa3, 0xc5, 0x21, 0x83, 0x7b, 0x37, 0x87, 0x2f, 0x96, + 0xef, 0xee, 0x23, 0xe1, 0x66, 0xfd, 0x85, 0x0d, 0xfd, 0x9a, 0x5b, 0xba, + 0xcd, 0x16, 0xc2, 0xff, 0xfe, 0xe1, 0x3b, 0xf0, 0x73, 0x5e, 0xdf, 0x66, + 0xf9, 0xf3, 0xad, 0x0e, 0x5e, 0xd0, 0x3a, 0x72, 0xef, 0x7d, 0x84, 0x44, + 0x69, 0xae, 0xbe, 0xa3, 0xc5, 0x21, 0x83, 0x7b, 0x37, 0x87, 0x2f, 0x96, 0xee, 0xb3, 0x45, 0xb6, 0xbe, 0xdc, 0xef, 0xa3, 0x95, 0xa3, 0xd1, 0xf1, 0x75, 0xfc, 0x9d, 0xf2, 0x7e, 0x03, 0x97, 0xfd, 0x12, 0x8d, 0x4f, 0x1a, 0x9c, 0xe5, 0xf4, 0x4d, 0xb4, 0x39, 0x52, 0x4c, 0x63, 0x1b, 0x26, 0x22, - 0x12, 0xee, 0x03, 0xab, 0xff, 0x07, 0x48, 0x09, 0xf9, 0xef, 0x5e, 0x39, - 0x5c, 0xd1, 0x21, 0x89, 0xb7, 0xff, 0xb0, 0x7f, 0xe6, 0xc7, 0x0e, 0x60, + 0x12, 0xee, 0x03, 0xab, 0xff, 0x07, 0x48, 0x09, 0xfe, 0xef, 0x5e, 0x39, + 0x5f, 0x51, 0x21, 0x89, 0xb7, 0xff, 0xb0, 0x7f, 0xfa, 0xc7, 0x0e, 0x60, 0xaa, 0x72, 0xf7, 0x0d, 0xd0, 0x9c, 0xbd, 0x3f, 0x50, 0xe5, 0xff, 0xb8, 0x6e, 0x1b, 0x85, 0xfd, 0xdc, 0x18, 0xfc, 0xe5, 0xe6, 0xa3, 0xc2, 0xcd, 0x44, 0xe5, 0xfd, 0x03, 0x20, 0x81, 0x87, 0x2f, 0xfb, 0x35, 0xa8, 0x93, - 0xfc, 0xd9, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x78, 0x2f, 0xde, 0xf9, 0x69, - 0xa3, 0x97, 0xfe, 0x7f, 0x47, 0x1d, 0x6b, 0x3e, 0xd9, 0xca, 0xd2, 0x26, + 0xf2, 0xd9, 0xcb, 0xe5, 0xbb, 0xac, 0xd1, 0x78, 0x2f, 0xde, 0xe5, 0x69, + 0xa3, 0x97, 0xfe, 0x7f, 0x47, 0x1d, 0x6b, 0x39, 0xd9, 0xca, 0xd2, 0x26, 0x18, 0x5c, 0x25, 0x37, 0xde, 0x69, 0x9d, 0x39, 0x7e, 0x64, 0x0c, 0x9c, - 0xe5, 0xfd, 0x03, 0xee, 0x2e, 0xb3, 0x97, 0xf4, 0xa3, 0x8c, 0x6b, 0xe3, - 0x95, 0x23, 0xde, 0xc2, 0xeb, 0xfd, 0x1e, 0x7e, 0xf2, 0x0c, 0x1c, 0xbf, - 0xf2, 0x8c, 0xfa, 0x5e, 0xc1, 0xf6, 0xce, 0x5d, 0x8a, 0x9c, 0xa8, 0x3d, + 0xe5, 0xfd, 0x03, 0xee, 0x2e, 0xb3, 0x97, 0xf4, 0xa3, 0x8c, 0x6b, 0x93, + 0x95, 0x23, 0xde, 0xc2, 0xeb, 0xfd, 0x1e, 0x7e, 0xfc, 0x0c, 0x1c, 0xbf, + 0xf2, 0x8c, 0xe6, 0x5e, 0xc1, 0xf6, 0xce, 0x5d, 0x8a, 0x9c, 0xa8, 0x3d, 0x8c, 0x41, 0xbe, 0x49, 0xf1, 0x87, 0x2f, 0xd8, 0x3f, 0xf0, 0x41, 0xcb, - 0xf4, 0x28, 0x07, 0xd9, 0xcb, 0xff, 0x99, 0x0b, 0xe5, 0x82, 0x09, 0x66, + 0xf4, 0x28, 0x07, 0xd9, 0xcb, 0xff, 0x99, 0x0b, 0xf9, 0x82, 0x09, 0x66, 0xce, 0x5f, 0xee, 0xa3, 0x6a, 0xe9, 0xdb, 0x39, 0x7f, 0xff, 0xe7, 0x4f, - 0x3b, 0x1c, 0x7f, 0x5f, 0x53, 0x52, 0x52, 0x58, 0x27, 0x2f, 0xe8, 0xfb, - 0xe9, 0x3f, 0xc7, 0x2b, 0x13, 0x16, 0x5a, 0x2f, 0x4d, 0x80, 0xd7, 0x7f, + 0x3b, 0x1c, 0x7f, 0x5f, 0x53, 0x52, 0x52, 0x58, 0x27, 0x2f, 0xe8, 0xe7, + 0x99, 0x3f, 0x27, 0x2b, 0x13, 0x16, 0x5a, 0x2f, 0x4d, 0x80, 0xd7, 0x7f, 0xf6, 0x77, 0xaf, 0x26, 0x24, 0x6a, 0x47, 0x2f, 0xa0, 0x64, 0xd6, 0x72, 0xe8, 0xfc, 0xe5, 0x48, 0xff, 0x95, 0x43, 0xf1, 0x25, 0x70, 0x8b, 0xba, 0xfc, 0x31, 0x13, 0x51, 0x1d, 0xe1, 0x65, 0x09, 0xcc, 0x02, 0x5b, 0x90, - 0xd2, 0xf8, 0xbd, 0x09, 0x26, 0x84, 0x23, 0x08, 0x7b, 0x08, 0xc7, 0x20, - 0xfc, 0x88, 0x4a, 0xb7, 0x19, 0xf7, 0xa1, 0x77, 0x7f, 0xbe, 0xe7, 0x9f, - 0xbe, 0xb6, 0x72, 0xff, 0x7f, 0xce, 0x69, 0x40, 0xf8, 0xe5, 0x73, 0x4e, - 0x22, 0x23, 0x1a, 0xd1, 0xbd, 0xe4, 0xcf, 0x8e, 0x5f, 0x2d, 0xdd, 0x66, + 0xd2, 0xe4, 0xbd, 0x09, 0x26, 0x84, 0x23, 0x08, 0x7b, 0x08, 0xc7, 0x20, + 0xfc, 0x88, 0x4a, 0xb7, 0x19, 0xf7, 0xa1, 0x77, 0x7f, 0xb9, 0xfb, 0x9f, + 0xbe, 0xb6, 0x72, 0xff, 0x7f, 0xf6, 0x69, 0x40, 0xf8, 0xe5, 0x7d, 0x4e, + 0x22, 0x23, 0x1a, 0xd1, 0xbd, 0xe4, 0xce, 0x4e, 0x5f, 0x2d, 0xdd, 0x66, 0x8b, 0xd1, 0x7f, 0xe4, 0xf7, 0x45, 0xe5, 0xfb, 0xfe, 0x72, 0xb4, 0x7d, 0xac, 0x2e, 0xbf, 0xf3, 0xa7, 0x81, 0xa7, 0xe3, 0x81, 0x39, 0x79, 0x89, 0xe3, 0x97, 0xfc, 0xfe, 0x94, 0x2b, 0xe4, 0x9c, 0xe5, 0x30, 0xf5, 0x84, 0x72, 0xfd, 0x8c, 0xeb, 0x84, 0xe5, 0x05, 0x38, 0x8c, 0x84, 0x4f, 0x48, 0x94, 0x84, 0xaf, 0x01, 0x0d, 0xff, 0xd8, 0x1e, 0xe3, 0x18, 0xf2, 0xc1, - 0x39, 0x78, 0x11, 0xf9, 0xcb, 0xee, 0x38, 0x3c, 0xc2, 0x7b, 0xfa, 0x42, - 0xbf, 0xdc, 0xfd, 0x93, 0x49, 0xc2, 0x72, 0x90, 0xfc, 0xba, 0x79, 0x5c, - 0xd3, 0x4a, 0xc8, 0xca, 0x6a, 0x1d, 0x0b, 0x3c, 0xf0, 0xc4, 0x94, 0x27, + 0x39, 0x78, 0x11, 0xf9, 0xcb, 0xee, 0x38, 0x3f, 0x42, 0x7b, 0xfa, 0x42, + 0xbf, 0xdf, 0x7d, 0x93, 0x49, 0xc2, 0x72, 0x90, 0xfc, 0xba, 0x79, 0x5f, + 0x53, 0x4a, 0xc8, 0xca, 0x6a, 0x1d, 0x0b, 0x3c, 0xf0, 0xc4, 0x94, 0x27, 0x32, 0x7d, 0x21, 0x71, 0x94, 0x24, 0xbf, 0xc9, 0xa5, 0x00, 0x6a, 0x34, 0xb6, 0x46, 0x0f, 0xd8, 0xc8, 0x7f, 0x8d, 0x50, 0x63, 0xd1, 0xd9, 0x20, 0x27, 0xea, 0x9b, 0x96, 0x15, 0x70, 0x3a, 0x72, 0xff, 0xe0, 0x44, 0xc3, 0x9c, 0x5d, 0x8c, 0x43, 0x97, 0xd9, 0xd7, 0xf1, 0xcb, 0xfd, 0x89, 0xaf, 0xff, 0x06, 0xce, 0x5b, 0x84, 0x55, 0x13, 0x62, 0x8b, 0xb2, 0x1b, 0xff, - 0xde, 0xd8, 0x23, 0x79, 0xe4, 0x63, 0xc8, 0xe5, 0xe8, 0xfa, 0x73, 0x94, - 0x27, 0xcf, 0xe4, 0x9b, 0xfe, 0xf6, 0xf3, 0xe9, 0x74, 0x0a, 0x9c, 0xbd, + 0xde, 0xd8, 0x23, 0x79, 0xe4, 0x63, 0xc8, 0xe5, 0xe8, 0xe6, 0x73, 0x94, + 0x27, 0xcf, 0xe4, 0x9b, 0xfe, 0xf6, 0xf3, 0x99, 0x74, 0x0a, 0x9c, 0xbd, 0xb8, 0x98, 0xe5, 0x21, 0xfd, 0x09, 0x0e, 0xcf, 0x2f, 0xa3, 0x8c, 0x48, 0xe5, 0xfc, 0xfa, 0x90, 0x81, 0xce, 0x5c, 0x8c, 0x39, 0x40, 0x3c, 0x2e, 0x02, 0xcb, 0xce, 0xeb, 0x34, 0x44, 0x6b, 0xe5, 0x56, 0xfa, 0x39, 0x4b, 0x3c, 0xb4, 0x28, 0xbf, 0x70, 0xde, 0xdb, 0xfe, 0x72, 0xb4, 0x79, 0xec, - 0x21, 0xbf, 0xfe, 0xe8, 0x37, 0xbc, 0x60, 0xe7, 0x1e, 0x50, 0xd4, 0x9c, - 0xbf, 0xe8, 0x9f, 0x59, 0xef, 0x27, 0x8e, 0x5e, 0x18, 0xf8, 0xe5, 0x48, + 0x21, 0xbf, 0xfe, 0xe8, 0x37, 0xbc, 0x60, 0xe7, 0x1f, 0x90, 0xd4, 0x9c, + 0xbf, 0xe8, 0x9f, 0x59, 0xef, 0x27, 0x8e, 0x5e, 0x18, 0xe4, 0xe5, 0x48, 0xf5, 0x42, 0x73, 0x7f, 0xd9, 0xac, 0xde, 0x38, 0xce, 0x72, 0xf6, 0x05, 0x87, 0x2f, 0xff, 0xf7, 0x5d, 0x3d, 0x1d, 0x1c, 0xf7, 0x53, 0xb8, 0x8d, - 0x9c, 0xbf, 0xff, 0xfd, 0xef, 0x23, 0x34, 0x99, 0xf0, 0x83, 0xd1, 0xde, - 0x5c, 0x53, 0xd3, 0x41, 0xcb, 0xfe, 0xc7, 0x1f, 0xf4, 0x08, 0xfc, 0xe5, + 0x9c, 0xbf, 0xff, 0xfd, 0xef, 0x23, 0x34, 0x99, 0xc8, 0x83, 0xd1, 0xdf, + 0x9c, 0x53, 0xd3, 0x41, 0xcb, 0xfe, 0xc7, 0x1f, 0xf4, 0x08, 0xfc, 0xe5, 0x42, 0x62, 0x78, 0xbd, 0xa7, 0xcb, 0xfc, 0xec, 0xcd, 0x4a, 0x18, 0x72, - 0xe9, 0xd8, 0x52, 0xe6, 0xdb, 0x29, 0x7f, 0xee, 0x6b, 0xea, 0x4d, 0xd8, - 0x9f, 0x9f, 0xe6, 0xc5, 0xb1, 0x8b, 0xee, 0x31, 0xe8, 0x39, 0x52, 0x44, - 0x02, 0x2e, 0xdf, 0xd8, 0xec, 0xcf, 0xbc, 0x72, 0xff, 0x81, 0x1d, 0xc9, - 0xa4, 0xf3, 0x9c, 0xbf, 0xb9, 0xed, 0x34, 0xff, 0x9c, 0xac, 0x3e, 0xa7, - 0x3a, 0xb3, 0x59, 0xcb, 0xfe, 0x8c, 0xfa, 0x1e, 0x4f, 0x23, 0x97, 0xf8, - 0x39, 0xff, 0x21, 0xcf, 0xce, 0x5f, 0x33, 0xdf, 0xb9, 0xca, 0x6a, 0x91, - 0x48, 0x11, 0x4c, 0x37, 0x73, 0x6b, 0xf0, 0xe7, 0x5f, 0xc7, 0x2f, 0x72, + 0xe9, 0xd8, 0x52, 0xe6, 0xdb, 0x29, 0x7f, 0xef, 0xab, 0xea, 0x4d, 0xd8, + 0x9f, 0xef, 0xe6, 0xc5, 0xb1, 0x8b, 0xee, 0x31, 0xe8, 0x39, 0x52, 0x44, + 0x02, 0x2e, 0xdf, 0xd8, 0xec, 0xce, 0x7c, 0x72, 0xff, 0x81, 0x1d, 0xc9, + 0xa4, 0xf3, 0x9c, 0xbf, 0xbe, 0xed, 0x34, 0xff, 0x9c, 0xac, 0x3e, 0xa7, + 0x3a, 0xb3, 0x59, 0xcb, 0xfe, 0x8c, 0xe6, 0x1e, 0x4f, 0x23, 0x97, 0xf8, + 0x39, 0xff, 0xc1, 0xcf, 0xce, 0x5f, 0x33, 0xdf, 0xb9, 0xca, 0x6a, 0x91, + 0x48, 0x11, 0x4c, 0x37, 0x73, 0x6b, 0xf0, 0xe7, 0x5f, 0xc7, 0x2f, 0x7c, 0xda, 0xce, 0x53, 0x59, 0xe2, 0xf4, 0x9a, 0xff, 0x23, 0xff, 0xad, 0x03, 0xa7, 0x2f, 0xe8, 0x57, 0x05, 0x15, 0x39, 0x7f, 0x67, 0xb8, 0x3d, 0x9d, - 0x39, 0x58, 0x8b, 0x6e, 0x92, 0x89, 0xa6, 0xcb, 0x6f, 0xff, 0xe5, 0xf3, - 0xd3, 0x8a, 0x7b, 0x9e, 0xa3, 0xc2, 0xff, 0x9c, 0xbf, 0xfb, 0xc3, 0x1f, + 0x39, 0x58, 0x8b, 0x6e, 0x92, 0x89, 0xa6, 0xcb, 0x6f, 0xff, 0xe5, 0xfd, + 0xd3, 0x8a, 0x7b, 0xee, 0xa3, 0xc2, 0xff, 0x9c, 0xbf, 0xfb, 0xc3, 0x1f, 0xbf, 0xbf, 0x50, 0x64, 0x72, 0x9a, 0xb6, 0x50, 0xff, 0x0d, 0x0b, 0x28, - 0x8c, 0x72, 0x45, 0xa1, 0x65, 0xc8, 0x5f, 0xac, 0x8b, 0xe8, 0x56, 0xa1, + 0x8c, 0x72, 0x45, 0xa1, 0x65, 0xc8, 0x5f, 0xac, 0x8b, 0x98, 0x56, 0xa1, 0x14, 0xc6, 0xfa, 0x8c, 0xbf, 0xa5, 0xef, 0x0e, 0x3f, 0xc8, 0x86, 0x12, 0xfb, 0x86, 0x27, 0xa3, 0x3b, 0xe2, 0x76, 0xa2, 0xf5, 0xdc, 0x1d, 0x39, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0x8b, 0x97, 0xef, 0x7e, 0xa0, 0xc8, 0xa5, - 0xfb, 0x7e, 0xec, 0x7e, 0x72, 0xfc, 0xf3, 0xc6, 0x80, 0x72, 0xdc, 0xe7, - 0x46, 0x4e, 0x0d, 0x39, 0xa0, 0x0a, 0x9a, 0x14, 0xd7, 0x35, 0x4b, 0x72, - 0x94, 0x11, 0x7f, 0xf3, 0x1e, 0x5c, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0x66, - 0x5f, 0xdc, 0x2b, 0x85, 0xf8, 0x4d, 0xc7, 0x8e, 0x5e, 0xfa, 0x36, 0x72, + 0xfb, 0x7e, 0xec, 0x7e, 0x72, 0xfc, 0xf3, 0xc6, 0x80, 0x72, 0xdf, 0x67, + 0x46, 0x4e, 0x0d, 0x39, 0xa0, 0x0a, 0x9a, 0x14, 0xd7, 0xd5, 0x4b, 0x72, + 0x94, 0x11, 0x7f, 0xf3, 0x1e, 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x66, + 0x5f, 0xdc, 0x2b, 0x85, 0xf8, 0x4d, 0xc7, 0x8e, 0x5e, 0xe6, 0x36, 0x72, 0xff, 0xf7, 0x09, 0xe9, 0x67, 0x7a, 0xf2, 0x44, 0x13, 0x97, 0x96, 0x8c, 0x39, 0x7d, 0xc3, 0x79, 0xc4, 0xe5, 0xcd, 0x1a, 0xa3, 0x97, 0x60, 0x0e, - 0x5f, 0xfd, 0x0c, 0x7f, 0x67, 0xdf, 0xb1, 0x4e, 0x9c, 0xbf, 0xfe, 0x85, - 0xe8, 0x13, 0xfd, 0xb4, 0xd2, 0xfb, 0x87, 0x2b, 0xa8, 0x99, 0x14, 0x7b, - 0xe4, 0x9c, 0x02, 0x72, 0xfd, 0x93, 0xe7, 0xf3, 0x1c, 0xae, 0x47, 0x99, - 0xe2, 0x2b, 0xfd, 0xcb, 0x05, 0xf5, 0xfb, 0x43, 0x97, 0xff, 0xe6, 0x3f, - 0x73, 0xef, 0xfa, 0xdb, 0xf6, 0x6e, 0x80, 0xe5, 0xfd, 0x9b, 0x85, 0x06, + 0x5f, 0xfd, 0x0c, 0x7f, 0x67, 0x3f, 0xb1, 0x4e, 0x9c, 0xbf, 0xfe, 0x85, + 0xe8, 0x13, 0xf3, 0xb4, 0xd2, 0xfb, 0x87, 0x2b, 0xa8, 0x99, 0x14, 0x7b, + 0xe4, 0x9c, 0x02, 0x72, 0xfd, 0x93, 0xe7, 0xf3, 0x1c, 0xaf, 0x87, 0x99, + 0xe2, 0x2b, 0xfd, 0xf3, 0x05, 0xf5, 0xfb, 0x43, 0x97, 0xff, 0xe6, 0x3f, + 0x73, 0x9f, 0xfa, 0xdb, 0xf6, 0x6e, 0x80, 0xe5, 0xfd, 0x9b, 0x85, 0x06, 0x0e, 0x50, 0x51, 0x7b, 0x86, 0xfd, 0x5a, 0xbb, 0x78, 0x72, 0xee, 0x0f, 0x1c, 0xb7, 0x0e, 0x72, 0xdf, 0xc1, 0xb0, 0x00, 0xd5, 0xff, 0xff, 0x90, - 0x61, 0x63, 0x0c, 0xe5, 0x1a, 0xd2, 0x71, 0xd3, 0xbf, 0xe7, 0x2f, 0x93, + 0x61, 0x63, 0x0c, 0xf9, 0x1a, 0xd2, 0x71, 0xd3, 0xbf, 0xe7, 0x2f, 0x93, 0xd1, 0x23, 0x94, 0xd5, 0x2b, 0x46, 0x58, 0xf2, 0x42, 0xbe, 0x66, 0xee, 0xc3, 0x85, 0xcb, 0xff, 0x46, 0xf1, 0x3f, 0x16, 0xdb, 0xf9, 0xb8, 0x11, 0xcf, 0x1c, 0xbe, 0x7e, 0xa4, 0xc7, 0x2f, 0xbb, 0x34, 0x04, 0xe5, 0x61, 0xf8, 0xac, 0xb1, 0xc8, 0xaf, 0xf2, 0xd3, 0x04, 0x3d, 0x83, 0x94, 0x72, 0xfb, 0x51, 0x82, 0x72, 0xf9, 0xfd, 0x2f, 0xce, 0x5f, 0xf6, 0xd1, 0x6f, 0x9a, 0xcf, 0x1c, 0xbf, 0xcf, 0xa4, 0x86, 0xb4, 0x61, 0xca, 0x62, 0x2b, - 0xba, 0x41, 0xe2, 0x3e, 0x26, 0xf7, 0xff, 0xb9, 0x75, 0xd3, 0xdf, 0x80, - 0x45, 0xe4, 0x72, 0xff, 0x94, 0x66, 0x6d, 0xdf, 0xe9, 0x1c, 0xbc, 0xd4, + 0xba, 0x41, 0xe2, 0x3e, 0x26, 0xf7, 0xff, 0xbe, 0x75, 0xd3, 0xdf, 0x80, + 0x45, 0xe4, 0x72, 0xff, 0x94, 0x66, 0x6d, 0xdf, 0x99, 0x1c, 0xbc, 0xd4, 0x5a, 0xae, 0x10, 0xe5, 0x62, 0x7b, 0x6b, 0x31, 0x48, 0x5c, 0xb0, 0xff, 0xf4, 0xb1, 0x3a, 0xbf, 0xff, 0xff, 0xff, 0xfc, 0xd4, 0x78, 0x4c, 0x6a, 0x3c, 0x37, 0x0b, 0xf0, 0xba, 0xf8, 0x78, 0xe1, 0x6e, 0x1b, 0x53, 0xf0, - 0x60, 0x02, 0xd4, 0x21, 0xa7, 0xca, 0x77, 0x86, 0x88, 0xe1, 0x9a, 0xf8, - 0x57, 0xb9, 0x72, 0xeb, 0x43, 0x97, 0xff, 0xef, 0xfe, 0x97, 0x41, 0x1a, - 0xe7, 0xd4, 0x5b, 0xe8, 0xe5, 0xff, 0xbb, 0x83, 0x8a, 0xe0, 0xe0, 0x4e, - 0x5f, 0xfd, 0xf3, 0x71, 0xe0, 0xa3, 0x5e, 0xe1, 0x87, 0x2f, 0x90, 0x7d, + 0x60, 0x02, 0xd4, 0x21, 0xa7, 0x2a, 0x77, 0x86, 0x88, 0xe1, 0x9a, 0xf8, + 0x57, 0xbe, 0x7c, 0xeb, 0x43, 0x97, 0xff, 0xef, 0xf9, 0x97, 0x41, 0x1a, + 0xfb, 0xd4, 0x5b, 0xe8, 0xe5, 0xff, 0xbb, 0x83, 0x8a, 0xe0, 0xe0, 0x4e, + 0x5f, 0xfd, 0xcb, 0x71, 0xe0, 0xa3, 0x5e, 0xe1, 0x87, 0x2f, 0x90, 0x7d, 0xb3, 0x97, 0xff, 0xfc, 0xc4, 0xd7, 0x41, 0xb9, 0x47, 0x1d, 0x40, 0xfb, 0xb9, 0x23, 0x95, 0x24, 0x44, 0xa1, 0x0d, 0xff, 0x93, 0xc8, 0xb4, 0x0f, 0xb1, 0x67, 0x2a, 0x49, 0xb6, 0xe1, 0xe7, 0xa1, 0xa5, 0xc0, 0x45, 0x7d, - 0xe6, 0x99, 0xd3, 0x97, 0xff, 0xf9, 0xc5, 0x63, 0x81, 0xe8, 0x39, 0x76, + 0xe6, 0x99, 0xd3, 0x97, 0xff, 0xf9, 0xc5, 0x63, 0x81, 0xe8, 0x3e, 0x76, 0x25, 0xa8, 0x9c, 0xe5, 0x62, 0x21, 0x80, 0x49, 0x7f, 0xff, 0x9d, 0x51, - 0xcf, 0xc1, 0xbe, 0x52, 0x4e, 0xc2, 0xc5, 0xce, 0x5f, 0x37, 0x0c, 0xf1, - 0xcb, 0xc9, 0xd4, 0x39, 0x50, 0x6f, 0xbc, 0x47, 0x7f, 0xcf, 0xa9, 0x72, + 0xcf, 0xc1, 0xbf, 0x92, 0x4e, 0xc2, 0xc5, 0xce, 0x5f, 0x37, 0x0c, 0xf1, + 0xcb, 0xc9, 0xd4, 0x39, 0x50, 0x6f, 0xbc, 0x47, 0x7f, 0xcf, 0xa9, 0x7c, 0xc5, 0x87, 0x0e, 0x57, 0x0c, 0xb9, 0xc3, 0x11, 0x99, 0xe4, 0x78, 0xfd, 0x86, 0x5b, 0x91, 0x0c, 0x28, 0x00, 0x41, 0x6d, 0x1c, 0xbf, 0xbd, 0x8c, - 0xfb, 0x18, 0x72, 0xdd, 0xc3, 0x7e, 0x82, 0x37, 0xf8, 0x01, 0x79, 0x6d, + 0xe7, 0x18, 0x72, 0xdd, 0xc3, 0x7e, 0x82, 0x37, 0xf8, 0x01, 0x79, 0x6d, 0x24, 0x72, 0xfc, 0xb0, 0x0f, 0xb6, 0x72, 0xfa, 0x24, 0xd1, 0xb3, 0x97, 0xfe, 0x18, 0x5a, 0xaf, 0x9a, 0x4f, 0xce, 0x5f, 0xdb, 0xc4, 0xd6, 0x9c, 0xe5, 0x4e, 0x7d, 0x5f, 0x9f, 0x5f, 0xff, 0x20, 0xcf, 0x9b, 0x47, 0xef, - 0x36, 0xdb, 0x6c, 0xa5, 0x41, 0xfc, 0x04, 0x92, 0xfe, 0xfb, 0x3a, 0x0f, - 0xbf, 0x39, 0x7e, 0xec, 0x4f, 0xd0, 0x1c, 0xac, 0x3d, 0xaf, 0x18, 0xdf, + 0xd6, 0xdb, 0x6c, 0xa5, 0x41, 0xfc, 0x04, 0x92, 0xfe, 0xe7, 0x3a, 0x0e, + 0x7f, 0x39, 0x7e, 0xec, 0x4f, 0xd0, 0x1c, 0xac, 0x3d, 0xaf, 0x18, 0xdf, 0xf0, 0xe4, 0x2a, 0xfe, 0x75, 0x4e, 0x5f, 0xa5, 0xbf, 0xc1, 0x31, 0xcb, - 0xcb, 0x02, 0xce, 0x57, 0xc7, 0x90, 0x02, 0xbb, 0xfe, 0x9f, 0x3f, 0x08, + 0xcb, 0x02, 0xce, 0x57, 0x27, 0x90, 0x02, 0xbb, 0xfe, 0x9f, 0x3f, 0x08, 0x1f, 0x52, 0x39, 0x7f, 0x3b, 0x87, 0x8e, 0x04, 0xe5, 0xe7, 0x75, 0x9a, 0x2c, 0xf5, 0xfd, 0xfb, 0x8c, 0x91, 0x87, 0x2a, 0x74, 0x5f, 0x04, 0xed, - 0x65, 0xdf, 0x94, 0x5f, 0xee, 0xfb, 0x6f, 0xf2, 0x8c, 0x39, 0x7f, 0xdd, + 0x65, 0xdf, 0x94, 0x5f, 0xee, 0xfb, 0x6f, 0xca, 0x8c, 0x39, 0x7f, 0xdd, 0x89, 0x27, 0xa3, 0xdb, 0x39, 0x50, 0x7d, 0xc8, 0x6d, 0x7f, 0xfb, 0x5d, - 0x7e, 0x59, 0xc4, 0x73, 0x78, 0x27, 0x2f, 0xfa, 0x10, 0x38, 0xc6, 0xf3, - 0xa7, 0x2f, 0xfe, 0xdf, 0x92, 0x66, 0xdc, 0x31, 0xf6, 0xce, 0x52, 0x23, + 0x7f, 0x99, 0xc4, 0x73, 0x78, 0x27, 0x2f, 0xfa, 0x10, 0x38, 0xc6, 0xf3, + 0xa7, 0x2f, 0xfe, 0xdf, 0x92, 0x66, 0xdc, 0x31, 0xce, 0xce, 0x52, 0x23, 0x29, 0xd2, 0xc0, 0x71, 0x79, 0xb6, 0xdb, 0x29, 0x7f, 0xe7, 0x96, 0xc7, - 0x16, 0x1c, 0xd1, 0x4e, 0x66, 0x82, 0xfd, 0xc0, 0x06, 0x60, 0x4e, 0x5f, - 0xef, 0x77, 0x38, 0xf2, 0x93, 0x0e, 0x56, 0x1f, 0x18, 0x0a, 0xef, 0xfd, - 0xf4, 0x84, 0x1f, 0xf2, 0x5b, 0x3f, 0x39, 0x74, 0x2a, 0x72, 0xff, 0x83, + 0x16, 0x1c, 0xd1, 0x4f, 0xa6, 0x82, 0xfd, 0xc0, 0x06, 0x60, 0x4e, 0x5f, + 0xef, 0x77, 0x38, 0xfc, 0x93, 0x0e, 0x56, 0x1f, 0x18, 0x0a, 0xef, 0xfd, + 0xcc, 0x84, 0x1f, 0xfc, 0x5b, 0x3f, 0x39, 0x74, 0x2a, 0x72, 0xff, 0x83, 0x03, 0x1f, 0xcb, 0xa8, 0x72, 0xa1, 0x12, 0x93, 0xa2, 0xa0, 0xbd, 0xfe, 0xea, 0x04, 0x5d, 0xe6, 0x39, 0x7f, 0x83, 0xd0, 0x3f, 0xed, 0x30, 0xe5, - 0x41, 0xf4, 0x21, 0x95, 0xfe, 0x8e, 0x5e, 0xcd, 0xee, 0x0e, 0x5f, 0xc1, + 0x41, 0xf4, 0x21, 0x95, 0xfe, 0x8f, 0x9e, 0xcd, 0xee, 0x0e, 0x5f, 0xc1, 0x50, 0x20, 0xf6, 0xce, 0x59, 0x34, 0x7c, 0x82, 0x69, 0x7a, 0x05, 0x53, - 0x95, 0x26, 0x41, 0x68, 0x49, 0x70, 0xcd, 0x52, 0x85, 0xc6, 0x0f, 0xf3, + 0x95, 0x26, 0x41, 0x68, 0x49, 0x70, 0xcd, 0x52, 0x85, 0xc6, 0x0f, 0xcb, 0xda, 0x10, 0xcd, 0x08, 0x0d, 0x43, 0x85, 0x90, 0xad, 0xec, 0x3a, 0xbf, 0x4e, 0x18, 0x59, 0x6e, 0x16, 0xbe, 0x84, 0xbf, 0x18, 0x42, 0x28, 0x4d, 0x77, 0xfb, 0x39, 0x7f, 0xc0, 0xf6, 0xc7, 0x26, 0x86, 0x1c, 0xbe, 0xfd, 0xdb, 0xf1, 0xcb, 0xfc, 0xed, 0xf5, 0x23, 0x50, 0x72, 0x82, 0x8a, 0x75, 0x46, 0x10, 0xe7, 0x44, 0x97, 0xfe, 0xd2, 0x6e, 0x4a, 0x76, 0x06, 0x0e, 0x5f, 0x69, 0x21, 0x87, 0x2f, 0xff, 0xde, 0x54, 0x11, 0x81, 0xee, 0x6f, - 0xe9, 0x47, 0x4e, 0x56, 0x91, 0x6c, 0xc3, 0xe1, 0x21, 0xb9, 0xe4, 0x72, + 0x99, 0x47, 0x4e, 0x56, 0x91, 0x6c, 0xc3, 0xe1, 0x21, 0xb9, 0xe4, 0x72, 0xff, 0xff, 0xfe, 0x17, 0x6f, 0xd9, 0xd1, 0xcf, 0x03, 0xf6, 0x3c, 0x9c, 0x30, 0x2f, 0xa7, 0x91, 0xcb, 0xfd, 0x9d, 0xe8, 0x3c, 0xe2, 0x72, 0xe4, 0x09, 0xcb, 0xfb, 0xab, 0x7d, 0x3c, 0x8e, 0x59, 0x72, 0x3c, 0x3c, 0x16, 0xbc, 0x93, 0x6c, 0xe5, 0x41, 0xe2, 0x30, 0x9e, 0xc8, 0x14, 0xdd, 0xa6, - 0x16, 0xd4, 0x21, 0x99, 0x0b, 0x9b, 0xfb, 0x92, 0x75, 0xd8, 0x87, 0x2f, + 0x16, 0xd4, 0x21, 0x99, 0x0b, 0x9b, 0xfb, 0xe2, 0x75, 0xd8, 0x87, 0x2f, 0x71, 0xc0, 0x9c, 0xb6, 0xa7, 0x3c, 0xc9, 0x8b, 0xaf, 0xfd, 0x8d, 0xf0, 0x6b, 0x38, 0x04, 0x0d, 0x9c, 0xa8, 0x55, 0x5f, 0xd8, 0xe9, 0x5e, 0x13, 0x42, 0x55, 0x7f, 0xff, 0xfd, 0xfe, 0xf3, 0x05, 0x55, 0x34, 0x31, 0x9d, - 0xe7, 0xb1, 0xc9, 0xd9, 0x8c, 0x39, 0x7e, 0x52, 0x05, 0x46, 0x1c, 0xac, + 0xfb, 0xb1, 0xc9, 0xd9, 0x8c, 0x39, 0x7e, 0x52, 0x05, 0x46, 0x1c, 0xac, 0x45, 0x4f, 0xa1, 0x01, 0x77, 0xfb, 0x39, 0x7c, 0xfd, 0x85, 0x0e, 0x56, - 0x1b, 0xae, 0x23, 0x17, 0xff, 0xc0, 0xfa, 0x5b, 0x0f, 0x63, 0x41, 0x77, + 0x1b, 0xae, 0x23, 0x17, 0xff, 0xc0, 0xe6, 0x5b, 0x0f, 0x63, 0x41, 0x77, 0x6c, 0xe5, 0x62, 0x35, 0x51, 0x84, 0x48, 0xaf, 0x0b, 0x10, 0xe5, 0xed, 0xc4, 0xe7, 0x2f, 0x06, 0x24, 0x72, 0xff, 0xa3, 0x17, 0xd4, 0xe2, 0xfa, 0x39, 0x76, 0x74, 0xe5, 0x39, 0xf5, 0x88, 0xe3, 0x43, 0x9b, 0xb0, 0x27, 0x2a, 0x49, 0x8a, 0xe1, 0x6e, 0xc6, 0xfd, 0x08, 0x8e, 0x25, 0xf7, 0xba, 0x06, 0xce, 0x5e, 0xfc, 0x0b, 0x39, 0x7b, 0xd8, 0xa1, 0xcb, 0xfd, 0x0c, - 0x06, 0xfd, 0x9e, 0x39, 0x7f, 0x47, 0xdb, 0xe5, 0xa8, 0x39, 0x78, 0x20, + 0x06, 0xfd, 0x9e, 0x39, 0x7f, 0x47, 0x3b, 0xf9, 0xa8, 0x39, 0x78, 0x20, 0x59, 0xcb, 0xe0, 0x8c, 0x48, 0xe5, 0x21, 0xbe, 0x71, 0xda, 0x0a, 0x63, - 0x3f, 0x0f, 0x20, 0xf4, 0xc3, 0xac, 0x33, 0xeb, 0x75, 0xfe, 0x49, 0x9c, - 0x53, 0xed, 0x9c, 0xbb, 0x16, 0x72, 0xff, 0x0f, 0xb6, 0x31, 0xed, 0x9c, - 0xbf, 0x27, 0x1c, 0x1d, 0x9c, 0xac, 0x3d, 0xad, 0x19, 0x5f, 0xdf, 0x7b, + 0x3c, 0x8f, 0x20, 0xf4, 0xc3, 0xac, 0x33, 0xeb, 0x75, 0xfe, 0x49, 0x9c, + 0x53, 0x9d, 0x9c, 0xbb, 0x16, 0x72, 0xff, 0x0f, 0xb6, 0x31, 0xed, 0x9c, + 0xbf, 0x27, 0x1c, 0x1d, 0x9c, 0xac, 0x3d, 0xad, 0x19, 0x5f, 0xdc, 0xfb, 0x3a, 0x06, 0xb3, 0x97, 0xf6, 0xb3, 0xbd, 0x07, 0x8e, 0x5f, 0xba, 0x31, - 0x9a, 0x31, 0x7f, 0x66, 0xa7, 0x03, 0x84, 0xd1, 0x06, 0xb9, 0x9a, 0x6b, - 0x6a, 0x74, 0x50, 0xc9, 0x52, 0xf8, 0x7b, 0x9f, 0x1c, 0xa8, 0x4c, 0x7d, + 0x9a, 0x31, 0x7f, 0x66, 0xa7, 0x03, 0x84, 0xd1, 0x06, 0xbe, 0x9a, 0x6b, + 0x6a, 0x74, 0x50, 0xc9, 0x52, 0xf8, 0x7b, 0x9c, 0x9c, 0xa8, 0x4c, 0x7d, 0x21, 0xa6, 0xe5, 0x57, 0xe7, 0x5a, 0x32, 0x0e, 0x5f, 0xd2, 0xe8, 0xbf, - 0xde, 0x39, 0x4b, 0x3d, 0x41, 0x26, 0xbe, 0x50, 0x5e, 0x73, 0x95, 0x87, - 0x89, 0xb2, 0x1b, 0xf4, 0x7b, 0x93, 0x1b, 0x39, 0x7f, 0xa4, 0x8c, 0x8e, - 0xa8, 0x13, 0x97, 0xff, 0xa3, 0x07, 0xef, 0x66, 0x92, 0x77, 0x61, 0xcb, - 0xf3, 0xb7, 0xec, 0xee, 0xcf, 0xf7, 0xc6, 0x95, 0xc9, 0x5d, 0xb3, 0x56, + 0x3e, 0x39, 0x4b, 0x3d, 0x41, 0x26, 0xbe, 0x50, 0x5e, 0x73, 0x95, 0x87, + 0x89, 0xb2, 0x1b, 0xf4, 0x7b, 0xe3, 0x1b, 0x39, 0x7f, 0xa4, 0x8c, 0x8e, + 0xa8, 0x13, 0x97, 0xff, 0xa3, 0x07, 0x9f, 0x66, 0x92, 0x77, 0x61, 0xcb, + 0xf3, 0xb7, 0xec, 0xee, 0xcf, 0xf7, 0xc6, 0x95, 0xf1, 0x5d, 0xb3, 0x56, 0x67, 0x0e, 0x12, 0x8d, 0x03, 0x21, 0x97, 0xa2, 0x11, 0x85, 0x45, 0xed, 0xe4, 0x8e, 0x5d, 0x8a, 0x1c, 0xbe, 0xff, 0xb0, 0x13, 0x97, 0xfd, 0x1f, - 0xb2, 0x30, 0x7d, 0xb3, 0x94, 0x87, 0xb7, 0xd2, 0x3b, 0xf2, 0x7d, 0x24, + 0xb2, 0x30, 0x7d, 0xb3, 0x94, 0x87, 0xb7, 0xd2, 0x3b, 0xf2, 0x73, 0x24, 0x13, 0x97, 0x93, 0xb8, 0x72, 0xe8, 0x66, 0x1e, 0x12, 0xc9, 0xef, 0xe6, 0xf1, 0x91, 0xa5, 0x4e, 0x5f, 0x07, 0x7d, 0x83, 0x97, 0xe1, 0xd3, 0x6f, 0x39, 0xca, 0x83, 0xfa, 0xc2, 0xf7, 0x22, 0xbf, 0x67, 0xb6, 0x8c, 0x39, 0x70, 0x04, 0xe5, 0x42, 0xa0, 0x09, 0x0e, 0x63, 0x92, 0x31, 0xea, 0x14, - 0xc2, 0x59, 0xb2, 0x7b, 0xdd, 0xc1, 0x39, 0x7f, 0xb0, 0x73, 0xef, 0x49, + 0xc2, 0x59, 0xb2, 0x7b, 0xdd, 0xc1, 0x39, 0x7f, 0xb0, 0x73, 0x9f, 0x49, 0x87, 0x2e, 0xf4, 0x1c, 0xa8, 0x3c, 0x97, 0x33, 0xbf, 0xd3, 0x44, 0xec, 0x79, 0xa0, 0xe5, 0xff, 0xf3, 0xab, 0xe8, 0xd7, 0xfa, 0x8f, 0x0b, 0xfe, - 0x72, 0xfe, 0x1c, 0xff, 0x06, 0x47, 0x2f, 0xff, 0x95, 0xe4, 0xa0, 0xbf, - 0xb6, 0x9f, 0x75, 0x1b, 0x39, 0x61, 0xc4, 0x40, 0xb9, 0x65, 0x62, 0x76, + 0x72, 0xfe, 0x1c, 0xff, 0x06, 0x47, 0x2f, 0xff, 0x95, 0xf8, 0xa0, 0xbf, + 0xb6, 0x9c, 0xf5, 0x1b, 0x39, 0x61, 0xc4, 0x40, 0xb9, 0x65, 0x62, 0x76, 0x3a, 0x64, 0x72, 0x01, 0x35, 0x04, 0x34, 0xae, 0xdf, 0x13, 0x97, 0x27, 0x8e, 0x5f, 0x20, 0xb8, 0x4e, 0x5f, 0xf9, 0x99, 0xed, 0xa9, 0xb7, 0x96, - 0x1c, 0xbf, 0x6e, 0x35, 0xe8, 0x39, 0xcc, 0xdf, 0xd0, 0x51, 0x31, 0xb5, + 0x1c, 0xbf, 0x6e, 0x35, 0xe8, 0x39, 0xf4, 0xdf, 0xd0, 0x51, 0x31, 0xb5, 0xfb, 0xf2, 0x93, 0x3b, 0xe8, 0xe5, 0xf7, 0x71, 0x38, 0x9c, 0xbf, 0xb6, - 0x9a, 0xc0, 0x68, 0xe5, 0xff, 0xfd, 0x37, 0x24, 0x58, 0x35, 0xb0, 0x72, + 0x9a, 0xc0, 0x68, 0xe5, 0xff, 0xfd, 0x37, 0xc4, 0x58, 0x35, 0xb0, 0x7c, 0x62, 0x7b, 0xa8, 0x72, 0xe8, 0x54, 0xe5, 0x41, 0xfc, 0x23, 0x0d, 0x62, 0x7f, 0x6a, 0x8c, 0xa4, 0x2b, 0x98, 0x47, 0xd2, 0x9f, 0x11, 0xf0, 0x42, 0x96, 0xe6, 0x70, 0x86, 0x8b, 0xf1, 0x7d, 0xbd, 0x66, 0x1c, 0xbf, 0xfa, 0x5e, 0x04, 0xa4, 0xcf, 0x7a, 0x18, 0x72, 0xff, 0x7b, 0x71, 0x3e, 0x6c, - 0x27, 0x2e, 0xee, 0x1c, 0xbf, 0xfe, 0xec, 0x07, 0x17, 0xcb, 0x07, 0x03, + 0x27, 0x2e, 0xee, 0x1c, 0xbf, 0xfe, 0xec, 0x07, 0x17, 0xf3, 0x07, 0x03, 0xd8, 0x39, 0x7f, 0xda, 0x8e, 0xa7, 0x1d, 0x44, 0x8e, 0x5f, 0xfc, 0x98, - 0x39, 0x9b, 0xe5, 0x2d, 0xb0, 0xe5, 0xff, 0x9e, 0x3e, 0x97, 0x2d, 0xfc, - 0x18, 0x39, 0x41, 0x4f, 0x03, 0xe2, 0x14, 0x46, 0x6b, 0x34, 0x98, 0x5b, + 0x39, 0x9b, 0xf9, 0x2d, 0xb0, 0xe5, 0xff, 0x9e, 0x39, 0x97, 0xcd, 0xf2, + 0x18, 0x39, 0x41, 0x4f, 0x03, 0x92, 0x14, 0x46, 0x6b, 0x34, 0x98, 0x5b, 0x49, 0xfb, 0x3a, 0xf2, 0x25, 0xe5, 0x63, 0x47, 0x2f, 0xe0, 0xc7, 0xfa, - 0xcf, 0x8e, 0x57, 0x33, 0xcc, 0x60, 0xed, 0xcb, 0x9c, 0xe5, 0xfe, 0x86, + 0xce, 0x4e, 0x57, 0xd3, 0xcc, 0x60, 0xed, 0xcb, 0x9c, 0xe5, 0xfe, 0x86, 0x62, 0x6a, 0x69, 0x1c, 0xb9, 0x26, 0x39, 0x7f, 0xb5, 0x0a, 0x84, 0x63, - 0xe3, 0x97, 0xff, 0xbd, 0x1d, 0x17, 0x9e, 0x35, 0xa7, 0x91, 0xcb, 0xde, - 0x49, 0xce, 0x5f, 0xbf, 0x7f, 0xa2, 0x63, 0x97, 0x86, 0x16, 0x72, 0xff, - 0xe0, 0xa4, 0xdd, 0x8d, 0x7d, 0x28, 0xd1, 0xcb, 0xff, 0xc8, 0x2f, 0xf6, - 0xf7, 0x9a, 0x0f, 0x70, 0xe5, 0x72, 0x4e, 0x16, 0x42, 0xe8, 0x68, 0xc4, + 0x93, 0x97, 0xff, 0xbd, 0x1d, 0x17, 0x9e, 0x35, 0xa7, 0x91, 0xcb, 0xde, + 0x49, 0xce, 0x5f, 0xbf, 0x7e, 0x62, 0x63, 0x97, 0x86, 0x16, 0x72, 0xff, + 0xe0, 0xa4, 0xdd, 0x8d, 0x73, 0x28, 0xd1, 0xcb, 0xff, 0xc8, 0x2f, 0xce, + 0xf7, 0x9a, 0x0f, 0x70, 0xe5, 0x7c, 0x4e, 0x16, 0x42, 0xe8, 0x68, 0xc4, 0x97, 0x1d, 0x12, 0xad, 0x8d, 0xf0, 0x23, 0x5a, 0x0e, 0x5e, 0xea, 0x78, 0xe5, 0xb8, 0xe1, 0xac, 0x50, 0x42, 0xa1, 0x77, 0x64, 0x2e, 0x39, 0x1f, 0x4a, 0x43, 0x09, 0x84, 0x9d, 0x18, 0x78, 0xee, 0x3f, 0x85, 0x05, 0xe6, 0x3a, 0x87, 0x2f, 0xfb, 0x06, 0x43, 0x8c, 0x85, 0x9c, 0xbf, 0x75, 0x38, 0xe0, 0x4e, 0x5f, 0xf8, 0x30, 0x38, 0x20, 0x96, 0x6c, 0xe5, 0xf9, 0xd8, - 0x9c, 0x18, 0x72, 0xfe, 0xce, 0xbf, 0x9e, 0x63, 0x97, 0x47, 0xc7, 0x2b, - 0xe3, 0xc4, 0xf1, 0x6d, 0x62, 0x24, 0x1d, 0xb6, 0xf4, 0x24, 0xc7, 0x2e, + 0x9c, 0x18, 0x72, 0xfe, 0xce, 0xbf, 0x9e, 0x63, 0x97, 0x47, 0x27, 0x2b, + 0x93, 0xc4, 0xf1, 0x6d, 0x62, 0x24, 0x1d, 0xb6, 0xf4, 0x24, 0xc7, 0x2e, 0xd6, 0x1c, 0xbc, 0x2d, 0x57, 0x01, 0xcb, 0xf6, 0x4e, 0xc8, 0xd9, 0xcb, - 0xff, 0xff, 0x47, 0x51, 0x9c, 0xe6, 0x93, 0xe9, 0x4e, 0xa7, 0xdb, 0x5a, + 0xff, 0xff, 0x47, 0x51, 0x9f, 0x66, 0x93, 0xe9, 0x4e, 0xa7, 0x3b, 0x5a, 0x4e, 0x72, 0xa7, 0x54, 0xb2, 0x11, 0xd5, 0x4d, 0x90, 0xa6, 0x68, 0x66, 0x74, 0x87, 0xf1, 0xc1, 0x16, 0xd9, 0x27, 0x01, 0x45, 0xe4, 0xee, 0xce, - 0x5f, 0x72, 0x79, 0x35, 0x27, 0x2f, 0xfe, 0xce, 0x38, 0x1c, 0x10, 0x4b, + 0x5f, 0x7c, 0x79, 0x35, 0x27, 0x2f, 0xfe, 0xce, 0x38, 0x1c, 0x10, 0x4b, 0x36, 0x72, 0xfd, 0xa8, 0xea, 0x81, 0x39, 0x5a, 0x3e, 0xd7, 0x44, 0xbe, - 0x84, 0x9e, 0x0e, 0x5f, 0x36, 0xf9, 0xb3, 0x97, 0xf0, 0x63, 0xf1, 0xcf, - 0x8e, 0x5f, 0xf4, 0x98, 0xf2, 0xf6, 0xe1, 0x53, 0x95, 0x08, 0x8a, 0xc2, - 0x27, 0x2e, 0xbd, 0xb4, 0x13, 0x97, 0xe1, 0x5f, 0x2d, 0xfc, 0x72, 0xff, + 0x84, 0x9e, 0x0e, 0x5f, 0x36, 0xf9, 0xb3, 0x97, 0xf0, 0x63, 0xf1, 0xce, + 0x4e, 0x5f, 0xf4, 0x98, 0xf2, 0xf6, 0xe1, 0x53, 0x95, 0x08, 0x8a, 0xc2, + 0x27, 0x2e, 0xbd, 0xb4, 0x13, 0x97, 0xe1, 0x5f, 0xcd, 0xf2, 0x72, 0xff, 0x29, 0x28, 0xe2, 0x83, 0xf9, 0xca, 0xc3, 0xfc, 0x71, 0xb1, 0x2b, 0xac, 0x54, 0xa6, 0xd6, 0x38, 0xf0, 0x96, 0xfc, 0x84, 0x61, 0x56, 0x08, 0x54, - 0xdd, 0x3c, 0x8e, 0x5e, 0x4e, 0xa1, 0xca, 0xf8, 0xd9, 0xf8, 0x62, 0xf9, + 0xdd, 0x3c, 0x8e, 0x5e, 0x4e, 0xa1, 0xca, 0xe4, 0xd9, 0xf8, 0x62, 0xf9, 0x40, 0x3e, 0xce, 0x5f, 0xf2, 0x2b, 0x01, 0x8e, 0x39, 0xd3, 0x97, 0xfd, - 0xd4, 0x6f, 0xe9, 0x6f, 0x16, 0x72, 0xfe, 0x06, 0xe2, 0x60, 0x68, 0xe5, - 0xe0, 0x67, 0xc7, 0x2b, 0xa7, 0x99, 0xe2, 0xfb, 0xfd, 0x20, 0x0c, 0xfb, - 0x4f, 0x8e, 0x5f, 0x7f, 0xfe, 0x7c, 0x72, 0xfe, 0xe0, 0xf6, 0x38, 0xac, - 0xe5, 0xff, 0x01, 0xe4, 0x1c, 0xcf, 0xf6, 0x72, 0xff, 0xdf, 0x4b, 0xb0, - 0xc7, 0xfa, 0x58, 0x72, 0xfe, 0x4f, 0xbe, 0x96, 0x78, 0xe5, 0x61, 0xf7, - 0xfe, 0x81, 0x5d, 0x46, 0x56, 0xe1, 0x51, 0x7e, 0xfb, 0x6c, 0x46, 0xb3, - 0x97, 0xff, 0xec, 0xdf, 0x2e, 0xba, 0x7b, 0xf0, 0x08, 0xbc, 0x8e, 0x54, + 0xd4, 0x6f, 0x99, 0x6f, 0x16, 0x72, 0xfe, 0x06, 0xe2, 0x60, 0x68, 0xe5, + 0xe0, 0x67, 0x27, 0x2b, 0xa7, 0x99, 0xe2, 0xfb, 0xfd, 0x20, 0x0c, 0xfb, + 0x4e, 0x4e, 0x5f, 0x7f, 0xfe, 0x72, 0x72, 0xfe, 0xe0, 0xf6, 0x38, 0xac, + 0xe5, 0xff, 0x01, 0xe4, 0x1c, 0xcf, 0xf6, 0x72, 0xff, 0xdc, 0xcb, 0xb0, + 0xc7, 0xe6, 0x58, 0x72, 0xfe, 0x4e, 0x79, 0x96, 0x78, 0xe5, 0x61, 0xf7, + 0xfe, 0x81, 0x5d, 0x46, 0x56, 0xe1, 0x51, 0x7e, 0xe7, 0x6c, 0x46, 0xb3, + 0x97, 0xff, 0xec, 0xdf, 0xce, 0xba, 0x7b, 0xf0, 0x08, 0xbc, 0x8e, 0x54, 0x22, 0x08, 0x4b, 0x2f, 0xe7, 0x9f, 0xf7, 0x10, 0x9c, 0xa9, 0xd5, 0x97, 0x84, 0xe9, 0x70, 0x87, 0x98, 0x8b, 0x46, 0xbd, 0x25, 0xf4, 0x3e, 0x78, 0xc2, 0xa9, 0xa1, 0x0d, 0xef, 0x60, 0x9c, 0xbd, 0xd7, 0x6b, 0x39, 0x7f, 0x94, 0x85, 0xb4, 0xcd, 0x41, 0xcb, 0xfe, 0x0e, 0x03, 0x53, 0xad, 0x27, 0x39, 0x7f, 0x47, 0x53, 0x50, 0xc3, 0x95, 0x24, 0x6b, 0x2a, 0x37, 0xd1, 0xf7, 0x35, 0xf1, 0xdd, 0x42, 0xe8, 0x3e, 0x4b, 0x52, 0x78, 0xda, 0xee, - 0x98, 0x07, 0x2c, 0xc3, 0x95, 0xf1, 0xa9, 0xe1, 0xc6, 0x2f, 0xf7, 0xbf, + 0x98, 0x07, 0x2c, 0xc3, 0x95, 0xc9, 0xa9, 0xe1, 0xc6, 0x2f, 0xf7, 0xbf, 0x00, 0xed, 0x02, 0x72, 0xfd, 0x2f, 0xf3, 0x02, 0x72, 0xfa, 0x35, 0x9c, - 0x50, 0xf7, 0x1c, 0xd2, 0xff, 0xf4, 0xc3, 0x1e, 0xdf, 0xbe, 0x5a, 0x0c, - 0xe7, 0x2f, 0xc8, 0xc5, 0x26, 0xd9, 0xcb, 0xf9, 0xfe, 0x90, 0xc0, 0x4e, - 0x5f, 0xf4, 0x7d, 0x24, 0x16, 0x3f, 0x8e, 0x52, 0x23, 0x6f, 0xa9, 0x8e, + 0x50, 0xf7, 0x1c, 0xd2, 0xff, 0xf4, 0xc3, 0x1e, 0xdf, 0xb9, 0x5a, 0x0c, + 0xe7, 0x2f, 0xc8, 0xc5, 0x26, 0xd9, 0xcb, 0xf9, 0xf9, 0x90, 0xc0, 0x4e, + 0x5f, 0xf4, 0x73, 0x24, 0x16, 0x3f, 0x8e, 0x52, 0x23, 0x6f, 0xa9, 0x8e, 0x54, 0x25, 0xb7, 0xe7, 0x96, 0x4f, 0x07, 0x2f, 0xfe, 0x8d, 0xef, 0x19, 0xe1, 0x86, 0x6c, 0xe5, 0xfe, 0x0e, 0xd3, 0xbd, 0xc0, 0x9c, 0xbf, 0xf9, - 0x23, 0x62, 0xf2, 0xe5, 0xbc, 0xd1, 0xcb, 0xff, 0xfc, 0x9b, 0x9f, 0x1b, - 0xc1, 0x07, 0x04, 0x73, 0xc1, 0x7d, 0x1c, 0xbf, 0xdf, 0x4b, 0x73, 0x4a, + 0x23, 0x62, 0xf2, 0xf9, 0xbc, 0xd1, 0xcb, 0xff, 0xfc, 0x9b, 0x9f, 0x1b, + 0xc1, 0x07, 0x04, 0x7d, 0xc1, 0x7d, 0x1c, 0xbf, 0xdc, 0xcb, 0x73, 0x4a, 0x27, 0x39, 0x41, 0x4d, 0xf1, 0x64, 0xee, 0x86, 0x26, 0x7e, 0x44, 0x03, - 0x25, 0xff, 0xff, 0xba, 0x9f, 0x7b, 0x3e, 0xf6, 0xb5, 0x1e, 0xfd, 0x41, + 0x25, 0xff, 0xff, 0xba, 0x9c, 0xfb, 0x39, 0xf6, 0xb5, 0x1e, 0xfd, 0x41, 0x97, 0x70, 0xe5, 0xfb, 0xb1, 0xc4, 0x30, 0x72, 0xf0, 0x5c, 0x4e, 0x5b, - 0x89, 0xcb, 0xf7, 0xde, 0x18, 0xe9, 0xcb, 0x6a, 0x0d, 0xdb, 0x89, 0xdc, + 0x89, 0xcb, 0xf7, 0x3e, 0x18, 0xe9, 0xcb, 0x6a, 0x0d, 0xdb, 0x89, 0xdc, 0x0d, 0x1c, 0xa9, 0x22, 0xec, 0x25, 0x3a, 0x56, 0xd9, 0x2d, 0xff, 0xa5, 0x03, 0xed, 0x27, 0x1c, 0x09, 0xcb, 0xff, 0x3f, 0xb6, 0x09, 0x28, 0x14, - 0xf1, 0xcb, 0xd8, 0x9b, 0x39, 0x7f, 0xfd, 0x3b, 0xf7, 0x03, 0xcb, 0x04, - 0x71, 0x3f, 0x39, 0x53, 0x9f, 0x5e, 0x86, 0xef, 0xfb, 0xab, 0x47, 0xe5, - 0xb7, 0xe9, 0xca, 0xc3, 0xdd, 0x72, 0x3b, 0xfb, 0xae, 0x3f, 0x49, 0x0e, - 0x5f, 0xff, 0xb6, 0x3c, 0xba, 0xe9, 0xef, 0xc0, 0x22, 0xf2, 0x39, 0x7f, + 0xf1, 0xcb, 0xd8, 0x9b, 0x39, 0x7f, 0xfd, 0x3b, 0xf7, 0x03, 0xf3, 0x04, + 0x71, 0x3f, 0x39, 0x53, 0x9f, 0x5e, 0x86, 0xef, 0xfb, 0xab, 0x47, 0xf9, + 0xb7, 0xe9, 0xca, 0xc3, 0xdd, 0x72, 0x3b, 0xfb, 0xae, 0x3c, 0xc9, 0x0e, + 0x5f, 0xff, 0xb6, 0x3f, 0x3a, 0xe9, 0xef, 0xc0, 0x22, 0xf2, 0x39, 0x7f, 0xba, 0x8a, 0xb4, 0x06, 0x95, 0x39, 0x7f, 0xd0, 0xdb, 0x3b, 0x08, 0x33, 0x9c, 0xbf, 0xfe, 0x1c, 0xde, 0x32, 0x17, 0x9e, 0x4d, 0x61, 0xcb, 0x62, 0xd1, 0x7b, 0xe3, 0x8e, 0x27, 0x37, 0xf4, 0xf9, 0xa4, 0x5c, 0x1c, 0xbe, @@ -4325,35 +4325,35 @@ 0x76, 0x30, 0xea, 0x86, 0x4a, 0x8c, 0xf0, 0x83, 0x0c, 0x62, 0x79, 0x1d, 0xb2, 0xd5, 0x92, 0x32, 0xb9, 0x8f, 0x58, 0x7f, 0xd8, 0xc2, 0x1c, 0x83, 0xf2, 0xd1, 0x8c, 0x4f, 0xd1, 0xbb, 0xdf, 0xfd, 0x83, 0xfe, 0x66, 0xb7, - 0xe8, 0xc3, 0x97, 0xfd, 0xf7, 0xb3, 0x49, 0x3b, 0xb0, 0xe5, 0xec, 0xe3, + 0xe8, 0xc3, 0x97, 0xfd, 0xcf, 0xb3, 0x49, 0x3b, 0xb0, 0xe5, 0xec, 0xe3, 0x87, 0x2d, 0x9f, 0xa2, 0x64, 0x50, 0xb6, 0x75, 0x7b, 0x87, 0x92, 0x1c, - 0xbe, 0x81, 0x79, 0x1c, 0xbf, 0x63, 0x5b, 0x8f, 0xfc, 0x8f, 0x07, 0x44, + 0xbe, 0x81, 0x79, 0x1c, 0xbf, 0x63, 0x5b, 0x8f, 0xff, 0x0f, 0x07, 0x44, 0x37, 0xf7, 0x1e, 0xa4, 0x6b, 0x67, 0x2f, 0xfd, 0xd4, 0x60, 0x72, 0x68, - 0xcd, 0x1c, 0xbd, 0x28, 0xf8, 0xe5, 0xf4, 0x7e, 0xec, 0x39, 0x70, 0xcb, + 0xcd, 0x1c, 0xbd, 0x28, 0xe4, 0xe5, 0xf4, 0x7e, 0xec, 0x39, 0x70, 0xcb, 0x0f, 0xf6, 0x63, 0xe1, 0x1d, 0xbe, 0xda, 0x7a, 0x0e, 0x54, 0x1e, 0xd3, - 0x9c, 0xdf, 0xfc, 0xb4, 0xd7, 0x21, 0x79, 0xc6, 0x3e, 0x39, 0x7c, 0xbe, - 0xa4, 0xc7, 0x2f, 0xff, 0xc3, 0x8a, 0xaa, 0x81, 0xea, 0x4d, 0xd4, 0xfb, + 0x9c, 0xdf, 0xfc, 0xb4, 0xd7, 0xc1, 0x79, 0xc6, 0x39, 0x39, 0x7c, 0xbe, + 0xa4, 0xc7, 0x2f, 0xff, 0xc3, 0x8a, 0xaa, 0x81, 0xea, 0x4d, 0xd4, 0xe7, 0xc7, 0x2a, 0x0f, 0xef, 0x08, 0xef, 0x2d, 0xf4, 0x72, 0xfd, 0xb5, 0xc6, - 0x95, 0x39, 0x7f, 0x27, 0xff, 0x4b, 0x3c, 0x72, 0xba, 0x7e, 0x9f, 0x8e, + 0x95, 0x39, 0x7f, 0x27, 0xfc, 0xcb, 0x3c, 0x72, 0xba, 0x7e, 0x9f, 0x8e, 0x71, 0x29, 0xbf, 0xa5, 0x88, 0x1e, 0xa1, 0xcb, 0xcf, 0xa5, 0x4e, 0x56, - 0x1e, 0x4b, 0x96, 0x5f, 0xfd, 0x9f, 0x7b, 0x68, 0x31, 0xfb, 0xb0, 0xe5, - 0xe9, 0x33, 0xa7, 0x2a, 0x73, 0xe1, 0xf2, 0x25, 0xfd, 0xf6, 0xf1, 0x90, + 0x1e, 0x4b, 0x96, 0x5f, 0xfd, 0x9c, 0xfb, 0x68, 0x31, 0xfb, 0xb0, 0xe5, + 0xe9, 0x33, 0xa7, 0x2a, 0x73, 0xe1, 0xf2, 0x25, 0xfd, 0xce, 0xf1, 0x90, 0xd6, 0x72, 0xf2, 0xa8, 0xd9, 0xcb, 0xf3, 0x69, 0x82, 0xa9, 0xca, 0x43, - 0xc6, 0x00, 0xf5, 0x62, 0x2e, 0xdc, 0x8c, 0x5d, 0xee, 0xe5, 0x87, 0x2f, - 0xb6, 0x30, 0xc3, 0x95, 0x06, 0xe7, 0xe1, 0x8b, 0xdd, 0x93, 0x0e, 0x5d, + 0xc6, 0x00, 0xf5, 0x62, 0x2e, 0xdc, 0x8c, 0x5d, 0xee, 0xf9, 0x87, 0x2f, + 0xb6, 0x30, 0xc3, 0x95, 0x06, 0xe7, 0x91, 0x8b, 0xdd, 0x93, 0x0e, 0x5d, 0xd4, 0x39, 0x58, 0x6c, 0xfc, 0x3b, 0x50, 0xbb, 0x8b, 0x27, 0x6c, 0x43, - 0x56, 0x30, 0x6f, 0x88, 0x3b, 0x0c, 0x17, 0x84, 0xa0, 0xbd, 0xee, 0x33, - 0xc0, 0x33, 0x34, 0x54, 0xbf, 0xd1, 0x32, 0x7d, 0xb0, 0x30, 0xe5, 0xcc, + 0x56, 0x30, 0x6e, 0x48, 0x3b, 0x0c, 0x17, 0x84, 0xa0, 0xbd, 0xee, 0x33, + 0xc0, 0x33, 0x34, 0x54, 0xbf, 0xd1, 0x32, 0x73, 0xb0, 0x30, 0xe5, 0xcc, 0x59, 0xca, 0x9c, 0xf3, 0x02, 0x6b, 0x7f, 0x2c, 0x29, 0xc6, 0x02, 0x72, 0xdd, 0x39, 0x6f, 0xce, 0x5d, 0xb9, 0x1c, 0xa7, 0x3e, 0x9f, 0xcb, 0xf6, 0x22, 0x01, 0x2b, 0xfa, 0x79, 0xa5, 0xc3, 0x6a, 0x73, 0x97, 0x9f, 0x34, 0x72, 0xf0, 0xe7, 0x8e, 0x57, 0x4d, 0xb0, 0x8d, 0xdd, 0xe1, 0x39, 0x7a, - 0x3e, 0xd9, 0xcb, 0xe4, 0x19, 0x61, 0xcb, 0xd3, 0xb8, 0x9c, 0xa0, 0x9e, - 0xcb, 0x07, 0x7c, 0x41, 0x7e, 0xcf, 0x75, 0x3c, 0x72, 0xfc, 0xff, 0x67, - 0xde, 0x39, 0x65, 0x7a, 0x7a, 0x1e, 0x27, 0xb4, 0xe7, 0x2d, 0xa3, 0x95, - 0x39, 0xa3, 0x41, 0x2b, 0xfa, 0x7e, 0x53, 0xbb, 0xf4, 0xe5, 0x35, 0x4a, + 0x39, 0xd9, 0xcb, 0xe4, 0x19, 0x61, 0xcb, 0xd3, 0xb8, 0x9c, 0xa0, 0x9e, + 0xcb, 0x07, 0x7c, 0x41, 0x7e, 0xcf, 0x75, 0x3c, 0x72, 0xfc, 0xfc, 0xe7, + 0x3e, 0x39, 0x65, 0x7a, 0x7a, 0x1e, 0x27, 0xb4, 0xe7, 0x2d, 0xa3, 0x95, + 0x39, 0xa3, 0x41, 0x2b, 0xfa, 0x7f, 0x93, 0xbb, 0xf4, 0xe5, 0x35, 0x4a, 0x86, 0x61, 0xb6, 0x44, 0x18, 0xde, 0x8f, 0xfd, 0x4c, 0x72, 0x1b, 0xfe, - 0xc0, 0x85, 0x3e, 0xcf, 0xbc, 0x72, 0xf9, 0x63, 0x12, 0x39, 0x5d, 0x3d, + 0xc0, 0x85, 0x39, 0xce, 0x7c, 0x72, 0xf9, 0x63, 0x12, 0x39, 0x5d, 0x3d, 0xb7, 0x3a, 0xbf, 0xd1, 0x9e, 0x8e, 0xb8, 0x4e, 0x54, 0xe7, 0xa4, 0x12, 0x1b, 0xec, 0xc1, 0xf1, 0xcb, 0xf0, 0x40, 0xfa, 0x91, 0xcb, 0xff, 0x83, 0x01, 0xd4, 0x79, 0x16, 0x81, 0x39, 0x7d, 0x34, 0x70, 0x48, 0xe5, 0xfd, @@ -4362,18 +4362,18 @@ 0x7f, 0x74, 0x13, 0xcd, 0xd4, 0x39, 0x7f, 0xf8, 0x41, 0x2c, 0xda, 0xfa, 0x82, 0xf3, 0x9c, 0xbc, 0x39, 0xe3, 0x94, 0x87, 0xc8, 0x29, 0x35, 0x0a, 0x94, 0xa7, 0x23, 0x91, 0x00, 0x4a, 0x31, 0x0d, 0x52, 0x64, 0x2f, 0x99, - 0xd7, 0xa4, 0xde, 0x84, 0xa5, 0xfd, 0xca, 0x68, 0xf0, 0xf1, 0x39, 0x7f, + 0xd7, 0xa4, 0xde, 0x84, 0xa5, 0xfd, 0xf2, 0x68, 0xf0, 0xf1, 0x39, 0x7f, 0xf8, 0x63, 0x8e, 0xa3, 0x58, 0x9d, 0x80, 0x9c, 0xb9, 0xd8, 0x72, 0xe9, 0x9a, 0x1c, 0xa1, 0x36, 0x1c, 0x45, 0xaa, 0x48, 0xcd, 0xc3, 0x24, 0x79, - 0xb7, 0x36, 0xa9, 0xf5, 0x47, 0xda, 0xb4, 0x0e, 0x18, 0x77, 0x85, 0xd3, + 0xb7, 0xd6, 0xa9, 0xf5, 0x47, 0xda, 0xb4, 0x0e, 0x18, 0x77, 0x85, 0xd3, 0x5a, 0x80, 0xe4, 0x4b, 0x6c, 0x9e, 0x30, 0x29, 0x4a, 0x08, 0x0c, 0xe9, - 0xe6, 0x52, 0x3a, 0x95, 0x8f, 0x0d, 0x72, 0xe8, 0xbe, 0x95, 0xb4, 0x91, + 0xe6, 0x52, 0x3a, 0x95, 0x8f, 0x0d, 0x72, 0xe8, 0xb9, 0x95, 0xb4, 0x91, 0xb5, 0x4d, 0x38, 0x1f, 0xa9, 0x4f, 0x4c, 0x94, 0x31, 0xda, 0x41, 0x0b, 0xca, 0xe0, 0xfe, 0x57, 0x57, 0x0f, 0x09, 0xc1, 0x9d, 0x29, 0xdd, 0x26, 0xdf, 0xd3, 0xe7, 0x60, 0x87, 0xeb, 0x70, 0x8c, 0x69, 0x29, 0x55, 0x49, - 0x6c, 0xdc, 0x11, 0xaf, 0xd7, 0x37, 0xd7, 0xd2, 0xed, 0xea, 0xb8, 0xdf, - 0xfe, 0xe6, 0xc7, 0x97, 0x3c, 0xd2, 0xdd, 0xd6, 0x68, 0x9b, 0x17, 0xfb, - 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x55, 0xab, 0xfd, 0x29, 0x03, 0xc3, 0x12, + 0x6c, 0xdc, 0x11, 0xaf, 0xd7, 0xd7, 0xd7, 0xd2, 0xed, 0xea, 0xb8, 0xdf, + 0xfe, 0xfa, 0xc7, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x9b, 0x17, 0xfb, + 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x55, 0xab, 0xfd, 0x29, 0x03, 0xc3, 0x12, 0x39, 0x7d, 0x9d, 0x7f, 0x1c, 0xb7, 0x09, 0x87, 0xa8, 0x26, 0x77, 0xff, 0xfe, 0x94, 0x71, 0x84, 0xd2, 0xd1, 0x8f, 0x24, 0x1c, 0x0e, 0x2a, 0x72, 0xff, 0xf6, 0x92, 0x59, 0x2c, 0x79, 0x0c, 0x30, 0xe5, 0xfe, 0xd6, 0x2e, @@ -4382,131 +4382,131 @@ 0x3a, 0x92, 0x72, 0x28, 0xd7, 0xa4, 0x7e, 0xc2, 0xf6, 0xfb, 0x4c, 0xe8, 0x4e, 0x5f, 0xfd, 0xa9, 0x0e, 0x7b, 0x70, 0xcf, 0x2c, 0xe5, 0x41, 0xf3, 0x80, 0x8e, 0xf0, 0x70, 0x4e, 0x5e, 0x77, 0x59, 0xa2, 0xb4, 0x5f, 0x95, - 0xfb, 0x60, 0xf8, 0xe5, 0x2c, 0xf5, 0x10, 0xa2, 0xff, 0xf2, 0x7a, 0x50, - 0xbe, 0xa7, 0xb6, 0xff, 0x1c, 0xad, 0x1f, 0x5f, 0x12, 0x1b, 0xfc, 0x1f, - 0xf9, 0x66, 0x91, 0x53, 0x97, 0xff, 0xba, 0x8c, 0x85, 0xe3, 0x30, 0x7c, - 0xd0, 0xe5, 0xe9, 0x7d, 0x23, 0x97, 0xff, 0xf3, 0xa7, 0x04, 0x08, 0x24, - 0x9b, 0xdc, 0x72, 0x62, 0xce, 0x5f, 0xff, 0x2e, 0x35, 0x9f, 0xbb, 0x1e, + 0xe7, 0x60, 0xe4, 0xe5, 0x2c, 0xf5, 0x10, 0xa2, 0xff, 0xf2, 0x7a, 0x50, + 0xbe, 0xa7, 0xb6, 0xfc, 0x9c, 0xad, 0x1f, 0x5f, 0x12, 0x1b, 0xfc, 0x1f, + 0xfe, 0x66, 0x91, 0x53, 0x97, 0xff, 0xba, 0x8c, 0x85, 0xe3, 0x30, 0x7c, + 0xd0, 0xe5, 0xe9, 0x73, 0x23, 0x97, 0xff, 0xf3, 0xa7, 0x04, 0x08, 0x24, + 0x9b, 0xdc, 0x7c, 0x62, 0xce, 0x5f, 0xff, 0x2e, 0x35, 0x9f, 0xbb, 0x1e, 0x50, 0x8b, 0x39, 0x7f, 0xfd, 0x2d, 0xe0, 0xc3, 0x1f, 0x3d, 0xe8, 0x61, 0xcb, 0x7a, 0x11, 0x36, 0xe9, 0xd5, 0xd4, 0xc8, 0x3d, 0x0f, 0x9b, 0xff, 0xff, 0xd1, 0xc5, 0x3d, 0xbc, 0x55, 0x7d, 0x4f, 0x64, 0xc3, 0x0c, 0x9f, - 0x1b, 0x39, 0x7f, 0xa3, 0xcf, 0xde, 0x41, 0x83, 0x97, 0xd2, 0xf2, 0x4e, - 0x72, 0xfc, 0xa7, 0x86, 0x3f, 0x39, 0x5f, 0x1e, 0x67, 0x12, 0x3b, 0xfc, + 0x1b, 0x39, 0x7f, 0xa3, 0xcf, 0xdf, 0x81, 0x83, 0x97, 0xd2, 0xf2, 0x4e, + 0x72, 0xfc, 0xa7, 0x86, 0x3f, 0x39, 0x5c, 0x9e, 0x67, 0x12, 0x3b, 0xfc, 0xf2, 0xf2, 0x4f, 0xd4, 0x39, 0x50, 0x7b, 0x08, 0x4b, 0x7e, 0xce, 0xa6, 0x30, 0xe5, 0xf9, 0x3f, 0x62, 0x68, 0xe5, 0xff, 0xc2, 0xe8, 0xbe, 0xb8, 0x27, 0xd2, 0x1c, 0xa9, 0xd1, 0x22, 0x12, 0x6e, 0x94, 0x5f, 0xe9, 0x46, 0xa7, 0x8d, 0x4e, 0x72, 0xfa, 0x5a, 0xc6, 0x1c, 0xbd, 0x9a, 0xfc, 0xe5, - 0xfa, 0x6c, 0x0b, 0x1a, 0xce, 0x5f, 0xc3, 0x0d, 0xfd, 0x2d, 0x9c, 0xaf, - 0x91, 0x34, 0x84, 0x53, 0x0e, 0xf0, 0x16, 0x54, 0x26, 0x21, 0x90, 0xcf, - 0xbf, 0xff, 0xff, 0xb1, 0x17, 0x9e, 0x81, 0xf6, 0xf9, 0x42, 0x07, 0x19, - 0xcb, 0x50, 0x92, 0x7d, 0x9c, 0xbf, 0xb3, 0xce, 0x3f, 0x80, 0xe5, 0xfd, - 0xde, 0x49, 0x3b, 0x89, 0xcb, 0xfd, 0x0c, 0xd8, 0x45, 0xdb, 0x39, 0x7c, - 0xff, 0xb8, 0x4e, 0x54, 0x91, 0x63, 0x85, 0xa2, 0x5f, 0xb3, 0x3b, 0x73, + 0xfa, 0x6c, 0x0b, 0x1a, 0xce, 0x5f, 0xc3, 0x0d, 0xf3, 0x2d, 0x9c, 0xae, + 0x51, 0x34, 0x84, 0x53, 0x0e, 0xf0, 0x16, 0x54, 0x26, 0x21, 0x90, 0xcf, + 0xbf, 0xff, 0xff, 0xb1, 0x17, 0x9e, 0x81, 0xf6, 0xfe, 0x42, 0x07, 0x19, + 0xf3, 0x50, 0x92, 0x7d, 0x9c, 0xbf, 0xb3, 0xce, 0x3f, 0x80, 0xe5, 0xfd, + 0xdf, 0x89, 0x3b, 0x89, 0xcb, 0xfd, 0x0c, 0xd8, 0x45, 0xdb, 0x39, 0x7c, + 0xff, 0xb8, 0x4e, 0x54, 0x91, 0x63, 0x85, 0xa2, 0x5f, 0xb3, 0x3b, 0x7d, 0xe1, 0x99, 0x49, 0x91, 0x1d, 0xe4, 0xf0, 0xa9, 0x09, 0x0e, 0x43, 0x69, - 0x52, 0x45, 0x9b, 0xfc, 0x94, 0x91, 0x9f, 0x68, 0xa5, 0x8f, 0x7d, 0x86, + 0x52, 0x45, 0x9b, 0xf2, 0x94, 0x91, 0x9f, 0x68, 0xa5, 0x8f, 0x7d, 0x86, 0xc3, 0xc2, 0xc4, 0x63, 0x41, 0xd9, 0x3f, 0xa3, 0x39, 0xbf, 0x69, 0x6e, - 0xeb, 0x34, 0x58, 0x0b, 0xf3, 0xad, 0x4e, 0xcc, 0x72, 0xdc, 0xf0, 0xf7, + 0xeb, 0x34, 0x58, 0x0b, 0xf3, 0xad, 0x4e, 0xcc, 0x72, 0xdf, 0x70, 0xf7, 0xb6, 0x69, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0x9d, 0x57, 0xff, 0xfb, 0xb1, - 0x38, 0x71, 0x9c, 0xf7, 0xbc, 0xea, 0x6c, 0x13, 0x9c, 0xbf, 0x73, 0x63, - 0xcb, 0x9e, 0x22, 0x66, 0x63, 0x4b, 0xff, 0xfd, 0x02, 0x08, 0xf6, 0xf0, - 0x79, 0xff, 0xfc, 0x75, 0xe7, 0x39, 0x79, 0x58, 0x61, 0xcb, 0xe7, 0x5a, - 0x8c, 0x39, 0x7a, 0x5b, 0xe6, 0xa9, 0xe0, 0x71, 0x1d, 0xbf, 0x69, 0x6e, - 0xeb, 0x34, 0x5b, 0x2b, 0xfb, 0xcf, 0xde, 0x41, 0x83, 0x97, 0xff, 0xf4, - 0xb9, 0xee, 0x13, 0x02, 0x99, 0xbc, 0xf0, 0xc1, 0xca, 0x84, 0x44, 0x39, - 0x7d, 0xfa, 0x50, 0x9c, 0x60, 0xe5, 0xff, 0x46, 0xf9, 0xf5, 0x16, 0xfa, + 0x38, 0x71, 0x9f, 0x77, 0xbc, 0xea, 0x6c, 0x13, 0x9c, 0xbf, 0x7d, 0x63, + 0xcb, 0xee, 0x22, 0x66, 0x63, 0x4b, 0xff, 0xfd, 0x02, 0x08, 0xf6, 0xf0, + 0x7e, 0xff, 0xfc, 0x75, 0xe7, 0x39, 0x79, 0x58, 0x61, 0xcb, 0xe7, 0x5a, + 0x8c, 0x39, 0x7a, 0x5b, 0xfa, 0xa9, 0xe0, 0x71, 0x1d, 0xbf, 0x69, 0x6e, + 0xeb, 0x34, 0x5b, 0x2b, 0xfb, 0xcf, 0xdf, 0x81, 0x83, 0x97, 0xff, 0xf4, + 0xbe, 0xee, 0x13, 0x02, 0x99, 0xbc, 0xf0, 0xc1, 0xca, 0x84, 0x44, 0x39, + 0x7d, 0xfa, 0x50, 0x9c, 0x60, 0xe5, 0xff, 0x46, 0xfe, 0xf5, 0x16, 0xfa, 0x39, 0x50, 0x7c, 0x5f, 0x94, 0x5f, 0xf4, 0x4a, 0x35, 0x3c, 0x6a, 0x73, - 0x96, 0xe7, 0x89, 0xcd, 0xb2, 0x17, 0x8f, 0x08, 0x31, 0x22, 0xbf, 0xf0, - 0xf3, 0x60, 0x13, 0xc2, 0xfc, 0x07, 0x2f, 0xfe, 0x06, 0xf9, 0xe6, 0x9f, - 0x7d, 0x79, 0x1c, 0xb9, 0xff, 0xc4, 0x44, 0x7e, 0x85, 0x77, 0xcb, 0x39, + 0x96, 0xfb, 0x89, 0xcd, 0xb2, 0x17, 0x8f, 0x08, 0x31, 0x22, 0xbf, 0xf0, + 0xfd, 0x60, 0x13, 0xc2, 0xfc, 0x07, 0x2f, 0xfe, 0x06, 0xfe, 0xe6, 0x9f, + 0x7d, 0x79, 0x1c, 0xb9, 0xff, 0xc4, 0x44, 0x7e, 0x85, 0x77, 0x2b, 0x39, 0x7c, 0xb7, 0x75, 0x9a, 0x2e, 0x65, 0x98, 0x72, 0xb4, 0x6f, 0xdb, 0x2e, - 0xbf, 0xda, 0x1c, 0xfb, 0xf4, 0x91, 0xcb, 0xa6, 0x61, 0xca, 0x39, 0x6e, - 0x70, 0x8d, 0x0c, 0x57, 0x42, 0x26, 0xcd, 0x1a, 0x0c, 0x5f, 0xb4, 0xb7, - 0x75, 0x9a, 0x2e, 0xf5, 0xfe, 0x97, 0x3d, 0xeb, 0x48, 0xd9, 0xcb, 0x73, - 0xc3, 0xeb, 0x73, 0x4b, 0xee, 0x6a, 0x87, 0xf3, 0x95, 0x0f, 0xd6, 0x85, - 0x97, 0xb0, 0x00, 0xb3, 0x8f, 0x96, 0x92, 0x95, 0xc3, 0xa8, 0xdc, 0x99, + 0xbf, 0xda, 0x1c, 0xe7, 0xf4, 0x91, 0xcb, 0xa6, 0x61, 0xca, 0x39, 0x6f, + 0xb0, 0x8d, 0x0c, 0x57, 0x42, 0x26, 0xcd, 0x1a, 0x0c, 0x5f, 0xb4, 0xb7, + 0x75, 0x9a, 0x2e, 0xf5, 0xfe, 0x97, 0xdd, 0xeb, 0x48, 0xd9, 0xcb, 0x7d, + 0xc3, 0xeb, 0x73, 0x4b, 0xef, 0xaa, 0x87, 0xf3, 0x95, 0x0f, 0xd6, 0x85, + 0x97, 0xb0, 0x00, 0xb3, 0x8e, 0x56, 0x92, 0x95, 0xc3, 0xa8, 0xdc, 0x99, 0x0c, 0x2e, 0xa2, 0x3c, 0x28, 0xff, 0x8f, 0x50, 0x61, 0xab, 0xb8, 0x7f, - 0xfa, 0x17, 0xaa, 0x14, 0x5f, 0xf9, 0xb7, 0x19, 0xf6, 0x83, 0xf4, 0x8e, - 0x5f, 0xfd, 0x93, 0xe3, 0x7d, 0xcd, 0xe2, 0x09, 0xcb, 0x93, 0x9f, 0x51, + 0xfa, 0x17, 0xaa, 0x14, 0x5f, 0xf9, 0xb7, 0x19, 0xf6, 0x83, 0xcc, 0x8e, + 0x5f, 0xfd, 0x93, 0xe3, 0x7d, 0xcd, 0xe2, 0x09, 0xcb, 0x93, 0xef, 0x51, 0x06, 0x28, 0x17, 0xed, 0xed, 0x8f, 0x23, 0x97, 0xff, 0xff, 0xfe, 0xea, 0x75, 0x20, 0x7c, 0x2e, 0xae, 0x78, 0x1e, 0x4f, 0x6f, 0xa9, 0xa8, 0x9d, - 0xf4, 0xb3, 0x97, 0x6e, 0x0e, 0x5f, 0xfd, 0xf2, 0xc0, 0xff, 0x7b, 0x30, - 0x55, 0x39, 0x78, 0x5f, 0x9c, 0x26, 0x38, 0xb2, 0x8d, 0xc2, 0x63, 0xc2, + 0xf4, 0xb3, 0x97, 0x6e, 0x0e, 0x5f, 0xfd, 0xca, 0xc0, 0xfc, 0xfb, 0x30, + 0x55, 0x39, 0x78, 0x5f, 0xec, 0x26, 0x38, 0xb2, 0x8d, 0xc2, 0x63, 0xc2, 0xd7, 0x80, 0xec, 0x39, 0x7e, 0xce, 0x0f, 0x42, 0xa7, 0x2d, 0xc0, 0x72, 0xa7, 0x37, 0xf8, 0x57, 0x5a, 0x3f, 0xc1, 0x5b, 0xbf, 0xf6, 0xdd, 0x5e, - 0xa4, 0x08, 0x20, 0xe5, 0xff, 0xba, 0xfe, 0x7e, 0xfd, 0x2c, 0xf1, 0xca, + 0xa4, 0x08, 0x20, 0xe5, 0xff, 0xba, 0xfe, 0x7e, 0xf3, 0x2c, 0xf1, 0xca, 0xc3, 0xfc, 0x43, 0xdb, 0x9f, 0xf3, 0x97, 0xff, 0xff, 0x85, 0xdb, 0x1c, 0xf7, 0xb2, 0x78, 0x17, 0x57, 0x6c, 0x8c, 0x10, 0x9c, 0xbd, 0x8a, 0x6c, 0xe5, 0x62, 0x2a, 0x74, 0x2f, 0xc0, 0xeb, 0x7f, 0xbb, 0x81, 0x4e, 0x3a, 0xc3, 0x97, 0xf9, 0xe5, 0xac, 0x68, 0x9f, 0x9c, 0xbc, 0xee, 0xb3, 0x44, 0xae, 0xbf, 0xca, 0xb8, 0xff, 0xec, 0xe9, 0xca, 0x59, 0xee, 0x21, 0x45, - 0xfe, 0xf8, 0x5d, 0x57, 0xf4, 0x8e, 0x5f, 0xfd, 0xdc, 0x92, 0xfa, 0x81, + 0xfe, 0xe4, 0x5d, 0x57, 0xf4, 0x8e, 0x5f, 0xfd, 0xdc, 0x92, 0xfa, 0x81, 0x81, 0xf1, 0xca, 0x43, 0xf7, 0xf1, 0xa5, 0x49, 0x37, 0xe0, 0x9a, 0x6a, - 0x12, 0x23, 0x09, 0x8b, 0xfd, 0x1a, 0x79, 0x3f, 0xd2, 0x39, 0x7f, 0xff, - 0xfd, 0xa7, 0x15, 0x23, 0xfc, 0x97, 0x63, 0x88, 0x63, 0x9e, 0x08, 0x25, - 0x9b, 0x39, 0x74, 0xa7, 0x39, 0x7f, 0xff, 0x9f, 0xed, 0xe6, 0xbd, 0xe7, + 0x12, 0x23, 0x09, 0x8b, 0xfd, 0x1a, 0x79, 0x3f, 0x32, 0x39, 0x7f, 0xff, + 0xfd, 0xa7, 0x15, 0x23, 0xfc, 0x97, 0x63, 0x88, 0x63, 0xee, 0x08, 0x25, + 0x9b, 0x39, 0x74, 0xa7, 0x39, 0x7f, 0xff, 0x9f, 0x9d, 0xe6, 0xbd, 0xe7, 0x9d, 0x46, 0x07, 0xa8, 0xa9, 0xcb, 0xfe, 0xc4, 0xe2, 0x31, 0x9a, 0x91, - 0xcb, 0xff, 0xf7, 0xa5, 0x8d, 0x6e, 0x3f, 0xfd, 0xed, 0x46, 0x36, 0x71, - 0xb3, 0x71, 0x7e, 0xfb, 0xdd, 0x8f, 0xce, 0x53, 0xa2, 0x54, 0x0d, 0x77, - 0xff, 0xa6, 0x18, 0xf6, 0xfd, 0xf2, 0xd0, 0x67, 0x39, 0x7f, 0xce, 0xd8, + 0xcb, 0xff, 0xf7, 0xa5, 0x8d, 0x6e, 0x3f, 0xf3, 0xed, 0x46, 0x36, 0x71, + 0xb3, 0x71, 0x7e, 0xe7, 0xdd, 0x8f, 0xce, 0x53, 0xa2, 0x54, 0x0d, 0x77, + 0xff, 0xa6, 0x18, 0xf6, 0xfd, 0xca, 0xd0, 0x67, 0x39, 0x7f, 0xce, 0xd8, 0x7b, 0x13, 0xe3, 0x67, 0x29, 0x11, 0x0e, 0x29, 0x97, 0xff, 0xec, 0x4f, - 0xf1, 0x89, 0xed, 0xc3, 0x1f, 0xef, 0x1c, 0xbf, 0xe8, 0x67, 0xb2, 0x69, + 0xf1, 0x89, 0xed, 0xc3, 0x1f, 0x9f, 0x1c, 0xbf, 0xe8, 0x67, 0xb2, 0x69, 0x27, 0x8e, 0x54, 0x91, 0x1d, 0xe5, 0x5b, 0xe0, 0x3e, 0xa4, 0x72, 0xfe, 0x18, 0x9f, 0xf7, 0xf1, 0xcb, 0xfc, 0xe1, 0x53, 0x82, 0x06, 0x47, 0x2d, 0x0b, 0x3e, 0x46, 0x17, 0x5f, 0xff, 0xe4, 0xf3, 0xb1, 0xc7, 0xfe, 0xb6, 0xe3, 0x3a, 0xd2, 0x73, 0x94, 0x14, 0xc3, 0xd2, 0x10, 0xce, 0x4f, 0x7f, 0xc0, 0xfd, 0x8f, 0x2d, 0xe8, 0x27, 0x2f, 0xff, 0xf6, 0x20, 0xfb, 0x07, - 0x90, 0xb8, 0x60, 0x67, 0x8d, 0x1c, 0xb6, 0x79, 0x13, 0x3c, 0x4e, 0xef, - 0xfb, 0xef, 0xf3, 0x59, 0x9e, 0xd9, 0xca, 0x0a, 0xb1, 0x2c, 0x85, 0x7f, + 0xe0, 0xb8, 0x60, 0x67, 0x8d, 0x1c, 0xb6, 0x79, 0x13, 0x3c, 0x4e, 0xef, + 0xfb, 0x9f, 0xf3, 0x59, 0x9e, 0xd9, 0xca, 0x0a, 0xb1, 0x2c, 0x85, 0x7f, 0x63, 0x32, 0x18, 0x66, 0xa8, 0x55, 0x7f, 0xec, 0xef, 0x5e, 0x5f, 0xeb, - 0x3e, 0x39, 0x7f, 0xd9, 0xf6, 0xc3, 0x0e, 0x33, 0x9c, 0xbf, 0xe7, 0x96, + 0x39, 0x39, 0x7f, 0xd9, 0xce, 0xc3, 0x0e, 0x33, 0x9c, 0xbf, 0xe7, 0x96, 0xfb, 0x1a, 0x50, 0x27, 0x2a, 0x48, 0xb3, 0xc4, 0x0f, 0x1c, 0xdf, 0xfd, 0xe4, 0xe2, 0x9e, 0x9a, 0x50, 0x3e, 0x39, 0x7f, 0xf9, 0xf2, 0x5d, 0xc4, - 0x1c, 0xfd, 0xa6, 0x1c, 0xbc, 0xf2, 0xe7, 0x0c, 0xae, 0x19, 0x42, 0x74, - 0x30, 0xc9, 0xc8, 0xec, 0x3e, 0x47, 0xd1, 0x9b, 0x21, 0x01, 0xf8, 0xc0, + 0x1c, 0xfd, 0xa6, 0x1c, 0xbc, 0xf2, 0xfb, 0x0c, 0xae, 0x19, 0x42, 0x74, + 0x30, 0xc9, 0xc8, 0xec, 0x39, 0x47, 0xd1, 0x9b, 0x21, 0x01, 0xf8, 0xc0, 0xc6, 0x65, 0xb9, 0x77, 0x7e, 0x8c, 0x39, 0x42, 0xfe, 0x04, 0x6b, 0xff, - 0xd9, 0xde, 0x63, 0x81, 0x41, 0xf6, 0x74, 0xe5, 0xef, 0x40, 0x4a, 0x5f, - 0xfe, 0xeb, 0xa7, 0xa2, 0x49, 0xa9, 0xc1, 0xf9, 0x4b, 0xfc, 0xeb, 0xe6, - 0x1d, 0x70, 0xfc, 0xe0, 0xf9, 0xf6, 0x39, 0x6e, 0x61, 0x67, 0x79, 0xae, - 0x34, 0xb6, 0x52, 0xec, 0x7d, 0x0f, 0x4e, 0x30, 0xb0, 0xbf, 0xfd, 0xcd, - 0x8f, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x30, 0xaf, 0xff, 0xec, 0xe2, - 0xe1, 0xec, 0x73, 0xf7, 0x70, 0x20, 0xf6, 0xce, 0x5f, 0xfe, 0xd3, 0xff, - 0xcd, 0x5f, 0x49, 0xb8, 0xdc, 0x8e, 0x5d, 0x9c, 0xc5, 0x15, 0xea, 0x2f, - 0xdc, 0xce, 0x27, 0x2f, 0xfe, 0xe1, 0x33, 0xe9, 0x01, 0xfc, 0x31, 0x23, - 0x97, 0xe6, 0xad, 0xab, 0x6a, 0x5a, 0x35, 0x47, 0x2f, 0xd8, 0xce, 0x5f, - 0x35, 0x9c, 0xbf, 0xa1, 0x99, 0xfc, 0x71, 0x39, 0x41, 0x3d, 0xde, 0x97, + 0xd9, 0xdf, 0xa3, 0x81, 0x41, 0xf6, 0x74, 0xe5, 0xef, 0x40, 0x4a, 0x5f, + 0xfe, 0xeb, 0xa7, 0xa2, 0x49, 0xa9, 0xc1, 0xf9, 0x4b, 0xfc, 0xeb, 0xfa, + 0x1d, 0x70, 0xff, 0x60, 0xf9, 0xf6, 0x39, 0x6f, 0xa1, 0x67, 0x79, 0xae, + 0x34, 0xb6, 0x52, 0xec, 0x7d, 0x0f, 0x4e, 0x30, 0xb0, 0xbf, 0xfd, 0xf5, + 0x8f, 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x30, 0xaf, 0xff, 0xec, 0xe2, + 0xe1, 0xec, 0x7d, 0xf7, 0x70, 0x20, 0xf6, 0xce, 0x5f, 0xfe, 0xd3, 0xff, + 0xf5, 0x5f, 0x49, 0xb8, 0xdc, 0x8e, 0x5d, 0x9f, 0x45, 0x15, 0xea, 0x2f, + 0xdc, 0xce, 0x27, 0x2f, 0xfe, 0xe1, 0x33, 0x99, 0x01, 0xfc, 0x31, 0x23, + 0x97, 0xe6, 0xad, 0xab, 0x6a, 0x5a, 0x35, 0x47, 0x2f, 0xd8, 0xcf, 0x9c, + 0xb5, 0x9c, 0xbf, 0xa1, 0x99, 0xfc, 0x71, 0x39, 0x41, 0x3d, 0xde, 0x97, 0x5f, 0xed, 0x62, 0xe3, 0xf5, 0x18, 0x72, 0xfe, 0x8d, 0x43, 0x13, 0x47, 0x2f, 0xdd, 0x80, 0xa2, 0xa7, 0x29, 0x11, 0x57, 0xa2, 0x26, 0x1a, 0xf0, 0x16, 0x5e, 0xe2, 0xfb, 0x39, 0x7f, 0xa1, 0xe7, 0xf2, 0xaf, 0xa3, 0x97, 0xe7, 0xd4, 0x9d, 0x87, 0x2b, 0x0f, 0xe4, 0x47, 0x80, 0x69, 0x7f, 0xb7, 0x18, 0x21, 0xec, 0x1c, 0xbf, 0xa3, 0x04, 0x3d, 0x83, 0x97, 0x81, 0xa9, - 0xb9, 0x1e, 0xe6, 0xcc, 0x6f, 0xff, 0x69, 0x01, 0x8a, 0xe7, 0x81, 0x1f, - 0x04, 0xe5, 0xff, 0xf9, 0x35, 0xd7, 0xe4, 0x1c, 0x97, 0x63, 0x88, 0x60, + 0xbe, 0x1e, 0xe6, 0xcc, 0x6f, 0xff, 0x69, 0x01, 0x8a, 0xe7, 0x81, 0x1c, + 0x84, 0xe5, 0xff, 0xf9, 0x35, 0xd7, 0xf8, 0x1c, 0x97, 0x63, 0x88, 0x60, 0xe5, 0xff, 0x36, 0xa7, 0x61, 0x7d, 0x49, 0x8e, 0x5f, 0x01, 0x98, 0x13, - 0x96, 0xcf, 0x8f, 0x7b, 0x80, 0xf2, 0xfe, 0x8d, 0x44, 0xb7, 0x87, 0x29, + 0x96, 0xce, 0x4f, 0x7b, 0x80, 0xf2, 0xfe, 0x8d, 0x44, 0xb7, 0x87, 0x29, 0x69, 0xc7, 0xe8, 0xdf, 0xa9, 0x63, 0x0b, 0x6f, 0x15, 0xdf, 0xfe, 0x85, 0xec, 0x1e, 0x4e, 0xa2, 0xbd, 0x43, 0x97, 0xf3, 0x23, 0x07, 0xcd, 0x0e, - 0x5b, 0x67, 0x2f, 0xd1, 0x83, 0xe6, 0x87, 0x2f, 0x6d, 0xfe, 0xe4, 0x7c, + 0x5b, 0x67, 0x2f, 0xd1, 0x83, 0xe6, 0x87, 0x2f, 0x6d, 0xf9, 0xf8, 0x7c, 0xf3, 0x17, 0x30, 0x46, 0x98, 0x8f, 0x5f, 0x42, 0xc6, 0xff, 0x9a, 0xf0, 0x3d, 0x86, 0xb1, 0x83, 0x94, 0x87, 0xca, 0xe5, 0x17, 0xfd, 0xa9, 0xd7, 0xd4, 0xe8, 0x3c, 0x72, 0xba, 0x7b, 0x6e, 0x41, 0x7f, 0x7a, 0x19, 0xc7, 0xf9, 0x1c, 0xbb, 0xc8, 0x72, 0xa4, 0x78, 0xea, 0x98, 0xde, 0xd0, 0x36, 0x72, 0xff, 0xfb, 0xb0, 0x39, 0xee, 0xe7, 0xbb, 0x00, 0xe1, 0xce, 0x5f, - 0xff, 0xe6, 0xf8, 0x3d, 0x9d, 0xe4, 0x39, 0x3a, 0x60, 0xfd, 0x2d, 0x9c, + 0xff, 0xe6, 0xf8, 0x3d, 0x9d, 0xf8, 0x39, 0x3a, 0x60, 0xf3, 0x2d, 0x9c, 0xbf, 0x37, 0xec, 0xea, 0xce, 0x56, 0x22, 0x41, 0xd9, 0xeb, 0x13, 0x21, 0x41, 0xd1, 0x87, 0x1d, 0xff, 0xef, 0x0b, 0xff, 0xdc, 0x40, 0x83, 0xdb, 0x39, 0x7d, 0xc7, 0x03, 0x07, 0x2f, 0xfa, 0x27, 0x52, 0x5d, 0x03, 0xce, - 0x72, 0xa1, 0x15, 0x38, 0x95, 0xa2, 0x3b, 0xff, 0xb3, 0xe9, 0x72, 0xeb, - 0xae, 0x04, 0x27, 0x2f, 0x92, 0x3e, 0xd9, 0xcb, 0xf2, 0x9e, 0x18, 0xfc, + 0x72, 0xa1, 0x15, 0x38, 0x95, 0xa2, 0x3b, 0xff, 0xb3, 0x99, 0x7c, 0xeb, + 0xae, 0x04, 0x27, 0x2f, 0x92, 0x39, 0xd9, 0xcb, 0xf2, 0x9e, 0x18, 0xfc, 0xe5, 0x78, 0xf2, 0xf8, 0x91, 0x5f, 0x7b, 0xd8, 0xd9, 0xcb, 0xff, 0xd1, - 0xef, 0xe2, 0x59, 0xf7, 0xa7, 0x03, 0x67, 0x2f, 0x6d, 0xff, 0x39, 0x50, + 0xef, 0xe2, 0x59, 0xcf, 0xa7, 0x03, 0x67, 0x2f, 0x6d, 0xff, 0x39, 0x50, 0x8b, 0x2c, 0x24, 0x42, 0x3f, 0x27, 0x5c, 0xf2, 0x39, 0x7f, 0xf9, 0x37, - 0x12, 0xe5, 0x9d, 0x4d, 0x75, 0xce, 0x53, 0x59, 0xf0, 0x74, 0x5a, 0xfe, - 0x7f, 0xf5, 0xa4, 0xd1, 0xcb, 0xde, 0xe5, 0x87, 0x2b, 0xf3, 0xcc, 0x50, - 0xba, 0xfb, 0xa0, 0xfb, 0xc7, 0x2f, 0xfd, 0xd4, 0xf2, 0x63, 0x07, 0x27, + 0x12, 0xf9, 0x9d, 0x4d, 0x75, 0xce, 0x53, 0x59, 0xf0, 0x74, 0x5a, 0xfe, + 0x7f, 0xf5, 0xa4, 0xd1, 0xcb, 0xde, 0xf9, 0x87, 0x2b, 0xf3, 0xcc, 0x50, + 0xba, 0xfb, 0xa0, 0xe7, 0xc7, 0x2f, 0xfd, 0xd4, 0xf2, 0x63, 0x07, 0x27, 0x39, 0x7f, 0x6d, 0x15, 0x63, 0xf8, 0xe5, 0xff, 0xb8, 0xc2, 0xb2, 0x41, - 0x8d, 0x41, 0xcb, 0xff, 0xff, 0x6b, 0x38, 0xc0, 0xfb, 0x92, 0x83, 0x1d, - 0x74, 0xf4, 0x7b, 0x67, 0x2f, 0xe1, 0xcd, 0xf2, 0x5f, 0x0c, 0x72, 0x96, - 0x9a, 0x67, 0xc7, 0xa8, 0x5d, 0xa3, 0xfe, 0x2d, 0xd7, 0xdc, 0xb8, 0xf0, + 0x8d, 0x41, 0xcb, 0xff, 0xff, 0x6b, 0x38, 0xc0, 0xfb, 0xe2, 0x83, 0x1d, + 0x74, 0xf4, 0x7b, 0x67, 0x2f, 0xe1, 0xcd, 0xfc, 0x5f, 0x0c, 0x72, 0x96, + 0x9a, 0x67, 0x27, 0xa8, 0x5d, 0xa3, 0xfe, 0x2d, 0xd7, 0xdf, 0x38, 0xf0, 0x4e, 0x72, 0x82, 0x9f, 0x46, 0x46, 0xe0, 0xaa, 0x6d, 0x9a, 0xce, 0x5f, 0x99, 0xac, 0x0f, 0x8e, 0x5d, 0xec, 0x39, 0x7f, 0xc1, 0x81, 0x8f, 0xdd, 0xf8, 0x0e, 0x5f, 0xb7, 0x9e, 0xd4, 0x1c, 0xbf, 0xfd, 0xc3, 0x8c, 0x31, @@ -4514,82 +4514,82 @@ 0x73, 0xac, 0xe5, 0xfc, 0x93, 0x3a, 0xf7, 0x23, 0x94, 0xb3, 0xc4, 0xe8, 0xb5, 0xff, 0xfe, 0xea, 0x08, 0x75, 0x8b, 0xec, 0x77, 0x35, 0xa8, 0x54, 0xe5, 0xf8, 0x1c, 0x09, 0x8c, 0x39, 0x7e, 0xf3, 0xb1, 0x3c, 0x72, 0x95, - 0x3d, 0x11, 0x2a, 0xbf, 0xf2, 0x78, 0x1a, 0x7d, 0xf2, 0x67, 0x8e, 0x54, + 0x3d, 0x11, 0x2a, 0xbf, 0xf2, 0x78, 0x1a, 0x7d, 0xfc, 0x67, 0x8e, 0x54, 0x1f, 0x1b, 0x91, 0x5f, 0xf6, 0x26, 0x30, 0x72, 0x77, 0x39, 0x7e, 0x8f, 0x6f, 0xf0, 0x1c, 0xa6, 0xa9, 0x59, 0x9c, 0x0a, 0x64, 0x3a, 0xd6, 0xff, 0x31, 0x17, 0x63, 0x14, 0x12, 0x0f, 0x1b, 0x5f, 0xff, 0xba, 0x39, 0xee, - 0xa6, 0x7d, 0xec, 0xe3, 0x1b, 0x39, 0x7c, 0xfb, 0xf4, 0xe7, 0x2f, 0xfe, + 0xa6, 0x73, 0xec, 0xe3, 0x1b, 0x39, 0x7c, 0xfb, 0xf4, 0xe7, 0x2f, 0xfe, 0x71, 0xec, 0x20, 0x53, 0x79, 0x23, 0x97, 0xa3, 0xf5, 0x0e, 0x5f, 0xd9, 0xc7, 0xa9, 0xfc, 0xc7, 0x2b, 0x13, 0x09, 0x55, 0x59, 0xc8, 0xc5, 0x07, 0x63, 0xd7, 0xdd, 0x8d, 0xc1, 0xcb, 0xca, 0x07, 0x0e, 0x5e, 0xe1, 0xf7, - 0xc3, 0x1c, 0xa0, 0x9f, 0x2b, 0x90, 0xec, 0x76, 0xfb, 0x93, 0x39, 0x2c, + 0xc3, 0x1c, 0xa0, 0x9f, 0x2b, 0x90, 0xec, 0x76, 0xfb, 0xe3, 0x3e, 0x2c, 0xe5, 0xec, 0x58, 0x4e, 0x5f, 0x7b, 0x07, 0xf3, 0x97, 0xf3, 0xb7, 0x1e, 0xc9, 0xce, 0x56, 0x1f, 0x62, 0x0e, 0x09, 0x15, 0xf3, 0x73, 0x6e, 0x0e, - 0x5f, 0xf9, 0xfd, 0xb0, 0xe9, 0xfd, 0xd0, 0x1c, 0xaf, 0x8f, 0x8c, 0x49, - 0x2d, 0xcd, 0xaa, 0x6d, 0x28, 0x78, 0x61, 0x96, 0xa0, 0x93, 0x11, 0xa3, - 0x86, 0x17, 0x19, 0x28, 0x61, 0x72, 0x81, 0x3e, 0x68, 0x9a, 0x34, 0x4d, + 0x5f, 0xf9, 0xfd, 0xb0, 0xe9, 0xfd, 0xd0, 0x1c, 0xae, 0x4f, 0x8c, 0x49, + 0x2d, 0xf5, 0xaa, 0x6d, 0x28, 0x78, 0x61, 0x96, 0xa0, 0x93, 0x11, 0xa3, + 0x86, 0x17, 0x19, 0x28, 0x61, 0x72, 0x81, 0x39, 0x68, 0x9a, 0x34, 0x4d, 0x43, 0x71, 0x85, 0xdd, 0x8d, 0x0d, 0xe1, 0x35, 0xfb, 0x88, 0xca, 0x0c, 0xdc, 0xb6, 0xaf, 0x47, 0x14, 0x08, 0x57, 0x36, 0x5c, 0xd2, 0x12, 0x6a, - 0x42, 0x3e, 0xff, 0xfb, 0x49, 0xf4, 0xb6, 0x9e, 0xec, 0x6b, 0xd0, 0x72, + 0x42, 0x3e, 0xff, 0xfb, 0x49, 0xcc, 0xb6, 0x9e, 0xec, 0x6b, 0xd0, 0x72, 0xf3, 0xba, 0xcd, 0x15, 0x72, 0xfe, 0x75, 0x3b, 0xd7, 0x61, 0xca, 0x59, 0xeb, 0x74, 0xa2, 0xfe, 0x4d, 0x75, 0xd4, 0x61, 0xca, 0xd1, 0xe8, 0x74, 0x8a, 0xf8, 0x78, 0x36, 0xe7, 0x2f, 0x6a, 0x18, 0x72, 0xff, 0x46, 0xbd, - 0x03, 0x1f, 0x9c, 0xbf, 0xdc, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0x3c, 0x5f, + 0x03, 0x1f, 0x9c, 0xbf, 0xdf, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x3c, 0x5f, 0xf6, 0x07, 0x3a, 0x9a, 0xeb, 0x9c, 0xa9, 0x1f, 0xc3, 0x10, 0x6f, 0xfa, 0x25, 0x1a, 0x9e, 0x35, 0x39, 0xcb, 0xfe, 0xf2, 0x03, 0x87, 0xc9, 0x4f, 0x31, 0xcb, 0xf8, 0x73, 0xdb, 0xc6, 0xce, 0x54, 0x1f, 0x6b, 0xa0, 0x5f, - 0xf7, 0xcb, 0x4d, 0xf5, 0x3c, 0x87, 0x2f, 0xde, 0xf6, 0x0f, 0xe7, 0x2f, - 0xf7, 0x03, 0x86, 0x30, 0x28, 0x72, 0xdc, 0xc2, 0xae, 0x03, 0x21, 0xec, + 0xf7, 0x2b, 0x4d, 0xf5, 0x3c, 0x87, 0x2f, 0xde, 0xf6, 0x0f, 0xe7, 0x2f, + 0xf7, 0x03, 0x86, 0x30, 0x28, 0x72, 0xdf, 0x42, 0xae, 0x03, 0x21, 0xec, 0x84, 0x5a, 0x24, 0xe8, 0xe3, 0xc2, 0xa8, 0x48, 0xb7, 0x0a, 0x7f, 0x10, 0x28, 0x73, 0xc0, 0x51, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0xb0, 0x57, 0x95, 0x89, 0xce, 0x5f, 0xff, 0xc2, 0x07, 0x9d, 0x98, 0xd0, 0x1a, 0xcd, 0x49, 0x49, 0x1c, 0xbf, 0x60, 0xe7, 0xb6, 0x72, 0xff, 0x69, 0xd8, 0xa6, 0x9f, - 0xe3, 0x96, 0xe7, 0x89, 0x86, 0x2a, 0x68, 0xb1, 0xe7, 0x5f, 0x50, 0x9a, - 0xff, 0x73, 0xcd, 0x2d, 0xdd, 0x66, 0x8b, 0x29, 0x7e, 0xd2, 0xdd, 0xd6, - 0x68, 0xb4, 0xd7, 0xfc, 0xe1, 0xeb, 0xcd, 0xd4, 0x61, 0xcb, 0x73, 0xc3, + 0x93, 0x96, 0xfb, 0x89, 0x86, 0x2a, 0x68, 0xb1, 0xe7, 0x5f, 0x50, 0x9a, + 0xff, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x8b, 0x29, 0x7e, 0xd2, 0xdd, 0xd6, + 0x68, 0xb4, 0xd7, 0xfc, 0xe1, 0xeb, 0xcd, 0xd4, 0x61, 0xcb, 0x7d, 0xc3, 0xed, 0x61, 0xa5, 0xfb, 0x85, 0xda, 0x8b, 0x54, 0xd5, 0x35, 0x67, 0x2f, 0xfb, 0x86, 0xea, 0x36, 0x17, 0x75, 0x9c, 0xbf, 0x70, 0xbf, 0x09, 0xbc, 0x83, 0x97, 0xf9, 0x46, 0x67, 0xb6, 0x9b, 0x39, 0x64, 0x39, 0x5c, 0x31, 0xe2, 0x34, 0x34, 0xbf, 0xd1, 0x3e, 0x9c, 0x33, 0xb9, 0xcb, 0xff, 0xf7, 0x5c, 0x7d, 0x2c, 0xd6, 0x40, 0x8e, 0x78, 0xe5, 0x49, 0x10, 0xa8, 0x69, - 0x7e, 0xe2, 0xe1, 0xc6, 0x1c, 0xbe, 0x64, 0x7d, 0xb3, 0x97, 0xff, 0x26, + 0x7e, 0xe2, 0xe1, 0xc6, 0x1c, 0xbe, 0x64, 0x73, 0xb3, 0x97, 0xff, 0x26, 0x3f, 0xf1, 0x2d, 0x46, 0x09, 0xcb, 0xe4, 0xe3, 0xde, 0x27, 0x2f, 0xf7, - 0x02, 0x7f, 0xc9, 0xfa, 0x03, 0x95, 0x24, 0xc3, 0xb0, 0x8a, 0x62, 0x91, + 0x02, 0x7f, 0xf1, 0xfa, 0x03, 0x95, 0x24, 0xc3, 0xb0, 0x8a, 0x62, 0x91, 0x23, 0xda, 0x0f, 0x01, 0x35, 0xfe, 0x62, 0x8c, 0xfd, 0x89, 0xf9, 0xcb, - 0xf7, 0x2d, 0x68, 0x1d, 0x39, 0x7e, 0x45, 0x60, 0x56, 0x72, 0xb6, 0x7a, + 0xf7, 0xcd, 0x68, 0x1d, 0x39, 0x7e, 0x45, 0x60, 0x56, 0x72, 0xb6, 0x7a, 0x5e, 0x2b, 0xa8, 0x45, 0x5e, 0x42, 0x26, 0xff, 0xf8, 0x57, 0xd4, 0xea, - 0x6a, 0x26, 0x6f, 0x3a, 0x72, 0xff, 0xdb, 0x4e, 0x5d, 0x7d, 0x47, 0x18, + 0x6a, 0x26, 0x6f, 0x3a, 0x72, 0xff, 0xdb, 0x4f, 0x9d, 0x7d, 0x47, 0x18, 0x39, 0x7f, 0xcc, 0x79, 0x34, 0x07, 0x53, 0x47, 0x2b, 0x47, 0xf8, 0xc4, 0x1b, 0xf3, 0xef, 0xd0, 0x13, 0x95, 0x07, 0x92, 0x02, 0x2b, 0xfc, 0xfa, 0x93, 0xf9, 0xd6, 0x72, 0xa1, 0x36, 0x8e, 0xc6, 0x2a, 0x02, 0x1b, 0xe8, 0x52, 0x3a, 0x72, 0xf9, 0x6e, 0xeb, 0x34, 0x5b, 0x8b, 0xe9, 0xa0, 0x38, - 0x72, 0xff, 0xd9, 0xac, 0x1e, 0x5d, 0xcf, 0x9b, 0x39, 0x7e, 0x1f, 0xdf, - 0xed, 0x9c, 0xa8, 0x3e, 0xa7, 0x41, 0xaf, 0x91, 0xf9, 0xa2, 0x27, 0x2e, + 0x72, 0xff, 0xd9, 0xac, 0x1f, 0x9d, 0xce, 0x5b, 0x39, 0x7e, 0x1f, 0xdf, + 0x9d, 0x9c, 0xa8, 0x3e, 0xa7, 0x41, 0xae, 0x51, 0xf9, 0xa2, 0x27, 0x2e, 0xdc, 0x23, 0x2f, 0xf3, 0x8f, 0xf3, 0x0c, 0x30, 0xe5, 0xe6, 0x0a, 0x1c, - 0xb0, 0x9c, 0xbf, 0xee, 0x81, 0xf7, 0x98, 0x2a, 0x9c, 0xbf, 0x6d, 0xfe, + 0xb0, 0x9c, 0xbf, 0xee, 0x81, 0xf7, 0x98, 0x2a, 0x9c, 0xbf, 0x6d, 0xf9, 0x70, 0x9c, 0xb2, 0x04, 0xf8, 0x3c, 0x71, 0x50, 0x8b, 0x2c, 0x1b, 0xeb, 0x85, 0xff, 0x43, 0x8f, 0x73, 0x05, 0x67, 0x2f, 0xf7, 0xbc, 0x93, 0xb2, 0x04, 0xe5, 0x48, 0xfa, 0x30, 0xd6, 0xff, 0xa0, 0x40, 0xc8, 0xdf, 0x90, 0xe5, 0xe8, 0xcd, 0x1c, 0xbf, 0xdd, 0x89, 0x23, 0x4c, 0x61, 0xca, 0x09, - 0xe7, 0xec, 0x6e, 0xfd, 0xcb, 0xed, 0xa2, 0xa7, 0x2c, 0xf3, 0x9e, 0x77, - 0xc4, 0x57, 0xff, 0x4b, 0x3a, 0x9a, 0x0f, 0x60, 0x56, 0x72, 0xff, 0x7d, + 0xe7, 0xec, 0x6e, 0xfd, 0xf3, 0x9d, 0xa2, 0xa7, 0x2c, 0xf3, 0x9e, 0x77, + 0x24, 0x57, 0xff, 0x4b, 0x3a, 0x9a, 0x0f, 0x60, 0x56, 0x72, 0xff, 0x73, 0x28, 0x1f, 0x67, 0xe7, 0x2f, 0xb7, 0xfa, 0x78, 0xe5, 0x3a, 0x30, 0xf6, 0x52, 0x04, 0x35, 0x0d, 0x2f, 0xcf, 0xaf, 0x67, 0x4e, 0x5f, 0xf9, 0x3f, 0x89, 0x07, 0xb0, 0x2b, 0x39, 0x52, 0x3e, 0x5f, 0x13, 0xdf, 0xde, 0x96, 0x6b, 0x36, 0x72, 0x8e, 0x5e, 0x03, 0xf8, 0xe5, 0xc0, 0x83, 0x95, 0x23, - 0x65, 0xe1, 0xca, 0x39, 0x7d, 0xf2, 0xd3, 0x47, 0x2f, 0x43, 0x39, 0xe2, - 0x23, 0x3e, 0x3d, 0x61, 0x0f, 0x82, 0xef, 0xf8, 0x7d, 0xd7, 0x90, 0x1d, + 0x65, 0xe1, 0xca, 0x39, 0x7d, 0xca, 0xd3, 0x47, 0x2f, 0x43, 0x3e, 0xe2, + 0x23, 0x39, 0x3d, 0x61, 0x0f, 0x82, 0xef, 0xf8, 0x7d, 0xd7, 0x90, 0x1d, 0x43, 0x95, 0x09, 0xb2, 0x61, 0x12, 0x42, 0xe5, 0xd4, 0x2f, 0x0f, 0x9a, - 0x1c, 0xbd, 0xc9, 0xab, 0x6a, 0xce, 0x5f, 0xf4, 0xb9, 0xe6, 0x96, 0xee, + 0x1c, 0xbd, 0xf1, 0xab, 0x6a, 0xce, 0x5f, 0xf4, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x0e, 0xa4, 0x44, 0x74, 0xc3, 0xce, 0x53, 0x7e, 0xfe, 0x17, 0x8c, 0x39, 0x7d, 0x13, 0x60, 0x4e, 0x56, 0x8f, 0x2b, 0x65, 0x17, 0xfd, 0x90, 0x1e, 0xc7, 0x04, 0x4c, 0x72, 0xff, 0x7e, 0x9d, 0xee, 0x7e, 0xe7, 0x29, 0x87, 0xdf, 0xf9, 0xdd, 0x42, 0x2d, 0x1e, 0x12, 0x37, 0xfe, 0x70, 0xc0, 0x7a, 0x82, 0x8c, 0x39, 0x7f, 0xee, 0x2f, 0xad, 0xbf, 0x77, 0x13, 0x9c, 0xbf, 0xdb, 0x02, 0xf3, 0xc3, 0x07, 0x29, 0x88, 0xaf, 0xe9, 0xe7, - 0x90, 0x6f, 0xfe, 0x04, 0xba, 0xfa, 0xfb, 0xd0, 0x93, 0x9c, 0xbf, 0xd2, + 0x90, 0x6f, 0xfe, 0x04, 0xba, 0xfa, 0xe7, 0xd0, 0x93, 0x9c, 0xbf, 0xd2, 0x8d, 0x4f, 0x1a, 0x9c, 0xe5, 0xf9, 0xf7, 0xc7, 0x36, 0x72, 0xa0, 0xf7, - 0xbf, 0x35, 0xbf, 0x72, 0xee, 0x7e, 0xe7, 0x2f, 0xe9, 0x3e, 0xb3, 0xef, + 0xbf, 0x35, 0xbf, 0x7c, 0xee, 0x7e, 0xe7, 0x2f, 0xe9, 0x3e, 0xb3, 0x9f, 0x1c, 0xbf, 0x82, 0xec, 0xea, 0x36, 0x72, 0xa0, 0xf7, 0x30, 0xba, 0xff, 0xb3, 0xdb, 0x53, 0x7a, 0x7d, 0x9c, 0xbf, 0x27, 0xb6, 0xe8, 0x72, 0xff, 0xb5, 0xfe, 0x9c, 0x7d, 0x9f, 0x9c, 0xa9, 0xd3, 0x40, 0xd4, 0x21, 0x98, @@ -4598,266 +4598,267 @@ 0xd1, 0x7d, 0xff, 0xcb, 0x18, 0xf0, 0xe7, 0x1c, 0xd4, 0x8e, 0x5f, 0xf0, 0x05, 0x55, 0x3b, 0xd0, 0x6c, 0xe5, 0xff, 0x29, 0x1f, 0xcd, 0x28, 0xd4, 0xe7, 0x2f, 0xe1, 0x7f, 0x29, 0x0b, 0x39, 0x4c, 0x3e, 0xa1, 0x3d, 0xbe, - 0x1f, 0xe7, 0xfc, 0xe5, 0x61, 0xe3, 0x21, 0x0d, 0xfe, 0xdf, 0x2f, 0x72, - 0x0e, 0x09, 0xcb, 0x7e, 0x72, 0xc9, 0xf1, 0xe4, 0xe8, 0xde, 0xfc, 0xff, - 0x6f, 0xc8, 0x72, 0xa1, 0x50, 0xce, 0x18, 0x22, 0x27, 0x61, 0xd8, 0x2d, + 0x1f, 0xe7, 0xfc, 0xe5, 0x61, 0xe3, 0x21, 0x0d, 0xfe, 0xdf, 0xcf, 0x7c, + 0x0e, 0x09, 0xcb, 0x7e, 0x72, 0xc9, 0xc9, 0xe4, 0xe8, 0xde, 0xfc, 0xfc, + 0xef, 0xc8, 0x72, 0xa1, 0x50, 0xce, 0x18, 0x22, 0x27, 0x61, 0xd8, 0x2d, 0x3b, 0x28, 0xbf, 0x38, 0x15, 0x85, 0x0e, 0x5f, 0xb8, 0x6c, 0xd4, 0x6c, 0xe5, 0x4c, 0x7a, 0xa2, 0x53, 0x7f, 0x67, 0x90, 0x38, 0xc3, 0x97, 0xc3, - 0x24, 0x61, 0xcb, 0x72, 0x98, 0xf3, 0x5c, 0xb2, 0xff, 0x6e, 0x26, 0xfa, - 0x59, 0xc4, 0xe5, 0x04, 0xf8, 0x5c, 0xaa, 0xff, 0xfc, 0x1e, 0xc2, 0x9c, - 0xfc, 0x2f, 0xfe, 0xf7, 0x1f, 0x94, 0xb8, 0x38, 0x72, 0xfd, 0x3c, 0x4e, + 0x24, 0x61, 0xcb, 0x7c, 0x98, 0xf3, 0x5c, 0xb2, 0xff, 0x6e, 0x26, 0xe6, + 0x59, 0xc4, 0xe5, 0x04, 0xf8, 0x5c, 0xaa, 0xff, 0xfc, 0x1e, 0xc2, 0x9f, + 0x7c, 0x2f, 0xfe, 0xf7, 0x1f, 0x94, 0xb8, 0x38, 0x72, 0xfd, 0x3c, 0x4e, 0xfb, 0x39, 0x58, 0x89, 0x94, 0x5a, 0x71, 0x6b, 0xbf, 0x01, 0xcb, 0xf9, 0xff, 0x98, 0x60, 0x27, 0x2f, 0xf8, 0x72, 0x70, 0xf7, 0x07, 0xc7, 0x2a, 0x0f, 0xfb, 0xa3, 0x02, 0x5d, 0x4d, 0x4b, 0x6d, 0xe4, 0xd5, 0xa2, 0xb5, 0x13, 0xee, 0x14, 0xef, 0x11, 0xde, 0x4a, 0x30, 0x50, 0xc7, 0x1d, 0x91, - 0x99, 0x2a, 0x84, 0xb8, 0x72, 0xfd, 0x09, 0x64, 0x21, 0x9a, 0x39, 0x7d, + 0x99, 0x2a, 0x84, 0xb8, 0x72, 0xf3, 0x09, 0x64, 0x21, 0x9a, 0x39, 0x7d, 0x4a, 0x06, 0x64, 0x33, 0x7b, 0x19, 0x6b, 0xc3, 0x57, 0xf3, 0x01, 0x85, 0x26, 0xe3, 0x62, 0xf4, 0xae, 0x60, 0x42, 0xbf, 0x8c, 0x34, 0x1a, 0x42, - 0xe9, 0x48, 0x55, 0xdf, 0xff, 0x97, 0xcf, 0xfd, 0x67, 0xcb, 0xea, 0x7b, - 0x6f, 0xf1, 0xca, 0xe6, 0xa8, 0xb4, 0x11, 0xe9, 0x5f, 0x46, 0xa4, 0xc3, - 0x97, 0xdf, 0x6d, 0xda, 0xce, 0x5e, 0x7d, 0x2a, 0x72, 0xdc, 0xe7, 0x3e, - 0x54, 0x22, 0x6c, 0x9a, 0xff, 0x73, 0xcd, 0x2d, 0xdd, 0x66, 0x8b, 0xcd, - 0x50, 0xee, 0x1a, 0x24, 0xe2, 0x18, 0xc2, 0x72, 0xb4, 0xd1, 0xfa, 0x74, + 0xe9, 0x48, 0x55, 0xdf, 0xff, 0x97, 0xf7, 0xfd, 0x67, 0x2b, 0xea, 0x7b, + 0x6f, 0xc9, 0xca, 0xfa, 0xa8, 0xb4, 0x11, 0xe9, 0x5f, 0x46, 0xa4, 0xc3, + 0x97, 0xdc, 0xed, 0xda, 0xce, 0x5e, 0x7d, 0x2a, 0x72, 0xdf, 0x67, 0x3e, + 0x54, 0x22, 0x6c, 0x9a, 0xff, 0x7d, 0xcd, 0x2d, 0xdd, 0x66, 0x8b, 0xcd, + 0x50, 0xee, 0x1a, 0x24, 0xe2, 0x18, 0xc2, 0x72, 0xb4, 0xd1, 0xe6, 0x74, 0x33, 0x51, 0xde, 0xb1, 0x4f, 0xb0, 0xae, 0x1a, 0xe5, 0x23, 0x70, 0x92, - 0xe2, 0x71, 0x7f, 0xb9, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x2c, 0xbf, 0x69, - 0x6e, 0xeb, 0x34, 0x58, 0x4b, 0xff, 0xec, 0x10, 0xc7, 0x63, 0xef, 0x60, + 0xe2, 0x71, 0x7f, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x2c, 0xbf, 0x69, + 0x6e, 0xeb, 0x34, 0x58, 0x4b, 0xff, 0xec, 0x10, 0xc7, 0x63, 0x9f, 0x60, 0xbb, 0x0e, 0x5e, 0x10, 0x2c, 0xe5, 0x41, 0xf4, 0xba, 0x6d, 0xb6, 0x72, - 0xfe, 0x06, 0x92, 0x77, 0x61, 0xcb, 0x73, 0xc4, 0x7e, 0x32, 0x13, 0xbb, - 0x20, 0x68, 0x23, 0x7f, 0xb9, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x96, 0xb4, - 0x8e, 0x5d, 0xa5, 0x4e, 0x5f, 0x73, 0x57, 0x85, 0x35, 0x27, 0x28, 0xa5, - 0xee, 0x6a, 0x30, 0xe5, 0x2c, 0xf7, 0x36, 0x62, 0x00, 0xba, 0x55, 0x16, + 0xfe, 0x06, 0x92, 0x77, 0x61, 0xcb, 0x7d, 0xc4, 0x7e, 0x32, 0x13, 0xbb, + 0x20, 0x68, 0x23, 0x7f, 0xbe, 0xe6, 0x96, 0xee, 0xb3, 0x45, 0x96, 0xb4, + 0x8e, 0x5d, 0xa5, 0x4e, 0x5f, 0x7d, 0x57, 0x85, 0x35, 0x27, 0x28, 0xa5, + 0xef, 0xaa, 0x30, 0xe5, 0x2c, 0xf7, 0x36, 0x62, 0x00, 0xba, 0x55, 0x16, 0x82, 0x23, 0xb7, 0x4b, 0xa3, 0xa7, 0x2d, 0xf9, 0xcb, 0x95, 0x9c, 0xe5, 0xb5, 0x23, 0x57, 0x82, 0x54, 0xb3, 0xe7, 0x74, 0x1b, 0x93, 0xf3, 0x97, - 0xfc, 0xff, 0x0e, 0x7d, 0xe8, 0x54, 0xe5, 0xfe, 0x9f, 0xed, 0xc0, 0x7c, + 0xfc, 0xfc, 0x8e, 0x73, 0xe8, 0x54, 0xe5, 0xfe, 0x9f, 0x9d, 0xc0, 0x7c, 0x87, 0x2f, 0xd1, 0x9c, 0x63, 0x67, 0x2d, 0x0e, 0x7b, 0xad, 0x9a, 0xd3, 0xa2, 0xf8, 0x61, 0x2f, 0x7c, 0xf2, 0x90, 0x4e, 0x5f, 0xcf, 0xa8, 0xf3, - 0xf4, 0xe5, 0xe6, 0xdb, 0x6c, 0xa5, 0xff, 0x44, 0xbe, 0xf6, 0xa3, 0x3e, - 0x29, 0xcc, 0xd0, 0x5f, 0xf0, 0x1f, 0xec, 0xf2, 0x7c, 0xd9, 0xcb, 0xa3, + 0xf4, 0xe5, 0xe6, 0xdb, 0x6c, 0xa5, 0xff, 0x44, 0xb9, 0xf6, 0xa3, 0x39, + 0x29, 0xf4, 0xd0, 0x5f, 0xf0, 0x1f, 0x9c, 0xf2, 0x72, 0xd9, 0xcb, 0xa3, 0x67, 0x28, 0x29, 0x85, 0xf4, 0x88, 0x53, 0x36, 0x99, 0xc4, 0xee, 0xee, 0x14, 0xd4, 0x9c, 0xbf, 0x91, 0xf7, 0xfe, 0xc0, 0x72, 0xff, 0xe4, 0x93, 0xed, 0xc4, 0x0b, 0xcd, 0x94, 0xbf, 0xff, 0xba, 0x9e, 0xee, 0x6c, 0x71, 0x80, 0xdf, 0x5e, 0x47, 0x2f, 0xf4, 0x4b, 0xcf, 0xd7, 0x09, 0xca, 0x84, - 0x67, 0x62, 0x16, 0x96, 0xad, 0x23, 0x96, 0x91, 0xcb, 0x48, 0xe5, 0x96, - 0x72, 0xa0, 0xf1, 0x15, 0x11, 0x41, 0x1f, 0xc4, 0x6f, 0xe0, 0x6f, 0xaf, - 0x2c, 0x39, 0x7f, 0xfd, 0xb4, 0x5e, 0x0e, 0xa0, 0x70, 0x38, 0xa9, 0xca, - 0x61, 0xfd, 0x78, 0xb6, 0xdf, 0x1c, 0xb2, 0xa7, 0x2c, 0x03, 0x94, 0x26, - 0x8f, 0x62, 0x55, 0x87, 0xef, 0xb2, 0x2f, 0x1a, 0xdd, 0xb5, 0x4e, 0x5b, - 0x0e, 0x5c, 0x0f, 0xe0, 0xd4, 0x04, 0x62, 0xe4, 0x83, 0x97, 0xf0, 0xc3, - 0x06, 0x30, 0xe5, 0xff, 0xd0, 0xfa, 0xf7, 0x70, 0x20, 0xf6, 0xce, 0x5d, - 0x28, 0x39, 0x7b, 0x61, 0x54, 0xe5, 0x4e, 0x8e, 0x40, 0x96, 0xcc, 0x2b, - 0xd2, 0xa0, 0x22, 0x28, 0x2d, 0x7f, 0xff, 0xfd, 0xd8, 0xf6, 0xd3, 0x7b, - 0x8f, 0x75, 0x23, 0x5f, 0xb1, 0xe5, 0x2f, 0x2a, 0x72, 0xe4, 0xf8, 0xe5, - 0xd0, 0xc3, 0x97, 0xff, 0xe8, 0x10, 0x4a, 0x51, 0xee, 0xe3, 0x14, 0x8f, - 0xce, 0x5f, 0xff, 0x20, 0x82, 0x59, 0xbd, 0x42, 0x49, 0xf6, 0x52, 0xa4, - 0x8a, 0x3f, 0x2b, 0x5c, 0xbe, 0x70, 0xc8, 0xcd, 0x9e, 0x12, 0xf2, 0x21, - 0x0c, 0x35, 0x72, 0x33, 0x15, 0x53, 0x16, 0x45, 0xa8, 0x7e, 0x3b, 0x90, - 0xc6, 0x5b, 0xb8, 0xce, 0xbc, 0xb5, 0xc5, 0xfd, 0xa0, 0xba, 0x90, 0xb9, - 0xbf, 0xfd, 0xcd, 0x8f, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x46, 0x2f, - 0xdc, 0x63, 0x51, 0xf9, 0xcb, 0xf0, 0xbf, 0xf0, 0xa1, 0xcb, 0xff, 0x27, - 0xd2, 0xd8, 0xe7, 0xba, 0x03, 0x97, 0xfc, 0x9a, 0xee, 0x60, 0xcb, 0x67, - 0x2d, 0xf4, 0x8f, 0xd9, 0x67, 0xf7, 0xfe, 0x79, 0x2f, 0xa8, 0xc8, 0xd2, - 0xa7, 0x2d, 0xce, 0x13, 0x30, 0xe9, 0x57, 0xa1, 0x3c, 0xd9, 0x4d, 0x49, - 0x9c, 0x4d, 0xa8, 0xcf, 0x58, 0x96, 0xf4, 0x9c, 0x2d, 0xc6, 0x0f, 0xe8, - 0xe2, 0xaf, 0xfe, 0xe6, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x11, 0xca, - 0xff, 0xf7, 0x36, 0x3c, 0xb9, 0xe6, 0x96, 0xee, 0xb3, 0x44, 0xe4, 0xbf, - 0xdc, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0xcc, 0x5f, 0xf4, 0xb6, 0xec, 0xe7, - 0xdf, 0x7e, 0x72, 0xff, 0xb8, 0x58, 0x38, 0xc8, 0xfa, 0x18, 0x72, 0xff, - 0x6a, 0x3d, 0xd7, 0xfa, 0x47, 0x2f, 0xff, 0xff, 0xa2, 0x6e, 0xc7, 0xa1, - 0x44, 0xd4, 0xd1, 0xdc, 0xe3, 0x9d, 0xc0, 0xf1, 0xc3, 0x95, 0xfa, 0x2d, - 0x44, 0xd2, 0xff, 0xb3, 0x6f, 0xef, 0xd4, 0x19, 0x1c, 0xbf, 0xd9, 0xbd, - 0x6b, 0x3e, 0xd9, 0xcb, 0xda, 0xc6, 0x1c, 0xbe, 0x41, 0xcd, 0x9c, 0xb6, - 0x78, 0xde, 0x70, 0x0e, 0x5f, 0xf9, 0x06, 0x37, 0x1e, 0x9f, 0x1b, 0x39, - 0x77, 0x25, 0x0e, 0x5f, 0xda, 0x5f, 0x5d, 0x38, 0x73, 0x97, 0xe7, 0x18, - 0xe2, 0x03, 0x97, 0x7c, 0xc3, 0x97, 0xff, 0x34, 0x71, 0xff, 0x3d, 0x02, - 0x9f, 0x9c, 0xb7, 0x36, 0xa5, 0x57, 0xd4, 0x43, 0xd6, 0x72, 0x39, 0x1d, - 0x05, 0xc1, 0x85, 0x3b, 0x3e, 0x00, 0xd7, 0x13, 0x26, 0x85, 0x0a, 0x0c, - 0x5f, 0xee, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x6e, 0xaf, 0xe1, 0x7e, 0x7a, - 0x9f, 0xa7, 0x2f, 0x27, 0xdf, 0x9c, 0xbf, 0xfb, 0x4e, 0xbf, 0xc1, 0xbf, - 0x47, 0xcd, 0x9c, 0xb8, 0x55, 0x39, 0x7c, 0xb7, 0x75, 0x9a, 0x29, 0x05, - 0x61, 0xe2, 0xe8, 0x5e, 0xff, 0x4b, 0xc8, 0xde, 0xff, 0x43, 0x97, 0xfe, - 0xce, 0xa7, 0x1e, 0xe6, 0x0a, 0xce, 0x5e, 0x79, 0x73, 0x0a, 0x64, 0x39, - 0x08, 0xdf, 0x88, 0x76, 0x6b, 0x7f, 0x90, 0x20, 0xf6, 0xd8, 0x27, 0x2f, - 0x38, 0xc8, 0xe5, 0xb9, 0xad, 0x50, 0x9e, 0x8c, 0x19, 0x19, 0xfb, 0xab, - 0x36, 0x67, 0x7f, 0xf7, 0x37, 0x97, 0x3c, 0xd2, 0xdd, 0xd6, 0x68, 0x94, - 0x95, 0x3a, 0xfe, 0xcc, 0xca, 0x8c, 0x5a, 0x74, 0x1f, 0xe5, 0x9b, 0x8c, - 0x2c, 0x7d, 0x29, 0x53, 0x81, 0x6a, 0xfe, 0x41, 0xf6, 0x20, 0x4e, 0x5d, - 0x2f, 0x1c, 0xbc, 0x30, 0xd9, 0xcb, 0xa3, 0x9e, 0x8d, 0x98, 0x8b, 0xd4, - 0x91, 0x17, 0xe5, 0xeb, 0xdb, 0x03, 0x0e, 0x5b, 0x9f, 0xc7, 0x80, 0x84, - 0x77, 0x85, 0xe4, 0x72, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, 0x3b, 0x2f, 0xfe, - 0xce, 0x8b, 0xc8, 0x1f, 0xb1, 0xe4, 0x72, 0xf3, 0xcb, 0x9e, 0x1f, 0xc0, - 0x9a, 0x5d, 0x3b, 0x59, 0xcb, 0xff, 0xf2, 0x04, 0x0c, 0x8e, 0x07, 0x08, - 0xc0, 0xe2, 0xce, 0x5f, 0xe9, 0x46, 0xa7, 0x8d, 0x4e, 0x72, 0xff, 0xdd, - 0x17, 0x90, 0x3f, 0x63, 0xc8, 0xe5, 0x41, 0xfa, 0x61, 0xad, 0xb9, 0xe2, - 0x79, 0x4c, 0x84, 0x9f, 0x4c, 0xdc, 0x6c, 0x61, 0x93, 0x7c, 0x9a, 0x8e, - 0x27, 0x2f, 0xfe, 0x68, 0xe3, 0xfe, 0x7a, 0x05, 0x3f, 0x39, 0x6e, 0x7b, - 0x3e, 0x85, 0x08, 0xef, 0xfe, 0x76, 0x77, 0x16, 0xfd, 0x85, 0x24, 0x72, - 0xf2, 0x05, 0xce, 0x5f, 0xfc, 0x39, 0xd7, 0x9f, 0x36, 0x2f, 0xf1, 0xcb, - 0x9a, 0x73, 0x0a, 0x28, 0xba, 0x89, 0xb1, 0xba, 0x92, 0xbc, 0x36, 0x47, - 0xe9, 0xb8, 0x61, 0x34, 0x86, 0x6d, 0xff, 0xfc, 0x17, 0xf7, 0x3c, 0xdc, - 0x0f, 0xdf, 0xef, 0x71, 0xf9, 0xcb, 0xf6, 0x96, 0xee, 0xb3, 0x44, 0x58, - 0xbf, 0xf3, 0xcb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x4b, 0xab, 0xff, 0xfb, - 0x03, 0xd8, 0x53, 0x9f, 0x85, 0xff, 0xde, 0xe3, 0xf2, 0x96, 0xe7, 0x88, - 0xdf, 0x61, 0xa3, 0x44, 0xcb, 0xff, 0x98, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, - 0xcd, 0x13, 0x12, 0xff, 0xfb, 0x17, 0x1c, 0xfa, 0xe8, 0xd1, 0x3f, 0xc0, - 0x9c, 0xae, 0x68, 0xa4, 0xea, 0x95, 0xfb, 0x4b, 0x77, 0x59, 0xa2, 0xa9, - 0x5b, 0x0e, 0x56, 0x1e, 0x22, 0xa6, 0x97, 0xfe, 0x03, 0xea, 0x43, 0x8d, - 0xbf, 0xe7, 0x2f, 0xfe, 0x7d, 0xe9, 0x1b, 0xf7, 0x53, 0x52, 0x39, 0x7f, - 0xda, 0x7e, 0xfd, 0x2c, 0xf7, 0x30, 0xa2, 0x13, 0xa7, 0xf5, 0xcd, 0x1f, - 0x4f, 0x0a, 0x6b, 0xff, 0xdc, 0xd8, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, - 0x13, 0xa2, 0xff, 0x23, 0xea, 0x24, 0xfc, 0x4e, 0x5f, 0xa6, 0x89, 0xa3, - 0x67, 0x2f, 0xe6, 0xf1, 0x38, 0xe0, 0x9c, 0xa4, 0x3d, 0x7d, 0x94, 0xde, - 0x4e, 0xc1, 0xce, 0x66, 0x86, 0xff, 0xe0, 0x6f, 0xd1, 0xf7, 0x30, 0x4c, - 0x8c, 0x39, 0x4c, 0x3f, 0x6e, 0x96, 0xdf, 0xf9, 0xe5, 0xcf, 0x34, 0xb7, - 0x75, 0x9a, 0x27, 0x75, 0xfb, 0xc0, 0x76, 0x21, 0x4b, 0xff, 0x0c, 0x7b, - 0x37, 0x99, 0xf4, 0x8e, 0x50, 0x53, 0xf3, 0xc8, 0xc8, 0x58, 0x44, 0xe9, - 0x9e, 0x27, 0xbf, 0xe0, 0xc4, 0xa3, 0x9b, 0x7b, 0xfc, 0xe5, 0xfd, 0x1c, - 0xff, 0x1c, 0x09, 0xca, 0xe6, 0x8b, 0xbc, 0x4f, 0x13, 0xdb, 0xff, 0xdc, - 0xd8, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x14, 0x2a, 0xff, 0xf9, 0xfd, - 0x2c, 0x14, 0x0f, 0x3d, 0xcf, 0x1a, 0x39, 0x7f, 0xff, 0xfb, 0xa0, 0x63, - 0x1e, 0x5c, 0xd7, 0xd0, 0x7a, 0x07, 0x27, 0x54, 0x11, 0x31, 0xcb, 0xf0, - 0x3e, 0xf2, 0x2c, 0xe5, 0xfb, 0x3f, 0xc7, 0x13, 0x97, 0xdb, 0x46, 0xfc, - 0x72, 0xf4, 0x7f, 0xce, 0x73, 0xf2, 0x12, 0x9f, 0x13, 0x52, 0x26, 0x64, - 0x30, 0xef, 0xbf, 0xfd, 0xcd, 0x8f, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, - 0x49, 0x2f, 0xff, 0xf6, 0x6f, 0x9a, 0x99, 0x37, 0x5d, 0x9e, 0xec, 0x78, - 0x0c, 0x39, 0x50, 0xc9, 0xa2, 0x9e, 0x33, 0xe9, 0x43, 0x75, 0x71, 0xb1, - 0xe8, 0xa5, 0x92, 0xc2, 0x3f, 0x30, 0x15, 0xaf, 0x47, 0x06, 0x02, 0x76, - 0x8b, 0x57, 0xfb, 0x9e, 0x69, 0x6e, 0xeb, 0x34, 0x44, 0x8b, 0xff, 0xdc, - 0xd8, 0xf2, 0xe7, 0x9a, 0x5b, 0xba, 0xcd, 0x12, 0xf2, 0xff, 0xe8, 0xe2, - 0xf3, 0x26, 0xbe, 0x94, 0x4c, 0x72, 0xf3, 0x52, 0xcf, 0xce, 0x5f, 0x68, - 0x1e, 0xd9, 0xcb, 0xf6, 0xbf, 0x62, 0x6c, 0xe5, 0xe8, 0x1f, 0x8e, 0x5f, - 0xbc, 0xa3, 0x06, 0x0e, 0x59, 0x3a, 0x78, 0x82, 0x39, 0x7f, 0xfb, 0xbc, - 0x60, 0x7f, 0x6b, 0xc0, 0xe6, 0xbe, 0x39, 0x74, 0x78, 0xe5, 0xff, 0x3c, - 0xfa, 0x8f, 0xa4, 0x8c, 0x39, 0x7f, 0xf8, 0x01, 0x4d, 0x29, 0x37, 0x00, - 0x1c, 0x66, 0x39, 0x52, 0x4c, 0x59, 0x09, 0xbf, 0x50, 0x11, 0x6d, 0x9d, - 0x5f, 0xdf, 0xf6, 0x34, 0x8c, 0x39, 0x7f, 0xe9, 0xb7, 0x1c, 0x5f, 0xb1, - 0xf4, 0xc7, 0x2a, 0x0f, 0xc5, 0xcb, 0xaf, 0x93, 0x81, 0x46, 0x1c, 0xbf, - 0x64, 0xf9, 0xb6, 0x1c, 0xbf, 0x9e, 0x77, 0xdb, 0xfe, 0x72, 0xff, 0xe9, - 0xb9, 0x28, 0x31, 0xc5, 0xf8, 0xc4, 0xc7, 0x28, 0xe5, 0xfa, 0x4f, 0xe7, - 0xe2, 0x72, 0xfc, 0xfb, 0x8e, 0x38, 0x72, 0xa6, 0x3d, 0x1e, 0x25, 0x35, - 0x08, 0xcd, 0xc4, 0xc7, 0x5c, 0xbb, 0x50, 0x72, 0x82, 0xb8, 0x1a, 0x84, - 0x73, 0x47, 0x07, 0xa8, 0x5d, 0xf4, 0x80, 0x49, 0xbc, 0x51, 0xc6, 0x1f, - 0x7c, 0x05, 0xb7, 0x60, 0x9c, 0xbf, 0xb9, 0x6f, 0xb8, 0x9e, 0x39, 0x41, - 0x3c, 0x44, 0x15, 0xb8, 0x3f, 0x1c, 0xbf, 0x84, 0x1e, 0x9a, 0x15, 0x39, - 0x7b, 0x87, 0x4d, 0x1c, 0xb2, 0x39, 0xe8, 0x00, 0xbe, 0xfc, 0x39, 0x3a, - 0x9c, 0x4e, 0x5f, 0x64, 0xea, 0x71, 0x39, 0x7e, 0x0c, 0x7c, 0x17, 0xe4, - 0x7a, 0x22, 0x57, 0x7f, 0xfc, 0x9a, 0xe5, 0xd8, 0x4f, 0x6c, 0x0b, 0x04, - 0x1c, 0xbe, 0x49, 0xff, 0x6b, 0x39, 0x7c, 0xb7, 0x75, 0x9a, 0x29, 0x75, - 0xf0, 0xfa, 0x34, 0x72, 0xff, 0xb3, 0x4d, 0x78, 0x1c, 0xd7, 0xc7, 0x29, - 0x0f, 0x77, 0x89, 0x0d, 0x49, 0x36, 0x65, 0x50, 0x26, 0x51, 0xd1, 0x3f, - 0x61, 0x17, 0x7f, 0x07, 0xe8, 0xd2, 0x7c, 0x72, 0xfb, 0xd3, 0xe3, 0x67, - 0x29, 0x0f, 0x4c, 0x4b, 0xef, 0xc8, 0xae, 0xb3, 0x67, 0x2f, 0xfd, 0x03, - 0x1d, 0xe4, 0x01, 0x02, 0xce, 0x5e, 0x03, 0xec, 0xe5, 0xf4, 0xc0, 0x79, - 0x8e, 0x5f, 0xa3, 0xf7, 0xfb, 0x67, 0x2f, 0x0a, 0x7e, 0x72, 0xf6, 0x7b, - 0x67, 0x2a, 0x0d, 0xc6, 0xc7, 0x2a, 0x49, 0x94, 0x04, 0xa2, 0x63, 0xfe, - 0x8e, 0x7e, 0x49, 0xe6, 0x1b, 0xf3, 0x5b, 0x88, 0x78, 0x0e, 0x5d, 0x1f, - 0x1c, 0xbf, 0xef, 0xf7, 0xa8, 0xfa, 0x48, 0xc3, 0x97, 0xbc, 0xfc, 0x4e, - 0x5f, 0xa7, 0x04, 0xd0, 0xd6, 0x72, 0xf8, 0x13, 0x43, 0x59, 0xcb, 0x9e, - 0x7e, 0x47, 0xa7, 0x39, 0x6d, 0x42, 0x37, 0x5c, 0xec, 0x0e, 0x37, 0xfc, - 0x9b, 0x99, 0x07, 0xd1, 0xf9, 0xcb, 0xff, 0x87, 0xdc, 0x63, 0x5b, 0x71, - 0x86, 0xb3, 0x95, 0x24, 0x57, 0x30, 0xbb, 0x67, 0x37, 0xfa, 0x1a, 0xf7, - 0x0c, 0x7f, 0x1c, 0xb9, 0xc4, 0xe5, 0xff, 0x47, 0xfc, 0xbb, 0x0c, 0x71, - 0x39, 0x5f, 0x1e, 0x7f, 0x11, 0x5a, 0x92, 0x2a, 0x75, 0x08, 0x4b, 0xfa, - 0x1b, 0x4e, 0x81, 0xac, 0xe5, 0xfd, 0xf4, 0xb6, 0xe3, 0xf1, 0xca, 0x85, - 0x66, 0x12, 0x2d, 0xc8, 0xe8, 0x92, 0x1b, 0x3a, 0x28, 0x50, 0xc6, 0xff, - 0xc3, 0x37, 0x2d, 0x47, 0xd2, 0x46, 0x1c, 0xba, 0x18, 0x72, 0xa0, 0xf6, - 0x34, 0x85, 0x7f, 0x40, 0xcd, 0xe4, 0x54, 0xe5, 0xff, 0x4b, 0x35, 0x36, - 0x0c, 0x30, 0xe5, 0xfb, 0xf8, 0x5e, 0x30, 0xe5, 0xfe, 0xc9, 0xf7, 0x13, - 0x03, 0x47, 0x29, 0x11, 0x2b, 0xa3, 0x81, 0x28, 0xba, 0x58, 0x72, 0xfd, - 0xb5, 0x74, 0xed, 0x9c, 0xbc, 0x30, 0xc3, 0x94, 0x13, 0xc5, 0xd1, 0x55, - 0xe8, 0xff, 0x67, 0x2a, 0x11, 0x90, 0x12, 0xec, 0x5b, 0x6c, 0x8a, 0xf9, - 0xfa, 0xf3, 0x9c, 0xbf, 0x74, 0x0a, 0xe0, 0x9c, 0xbf, 0xcd, 0x8b, 0xfa, - 0x4e, 0x13, 0x97, 0xef, 0x29, 0x3c, 0x74, 0xe5, 0xff, 0x47, 0x76, 0xfe, - 0x8d, 0x70, 0x1c, 0xbf, 0xf3, 0x1c, 0x2a, 0x4d, 0x28, 0x1f, 0x8e, 0x50, - 0x4f, 0xf1, 0x0e, 0xef, 0xb5, 0xfa, 0x9c, 0x4e, 0x5e, 0x46, 0xfc, 0x72, - 0xba, 0x78, 0x9b, 0x27, 0xa9, 0xd3, 0xaa, 0x09, 0x17, 0xc5, 0x13, 0x19, - 0xf6, 0x14, 0xde, 0x65, 0xbf, 0xc3, 0xec, 0xda, 0x3f, 0x4e, 0x5f, 0xf7, - 0xe9, 0xdc, 0xd3, 0xcd, 0xb3, 0x97, 0xff, 0xe8, 0x90, 0xc4, 0xea, 0x4d, - 0xbe, 0xe7, 0x06, 0xbf, 0x39, 0x7f, 0x72, 0x66, 0x79, 0xfc, 0x72, 0xfe, - 0xea, 0x05, 0x34, 0xb3, 0x96, 0x59, 0xcb, 0xbe, 0xde, 0x1f, 0x6a, 0xcb, - 0xdc, 0xb6, 0xf4, 0x20, 0x4e, 0x54, 0x27, 0x13, 0xf1, 0x8b, 0x0e, 0x9e, - 0x19, 0x3b, 0x3a, 0xbf, 0xd8, 0xdc, 0x93, 0x60, 0x61, 0xcb, 0xb8, 0xec, - 0xe5, 0xfc, 0x0d, 0xc4, 0xc0, 0xd1, 0xcb, 0xf6, 0x4f, 0x9d, 0xd9, 0xca, - 0x83, 0xf0, 0xe8, 0xc8, 0x97, 0xde, 0xcd, 0x6c, 0xe5, 0x2c, 0xf2, 0x78, - 0x96, 0xdf, 0xf7, 0xf1, 0xfa, 0x9c, 0x60, 0x78, 0x0e, 0x54, 0x26, 0xa3, - 0x90, 0xed, 0x42, 0x4b, 0xff, 0xff, 0xbb, 0x1a, 0xf9, 0x69, 0xf7, 0x25, - 0x5f, 0x96, 0xfa, 0xeb, 0x81, 0x09, 0xcb, 0xe4, 0x55, 0xa6, 0x1c, 0xbf, - 0x94, 0xf4, 0x4e, 0x3f, 0x1c, 0xbc, 0x28, 0xc3, 0x95, 0xa3, 0xef, 0xfc, - 0x93, 0xc6, 0x17, 0xf8, 0x61, 0xc7, 0xd8, 0x27, 0x2f, 0xf4, 0x7d, 0xb6, - 0xb8, 0xd2, 0xa7, 0x2f, 0xf7, 0x5e, 0x64, 0xd4, 0x4e, 0x72, 0xfe, 0xce, - 0x06, 0x46, 0x78, 0xe5, 0xd8, 0xc3, 0x94, 0x14, 0xfd, 0xf2, 0x1c, 0xec, - 0x30, 0xe9, 0x7b, 0x9c, 0x00, 0xd3, 0x89, 0x7d, 0xfb, 0x81, 0x19, 0x1b, - 0x39, 0x7e, 0x7e, 0x39, 0xad, 0x9c, 0xa0, 0x9e, 0x9b, 0x0a, 0xaf, 0xdd, - 0x71, 0x46, 0x1c, 0xbe, 0x56, 0x6d, 0xc1, 0xcb, 0xfb, 0xff, 0xbf, 0xcd, - 0x61, 0xcb, 0xf9, 0x70, 0x9e, 0x49, 0x1c, 0xbf, 0x9f, 0xf6, 0x46, 0x78, - 0xe5, 0x42, 0x22, 0x70, 0xc1, 0x0b, 0x2f, 0xf3, 0xff, 0xb8, 0xec, 0x6c, - 0xe5, 0xfb, 0xef, 0x6f, 0x27, 0x39, 0x76, 0x4e, 0x72, 0x9c, 0xf0, 0x44, - 0xaa, 0xa1, 0x3b, 0x6c, 0x22, 0x42, 0x6e, 0xc2, 0xb4, 0x4b, 0x76, 0xe9, - 0x77, 0xeb, 0x39, 0x6d, 0x9c, 0xb9, 0x15, 0xd9, 0xa9, 0x00, 0xc5, 0xef, - 0xdd, 0x67, 0x2f, 0x9b, 0x9b, 0x70, 0x72, 0xfe, 0xd8, 0xbc, 0xf1, 0xe3, - 0x97, 0xe9, 0xdf, 0x79, 0x23, 0x97, 0xff, 0xc1, 0xce, 0x2f, 0xa9, 0x94, - 0x93, 0xf9, 0xd8, 0x72, 0xa0, 0xfe, 0xd0, 0xa2, 0xfe, 0x7f, 0xbf, 0x62, - 0x6c, 0xe5, 0x42, 0x67, 0x1f, 0x0e, 0xcc, 0x49, 0xa8, 0x54, 0x74, 0x82, - 0xff, 0x79, 0x1b, 0x79, 0xa1, 0x87, 0x2d, 0xcf, 0x84, 0x6f, 0x03, 0x1a, - 0xb4, 0x88, 0x9c, 0x30, 0x9e, 0x1b, 0x32, 0x21, 0x0b, 0x46, 0x47, 0xbb, - 0xf4, 0x29, 0x52, 0x34, 0x89, 0xa5, 0xc5, 0x6a, 0x17, 0x4c, 0x21, 0xec, - 0x71, 0x6f, 0x1f, 0x37, 0xf1, 0xf4, 0x8c, 0x74, 0x1b, 0x94, 0x55, 0xe9, - 0x4e, 0x6d, 0x21, 0x04, 0xa4, 0x6c, 0xbc, 0x0a, 0x37, 0xfb, 0x9e, 0x69, - 0x6e, 0xeb, 0x34, 0x53, 0x8b, 0xfc, 0xc8, 0x66, 0x70, 0x47, 0x8e, 0x5f, - 0x66, 0xd4, 0x91, 0xcb, 0xff, 0x26, 0x9f, 0x7d, 0xcc, 0x15, 0x9c, 0xbf, - 0x33, 0x5a, 0xcd, 0x9c, 0xbf, 0xff, 0x74, 0x1e, 0xd4, 0x7b, 0x78, 0xbd, - 0xc6, 0x96, 0x72, 0xff, 0xb6, 0x8a, 0xe4, 0xa3, 0xfd, 0x9c, 0xbf, 0xff, - 0xbd, 0x93, 0x0a, 0x6f, 0xd0, 0xa2, 0x6a, 0x68, 0xe9, 0xcb, 0xfc, 0x8c, - 0x0c, 0x6c, 0x02, 0x72, 0xfe, 0x7f, 0xb7, 0xcb, 0x6a, 0x1c, 0xbf, 0x7b, - 0xe9, 0x43, 0x67, 0x2f, 0xe7, 0x53, 0x38, 0xc6, 0xce, 0x56, 0x1e, 0xc8, - 0x0a, 0xaf, 0xfc, 0x9f, 0x6c, 0x70, 0x3d, 0x76, 0xce, 0x5f, 0xff, 0x64, - 0xf9, 0xf7, 0xb6, 0x83, 0x1f, 0xbb, 0x0e, 0x52, 0xa8, 0x8f, 0xd9, 0xfd, - 0xff, 0xb3, 0xb1, 0xac, 0xe6, 0xdb, 0x6d, 0x94, 0xb9, 0x1b, 0x39, 0x74, - 0xfc, 0xe1, 0x5c, 0x9c, 0x8d, 0x42, 0x47, 0x87, 0x8b, 0x28, 0xf9, 0x59, - 0x0e, 0xba, 0xb9, 0xf9, 0x90, 0xc2, 0x2f, 0xd0, 0xb0, 0x68, 0x49, 0xc0, - 0x87, 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0xaf, 0x17, 0xff, 0xf6, 0x07, 0xb0, - 0xa7, 0x3f, 0x0b, 0xff, 0xbd, 0xc7, 0xe5, 0x2d, 0xcf, 0x11, 0x26, 0xd0, - 0xd2, 0xff, 0xee, 0x6f, 0x2e, 0x79, 0xa5, 0xbb, 0xac, 0xd1, 0x23, 0xaf, - 0x2f, 0x18, 0x72, 0xf2, 0x7f, 0x07, 0x2f, 0x2f, 0x18, 0x53, 0x99, 0x79, - 0x7e, 0xd2, 0xdd, 0xd6, 0x68, 0x92, 0x17, 0xff, 0xf4, 0x26, 0x93, 0x82, - 0x06, 0x78, 0xf2, 0x75, 0xe7, 0x39, 0x7f, 0xf9, 0xfd, 0x36, 0xf0, 0x21, - 0x03, 0xea, 0x47, 0x2f, 0xff, 0x0e, 0x7e, 0xd3, 0x35, 0x13, 0xbe, 0x96, - 0x72, 0xe9, 0x73, 0x84, 0xd5, 0x30, 0xb7, 0xa6, 0x9f, 0xae, 0x79, 0x2e, - 0xfd, 0x9d, 0xe7, 0x8c, 0x39, 0x6e, 0x70, 0xa8, 0x35, 0xe3, 0x8c, 0xf2, - 0xc5, 0xff, 0xdc, 0xde, 0x5c, 0xf3, 0x4b, 0x77, 0x59, 0xa2, 0x4a, 0x5f, - 0xb4, 0xb7, 0x75, 0x9a, 0x2f, 0x15, 0xff, 0x4b, 0x9e, 0x69, 0x6e, 0xeb, - 0x34, 0x49, 0xab, 0x73, 0xc3, 0xfb, 0x73, 0x4b, 0xfe, 0xd2, 0xe2, 0x7c, - 0xc1, 0xf1, 0xcb, 0xfa, 0x36, 0x8c, 0x89, 0x8e, 0x5b, 0xa7, 0x29, 0x0f, - 0xd9, 0x87, 0x0d, 0x96, 0xdf, 0xf6, 0x7e, 0x1e, 0xc0, 0xc3, 0x67, 0x2f, - 0xbf, 0xde, 0x09, 0xca, 0x83, 0xdb, 0x43, 0x9b, 0xff, 0x90, 0x0b, 0xde, - 0xdf, 0x5e, 0x85, 0x4e, 0x5f, 0x48, 0x11, 0xf1, 0xcb, 0xff, 0xe0, 0x3f, - 0xd9, 0x8a, 0xaa, 0xf2, 0xcf, 0xbc, 0x72, 0xa4, 0x8d, 0xa0, 0x90, 0x4c, - 0x8b, 0xb2, 0x3b, 0xff, 0x24, 0x33, 0xb8, 0x10, 0xa7, 0xc7, 0x2f, 0xb8, - 0x12, 0x15, 0x39, 0x7a, 0x5f, 0x2a, 0x72, 0xf0, 0x03, 0xf1, 0xcb, 0xff, - 0x9f, 0xf5, 0xf5, 0x34, 0x29, 0xed, 0x9c, 0xb8, 0x67, 0x39, 0x50, 0x8b, - 0xd0, 0x92, 0xa0, 0xfb, 0x8f, 0x28, 0x89, 0x6f, 0x1c, 0xbb, 0x58, 0x72, - 0xb4, 0x69, 0xff, 0x11, 0xbf, 0xf6, 0x80, 0xce, 0xa4, 0x31, 0xc4, 0xe5, - 0xff, 0x6e, 0x18, 0x39, 0x28, 0x13, 0x95, 0xa3, 0xf3, 0xf1, 0xed, 0xe6, - 0x9c, 0x33, 0x67, 0x2b, 0x0f, 0x1f, 0x80, 0x8a, 0xfd, 0xe4, 0xec, 0x71, - 0x39, 0x70, 0xce, 0x72, 0xf7, 0xa3, 0x47, 0x2a, 0x0f, 0x72, 0x62, 0x90, - 0x0b, 0xdc, 0xeb, 0x39, 0x7f, 0x2c, 0x20, 0x9d, 0x46, 0x1c, 0xbe, 0x0e, - 0x76, 0x0e, 0x54, 0x1f, 0x46, 0x0b, 0x39, 0x8d, 0xfa, 0x6d, 0xed, 0x18, - 0x72, 0xff, 0xfa, 0x76, 0xde, 0x5b, 0xde, 0x69, 0xb8, 0xd2, 0xa7, 0x2c, - 0x27, 0x2e, 0x51, 0x43, 0x95, 0x88, 0xa6, 0x72, 0x9f, 0xd5, 0x14, 0x10, - 0xb9, 0xa7, 0x38, 0x5e, 0x0e, 0xc8, 0xd9, 0x34, 0x7d, 0xd8, 0x7d, 0xbb, - 0x78, 0xc3, 0x73, 0x70, 0x80, 0xf4, 0x25, 0xd4, 0x86, 0x95, 0x43, 0xae, - 0x62, 0x9d, 0x06, 0x55, 0xe3, 0x30, 0x63, 0x91, 0x49, 0x7a, 0x93, 0x46, - 0xc6, 0xc2, 0xce, 0xca, 0x61, 0xf1, 0xf0, 0x21, 0x9e, 0xa4, 0xf5, 0x65, - 0x44, 0xef, 0x31, 0x24, 0xf2, 0xd0, 0xe5, 0x3d, 0xde, 0x19, 0xf0, 0x6c, - 0xc6, 0x91, 0x7a, 0xb4, 0x81, 0x95, 0xdf, 0xb6, 0x87, 0xd5, 0xed, 0xea, - 0x53, 0x4c, 0x5a, 0xe5, 0x1f, 0x4d, 0x78, 0xf7, 0x9a, 0xb6, 0x57, 0x6c, - 0xd4, 0x32, 0x55, 0xda, 0x7d, 0x7b, 0xde, 0x52, 0xff, 0xf4, 0xc2, 0x7e, - 0x1e, 0x5e, 0xe0, 0xd7, 0xd6, 0xbb, 0xb4, 0x48, 0xde, 0xbf, 0x8e, 0x10, - 0x5e, 0x46, 0xe7, 0x1a, 0x77, 0xb3, 0x74, 0x84, 0xe6, 0x93, 0xa3, 0x2a, - 0x52, 0x7c, 0xf8, 0x2d, 0x78, 0xf5, 0x00, + 0x67, 0x62, 0x16, 0x96, 0xad, 0x23, 0x96, 0x91, 0xcb, 0x48, 0xe5, 0xe6, + 0xdb, 0x6c, 0xe5, 0x96, 0x53, 0xe9, 0xa0, 0xa8, 0x3f, 0x65, 0x44, 0x50, + 0x47, 0xf3, 0x1b, 0xf8, 0x1b, 0xeb, 0xcb, 0x0e, 0x5f, 0xff, 0x6d, 0x17, + 0x83, 0xa8, 0x1c, 0x0e, 0x2a, 0x72, 0x98, 0x7f, 0x5e, 0x2d, 0xb7, 0x27, + 0x2c, 0xa9, 0xcb, 0x00, 0xe5, 0x09, 0xa3, 0xd8, 0x95, 0x61, 0xfb, 0xec, + 0x8b, 0xc6, 0xb7, 0x6d, 0x53, 0x96, 0xc3, 0x97, 0x03, 0xf8, 0x35, 0x01, + 0x18, 0xb9, 0x20, 0xe5, 0xfc, 0x30, 0xc1, 0x8c, 0x39, 0x7f, 0xf4, 0x3e, + 0xbd, 0xdc, 0x08, 0x3d, 0xb3, 0x97, 0x4a, 0x0e, 0x5e, 0xd8, 0x55, 0x39, + 0x53, 0xa3, 0x90, 0x25, 0xb3, 0x0a, 0xf4, 0xa8, 0x08, 0x8a, 0x0b, 0x5f, + 0xff, 0xff, 0x76, 0x3d, 0xb4, 0xde, 0xe3, 0xdd, 0x48, 0xd7, 0xec, 0x79, + 0x4b, 0xca, 0x9c, 0xb9, 0x39, 0x39, 0x74, 0x30, 0xe5, 0xff, 0xfa, 0x04, + 0x12, 0x94, 0x7b, 0xb8, 0xc5, 0x23, 0xf3, 0x97, 0xff, 0xc8, 0x20, 0x96, + 0x6f, 0x50, 0x92, 0x7d, 0x94, 0xa9, 0x22, 0x8f, 0xca, 0xd7, 0x2f, 0xec, + 0x32, 0x3f, 0xe7, 0x84, 0xbc, 0x88, 0x43, 0x0d, 0x5c, 0x8c, 0xc5, 0x54, + 0xc5, 0x91, 0x6a, 0x1f, 0x8f, 0x0a, 0x41, 0x8c, 0xb7, 0x71, 0x9d, 0x79, + 0x6b, 0x8b, 0xfb, 0x41, 0x75, 0x21, 0x73, 0x7f, 0xfb, 0xeb, 0x1e, 0x5f, + 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x8c, 0x5f, 0xb8, 0xc6, 0xa3, 0xf3, 0x97, + 0xe1, 0x7f, 0xe1, 0x43, 0x97, 0xfe, 0x4e, 0x65, 0xb1, 0xcf, 0x74, 0x07, + 0x2f, 0xf9, 0x35, 0xdc, 0xc1, 0x96, 0xce, 0x5b, 0x99, 0x1f, 0xb2, 0xcf, + 0xef, 0xfc, 0xf2, 0x5f, 0x51, 0x91, 0xa5, 0x4e, 0x5b, 0xec, 0x26, 0x61, + 0xd2, 0xaf, 0x42, 0x79, 0xb2, 0x9a, 0x93, 0x39, 0x77, 0x51, 0x9e, 0xb1, + 0x2d, 0xe9, 0x3e, 0x9b, 0x8c, 0x33, 0xd1, 0xc5, 0x5f, 0xfd, 0xf5, 0xe5, + 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x23, 0x95, 0xff, 0xef, 0xac, 0x79, 0x7d, + 0xcd, 0x2d, 0xdd, 0x66, 0x89, 0xc9, 0x7f, 0xbe, 0xe6, 0x96, 0xee, 0xb3, + 0x45, 0x98, 0xbf, 0xe9, 0x6d, 0xd9, 0xf7, 0xbe, 0xfc, 0xe5, 0xff, 0x70, + 0xb0, 0x71, 0x91, 0xcc, 0x30, 0xe5, 0xfe, 0xd4, 0x7b, 0xaf, 0xcc, 0x8e, + 0x5f, 0xff, 0xff, 0x44, 0xdd, 0x8f, 0x42, 0x89, 0xa9, 0xa3, 0xb9, 0xc7, + 0x3b, 0x81, 0xe3, 0x87, 0x2b, 0xf4, 0x5a, 0x89, 0xa5, 0xff, 0x66, 0xdf, + 0xdf, 0xa8, 0x32, 0x39, 0x7f, 0xb3, 0x7a, 0xd6, 0x73, 0xb3, 0x97, 0xb5, + 0x8c, 0x39, 0x7c, 0x83, 0x9b, 0x39, 0x6c, 0xf1, 0xbc, 0xe0, 0x1c, 0xbf, + 0xf2, 0x0c, 0x6e, 0x3d, 0x3e, 0x36, 0x72, 0xef, 0x8a, 0x1c, 0xbf, 0xb4, + 0xbe, 0xba, 0x70, 0xe7, 0x2f, 0xce, 0x31, 0xc4, 0x07, 0x2e, 0xe5, 0x87, + 0x2f, 0xfe, 0x68, 0xe3, 0xfe, 0x7a, 0x05, 0x3f, 0x39, 0x6f, 0xad, 0x4a, + 0xaf, 0xa8, 0x87, 0xac, 0xe4, 0x72, 0x3a, 0x0b, 0x83, 0x0a, 0x76, 0x7c, + 0x01, 0xae, 0x26, 0x4d, 0x0a, 0x14, 0x18, 0xbf, 0xdf, 0x73, 0x4b, 0x77, + 0x59, 0xa2, 0xdd, 0x5f, 0xc2, 0xff, 0x75, 0x3f, 0x4e, 0x5e, 0x4e, 0x7f, + 0x39, 0x7f, 0xf6, 0x9d, 0x7f, 0x83, 0x7e, 0x8e, 0x5b, 0x39, 0x70, 0xaa, + 0x72, 0xf9, 0x6e, 0xeb, 0x34, 0x52, 0x0a, 0xc3, 0xc5, 0xd0, 0xbd, 0xfe, + 0x97, 0x91, 0xbd, 0xfe, 0x87, 0x2f, 0xfd, 0x9d, 0x4e, 0x3d, 0xcc, 0x15, + 0x9c, 0xbc, 0xf2, 0xfa, 0x14, 0xc8, 0x72, 0x11, 0xbc, 0x90, 0xec, 0xd6, + 0xff, 0x20, 0x41, 0xed, 0xb0, 0x4e, 0x5e, 0x71, 0x91, 0xcb, 0x7d, 0x5a, + 0xa1, 0x3d, 0x18, 0x32, 0x33, 0xf7, 0x56, 0x6c, 0xce, 0xff, 0xef, 0xaf, + 0x2f, 0xb9, 0xa5, 0xbb, 0xac, 0xd1, 0x29, 0x2a, 0x75, 0xfd, 0x99, 0x95, + 0x18, 0xb4, 0xe8, 0x3f, 0xcb, 0x37, 0x18, 0x58, 0xfa, 0x52, 0xa7, 0x02, + 0xd5, 0xfc, 0x83, 0xec, 0x40, 0x9c, 0xba, 0x5e, 0x39, 0x78, 0x61, 0xb3, + 0x97, 0x47, 0xdd, 0x1b, 0x31, 0x17, 0xa9, 0x22, 0x2f, 0xcb, 0xd7, 0xb6, + 0x06, 0x1c, 0xb7, 0xde, 0x4f, 0x01, 0x08, 0xef, 0x0b, 0xc8, 0xe5, 0xfb, + 0x4b, 0x77, 0x59, 0xa2, 0x76, 0x5f, 0xfd, 0x9d, 0x17, 0x90, 0x3f, 0x63, + 0xc8, 0xe5, 0xe7, 0x97, 0xdc, 0x3f, 0x81, 0x34, 0xba, 0x76, 0xb3, 0x97, + 0xff, 0xe4, 0x08, 0x19, 0x1c, 0x0e, 0x11, 0x81, 0xc5, 0x9c, 0xbf, 0xd2, + 0x8d, 0x4f, 0x1a, 0x9c, 0xe5, 0xff, 0xba, 0x2f, 0x20, 0x7e, 0xc7, 0x91, + 0xca, 0x83, 0xf4, 0xc3, 0x5b, 0x7d, 0xc4, 0xf2, 0x99, 0x09, 0x3e, 0x99, + 0xb8, 0xd8, 0xc3, 0x26, 0xf9, 0x35, 0x1c, 0x4e, 0x5f, 0xfc, 0xd1, 0xc7, + 0xfc, 0xf4, 0x0a, 0x7e, 0x72, 0xdf, 0x76, 0x7d, 0x0a, 0x11, 0xdf, 0xfc, + 0xec, 0xee, 0x2d, 0xfb, 0x0a, 0x48, 0xe5, 0xe4, 0x0b, 0x9c, 0xbf, 0xf8, + 0x73, 0xaf, 0x3e, 0x6c, 0x5f, 0x93, 0x97, 0x34, 0xfa, 0x14, 0x51, 0x75, + 0x13, 0x63, 0x75, 0x25, 0x78, 0x6c, 0x8f, 0xd3, 0x70, 0xc2, 0x69, 0x0c, + 0xdb, 0xff, 0xf8, 0x2f, 0xef, 0xb9, 0xb8, 0x1e, 0x7f, 0xde, 0xe3, 0xf3, + 0x97, 0xed, 0x2d, 0xdd, 0x66, 0x88, 0xb1, 0x7f, 0xe7, 0x97, 0xdc, 0xd2, + 0xdd, 0xd6, 0x68, 0x97, 0x57, 0xff, 0xf6, 0x07, 0xb0, 0xa7, 0xdf, 0x0b, + 0xff, 0xbd, 0xc7, 0xe5, 0x2d, 0xf7, 0x11, 0xbe, 0xc3, 0x46, 0x89, 0x97, + 0xff, 0x31, 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x26, 0x25, 0xff, 0xf6, + 0x2e, 0x3e, 0xf5, 0xd1, 0xa2, 0x7f, 0x81, 0x39, 0x5f, 0x51, 0x49, 0xd5, + 0x2b, 0xf6, 0x96, 0xee, 0xb3, 0x45, 0x52, 0xb6, 0x1c, 0xac, 0x3c, 0x45, + 0x4d, 0x2f, 0xfc, 0x07, 0xd4, 0x87, 0x1b, 0x7f, 0xce, 0x5f, 0xfc, 0xfb, + 0xd2, 0x37, 0xee, 0xa6, 0xa4, 0x72, 0xff, 0xb4, 0xfd, 0xe6, 0x59, 0xef, + 0xa1, 0x44, 0x27, 0x4f, 0xeb, 0xea, 0x3e, 0x9e, 0x14, 0xd7, 0xff, 0xbe, + 0xb1, 0xe5, 0xf7, 0x34, 0xb7, 0x75, 0x9a, 0x27, 0x45, 0xfe, 0x47, 0xd4, + 0x49, 0xf8, 0x9c, 0xbf, 0x4d, 0x13, 0x46, 0xce, 0x5f, 0xcd, 0xe2, 0x71, + 0xc1, 0x39, 0x48, 0x7a, 0xfb, 0x29, 0xbc, 0x9d, 0x83, 0x9f, 0x4d, 0x0d, + 0xff, 0xc0, 0xdf, 0xa3, 0x9f, 0xa0, 0x99, 0x18, 0x72, 0x98, 0x7e, 0xdd, + 0x2d, 0xbf, 0xf3, 0xcb, 0xee, 0x69, 0x6e, 0xeb, 0x34, 0x4e, 0xeb, 0xf7, + 0x80, 0xec, 0x42, 0x97, 0xfe, 0x18, 0xf6, 0x6f, 0x33, 0x99, 0x1c, 0xa0, + 0xa7, 0xe7, 0x91, 0x90, 0xb0, 0x89, 0xd3, 0x3c, 0x4f, 0x7f, 0xc1, 0x89, + 0x47, 0xd6, 0xf7, 0xf9, 0xcb, 0xfa, 0x3e, 0xfe, 0x38, 0x13, 0x95, 0xf5, + 0x17, 0x78, 0x9e, 0x27, 0xb7, 0xff, 0xbe, 0xb1, 0xe5, 0xf7, 0x34, 0xb7, + 0x75, 0x9a, 0x28, 0x55, 0xff, 0xf3, 0xfa, 0x58, 0x28, 0x1f, 0xbb, 0x9e, + 0x34, 0x72, 0xff, 0xff, 0xf7, 0x40, 0xc6, 0x3c, 0xbe, 0xaf, 0xa0, 0xf4, + 0x0e, 0x4e, 0xa8, 0x22, 0x63, 0x97, 0xe0, 0x73, 0xe4, 0x59, 0xcb, 0xf6, + 0x7f, 0x8e, 0x27, 0x2f, 0xb6, 0x8d, 0xf8, 0xe5, 0xe8, 0xff, 0xec, 0xe7, + 0xe4, 0x25, 0x3e, 0x26, 0xa4, 0x4c, 0xc8, 0x61, 0xdf, 0x7f, 0xfb, 0xeb, + 0x1e, 0x5f, 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x92, 0x5f, 0xff, 0xec, 0xdf, + 0xd5, 0x32, 0x6e, 0xbb, 0x3d, 0xd8, 0xf0, 0x18, 0x72, 0xa1, 0x93, 0x45, + 0x3c, 0x67, 0xd2, 0x86, 0xea, 0xe3, 0x63, 0xd1, 0x4b, 0x25, 0x84, 0x7e, + 0x60, 0x2b, 0x5e, 0x8e, 0x0c, 0x04, 0xed, 0x16, 0xaf, 0xf7, 0xdc, 0xd2, + 0xdd, 0xd6, 0x68, 0x89, 0x17, 0xff, 0xbe, 0xb1, 0xe5, 0xf7, 0x34, 0xb7, + 0x75, 0x9a, 0x25, 0xe5, 0xff, 0xd1, 0xc5, 0xe6, 0x4d, 0x73, 0x28, 0x98, + 0xe5, 0xe6, 0xa5, 0x9f, 0x9c, 0xbe, 0xd0, 0x3d, 0xb3, 0x97, 0xed, 0x7e, + 0xc4, 0xd9, 0xcb, 0xd0, 0x3c, 0x9c, 0xbf, 0x79, 0x46, 0x0c, 0x1c, 0xb2, + 0x74, 0xf1, 0x04, 0x72, 0xff, 0xf7, 0x78, 0xc0, 0xfe, 0xd7, 0x81, 0xcd, + 0x72, 0x72, 0xe8, 0xf1, 0xcb, 0xfe, 0x79, 0xf5, 0x1c, 0xc9, 0x18, 0x72, + 0xff, 0xf0, 0x02, 0x9a, 0x52, 0x6e, 0x00, 0x38, 0xcc, 0x72, 0xa4, 0x98, + 0xb2, 0x13, 0x7e, 0xa0, 0x22, 0xdb, 0x3a, 0xbf, 0xbf, 0xec, 0x69, 0x18, + 0x72, 0xff, 0xd3, 0x6e, 0x38, 0xbf, 0x63, 0x99, 0x8e, 0x54, 0x1f, 0x8b, + 0x97, 0x5f, 0x27, 0x02, 0x8c, 0x39, 0x7e, 0xc9, 0xf3, 0x6c, 0x39, 0x7f, + 0x3c, 0xef, 0xb7, 0xfc, 0xe5, 0xff, 0xd3, 0x7c, 0x50, 0x63, 0x8b, 0xf1, + 0x89, 0x8e, 0x51, 0xcb, 0xf4, 0x9f, 0xcf, 0xc4, 0xe5, 0xf9, 0xf7, 0x1c, + 0x70, 0xe5, 0x4c, 0x7a, 0x3c, 0x4a, 0x6a, 0x11, 0x9b, 0x89, 0x8e, 0xb9, + 0x76, 0xa0, 0xe5, 0x05, 0x70, 0x35, 0x08, 0xe6, 0x8e, 0x0f, 0x50, 0xbb, + 0xe9, 0x00, 0x93, 0x78, 0xa3, 0x8c, 0x3e, 0xf8, 0x0b, 0x6e, 0xc1, 0x39, + 0x7f, 0x7c, 0xdf, 0x71, 0x3c, 0x72, 0x82, 0x78, 0x88, 0x2b, 0x70, 0x79, + 0x39, 0x7f, 0x08, 0x3d, 0x34, 0x2a, 0x72, 0xf7, 0x0e, 0x9a, 0x39, 0x64, + 0x73, 0xd0, 0x01, 0x7d, 0xf8, 0x72, 0x75, 0x38, 0x9c, 0xbe, 0xc9, 0xd4, + 0xe2, 0x72, 0xfc, 0x18, 0xe4, 0x2f, 0xf0, 0xf4, 0x44, 0xae, 0xff, 0xf9, + 0x35, 0xf3, 0xb0, 0x9e, 0xd8, 0x16, 0x08, 0x39, 0x7c, 0x93, 0xfe, 0xd6, + 0x72, 0xf9, 0x6e, 0xeb, 0x34, 0x52, 0xeb, 0xe1, 0xf4, 0x68, 0xe5, 0xff, + 0x66, 0x9a, 0xf0, 0x39, 0xae, 0x4e, 0x52, 0x1e, 0xef, 0x12, 0x1a, 0x92, + 0x6c, 0xca, 0xa0, 0x4c, 0xa3, 0xa2, 0x7e, 0xc2, 0x2e, 0xfe, 0x0f, 0x31, + 0xa4, 0xe4, 0xe5, 0xf7, 0xa7, 0xc6, 0xce, 0x52, 0x1e, 0x98, 0x97, 0xdf, + 0x91, 0x5d, 0x66, 0xce, 0x5f, 0xfa, 0x06, 0x3b, 0xf0, 0x02, 0x05, 0x9c, + 0xbc, 0x07, 0xd9, 0xcb, 0xe9, 0x80, 0xf3, 0x1c, 0xbf, 0x47, 0xef, 0xce, + 0xce, 0x5e, 0x14, 0xfc, 0xe5, 0xec, 0xf6, 0xce, 0x54, 0x1b, 0x8d, 0x8e, + 0x54, 0x93, 0x28, 0x09, 0x44, 0xc7, 0xfd, 0x1c, 0xfc, 0x93, 0xcc, 0x37, + 0xe6, 0xb7, 0x10, 0xf0, 0x1c, 0xba, 0x39, 0x39, 0x7f, 0xdf, 0xef, 0x51, + 0xcc, 0x91, 0x87, 0x2f, 0x79, 0xf8, 0x9c, 0xbf, 0x4e, 0x09, 0xa1, 0xac, + 0xe5, 0xf0, 0x26, 0x86, 0xb3, 0x97, 0x3c, 0xff, 0x0f, 0x4e, 0x72, 0xda, + 0x84, 0x6e, 0xb9, 0xd8, 0x1c, 0x6f, 0xf9, 0x37, 0x32, 0x0f, 0xa3, 0xf3, + 0x97, 0xff, 0x0f, 0xb8, 0xc6, 0xb6, 0xe3, 0x0d, 0x67, 0x2a, 0x48, 0xae, + 0x61, 0x76, 0xce, 0x6f, 0xf4, 0x35, 0xee, 0x18, 0xfe, 0x39, 0x73, 0x89, + 0xcb, 0xfe, 0x8f, 0xfe, 0x76, 0x18, 0xe2, 0x72, 0xb9, 0x3c, 0xfe, 0x22, + 0xb5, 0x24, 0x54, 0xea, 0x10, 0x97, 0xf4, 0x36, 0x9d, 0x03, 0x59, 0xcb, + 0xfb, 0x99, 0x6d, 0xc7, 0x93, 0x95, 0x0a, 0xcc, 0x24, 0x5b, 0x91, 0xd1, + 0x24, 0x36, 0x74, 0x50, 0xa1, 0x8d, 0xff, 0x86, 0x6f, 0x9a, 0x8e, 0x64, + 0x8c, 0x39, 0x74, 0x30, 0xe5, 0x41, 0xec, 0x69, 0x0a, 0xfe, 0x81, 0x9b, + 0xc8, 0xa9, 0xcb, 0xfe, 0x96, 0x6a, 0x6c, 0x18, 0x61, 0xcb, 0xf7, 0xf0, + 0xbc, 0x61, 0xcb, 0xfd, 0x93, 0xee, 0x26, 0x06, 0x8e, 0x52, 0x22, 0x57, + 0x47, 0x02, 0x51, 0x74, 0xb0, 0xe5, 0xfb, 0x6a, 0xe9, 0xdb, 0x39, 0x78, + 0x61, 0x87, 0x28, 0x27, 0x8b, 0xa2, 0xab, 0xd1, 0xfe, 0xce, 0x54, 0x23, + 0x20, 0x25, 0xd8, 0xb6, 0xd9, 0x15, 0xf3, 0xf5, 0xe7, 0x39, 0x7e, 0xe8, + 0x15, 0xc1, 0x39, 0x7f, 0x9b, 0x17, 0xf4, 0x9c, 0x27, 0x2f, 0xde, 0x52, + 0x78, 0xe9, 0xcb, 0xfe, 0x8e, 0xed, 0xfd, 0x1a, 0xe0, 0x39, 0x7f, 0xe6, + 0x38, 0x54, 0x9a, 0x50, 0x3c, 0x9c, 0xa0, 0x9f, 0xe2, 0x1d, 0xdf, 0x6b, + 0xf5, 0x38, 0x9c, 0xbc, 0x8d, 0xf8, 0xe5, 0x74, 0xf1, 0x36, 0x4f, 0x53, + 0xa7, 0x54, 0x12, 0x2e, 0x4a, 0x26, 0x33, 0xec, 0x29, 0xbc, 0xcb, 0x7f, + 0x87, 0xd9, 0xb4, 0x7e, 0x9c, 0xbf, 0xef, 0xd3, 0xb9, 0xa7, 0x9b, 0x67, + 0x2f, 0xff, 0xd1, 0x21, 0x89, 0xd4, 0x9b, 0x7d, 0xce, 0x0d, 0x7e, 0x72, + 0xfe, 0xf8, 0xcc, 0xf3, 0xf8, 0xe5, 0xfd, 0xd4, 0x0a, 0x69, 0x67, 0x2c, + 0xb3, 0x97, 0x73, 0xbc, 0x3e, 0xd5, 0x97, 0xb9, 0x6d, 0xe8, 0x40, 0x9c, + 0xa8, 0x4e, 0x27, 0x93, 0x16, 0x1d, 0x3c, 0x32, 0x76, 0x75, 0x7f, 0xb1, + 0xb9, 0x26, 0xc0, 0xc3, 0x97, 0x71, 0xd9, 0xcb, 0xf8, 0x1b, 0x89, 0x81, + 0xa3, 0x97, 0xec, 0x9f, 0x3b, 0xb3, 0x95, 0x07, 0xe1, 0xd1, 0x91, 0x2f, + 0xbd, 0x9a, 0xd9, 0xca, 0x59, 0xe4, 0xf1, 0x2d, 0xbf, 0xef, 0xe3, 0xf5, + 0x38, 0xc0, 0xf0, 0x1c, 0xa8, 0x4d, 0x47, 0x21, 0xda, 0x84, 0x97, 0xff, + 0xff, 0x76, 0x35, 0xca, 0xd3, 0x9f, 0x8a, 0xbf, 0xcd, 0xf5, 0xd7, 0x02, + 0x13, 0x97, 0xc8, 0xab, 0x4c, 0x39, 0x7f, 0x29, 0xe8, 0x9c, 0x79, 0x39, + 0x78, 0x51, 0x87, 0x2b, 0x47, 0xdf, 0xf9, 0x27, 0x8c, 0x2f, 0xf0, 0xc3, + 0x8f, 0xb0, 0x4e, 0x5f, 0xe8, 0xe7, 0x6d, 0x71, 0xa5, 0x4e, 0x5f, 0xee, + 0xbc, 0xc9, 0xa8, 0x9c, 0xe5, 0xfd, 0x9c, 0x0c, 0x8c, 0xf1, 0xcb, 0xb1, + 0x87, 0x28, 0x29, 0xfb, 0xe4, 0x39, 0xd8, 0x61, 0xd2, 0xf7, 0x38, 0x01, + 0xa7, 0x12, 0xfb, 0xf7, 0x02, 0x32, 0x36, 0x72, 0xfc, 0xfc, 0x73, 0x5b, + 0x39, 0x41, 0x3d, 0x36, 0x15, 0x5f, 0xba, 0xe2, 0x8c, 0x39, 0x7c, 0xac, + 0xdb, 0x83, 0x97, 0xf7, 0xfc, 0xff, 0x9a, 0xc3, 0x97, 0xf2, 0xe1, 0x3c, + 0x92, 0x39, 0x7f, 0x3f, 0xec, 0x8c, 0xf1, 0xca, 0x84, 0x44, 0xe1, 0x82, + 0x16, 0x5f, 0xe7, 0xff, 0x71, 0xd8, 0xd9, 0xcb, 0xf7, 0x3e, 0xde, 0x4e, + 0x72, 0xec, 0x9c, 0xe5, 0x39, 0xe0, 0x89, 0x55, 0x42, 0x76, 0xd8, 0x44, + 0x84, 0xdd, 0x85, 0x68, 0x96, 0xed, 0xd2, 0xef, 0xd6, 0x72, 0xdb, 0x39, + 0x72, 0x2b, 0xb3, 0x52, 0x01, 0x8b, 0xdf, 0xba, 0xce, 0x5f, 0x37, 0x36, + 0xe0, 0xe5, 0xfd, 0xb1, 0x79, 0xe3, 0xc7, 0x2f, 0xd3, 0xbe, 0xf2, 0x47, + 0x2f, 0xff, 0x83, 0x9c, 0x5f, 0x53, 0x29, 0x27, 0xf3, 0xb0, 0xe5, 0x41, + 0xfd, 0xa1, 0x45, 0xfc, 0xfc, 0xfe, 0xc4, 0xd9, 0xca, 0x84, 0xce, 0x39, + 0x1d, 0x98, 0x93, 0x50, 0xa8, 0xe9, 0x05, 0xfe, 0xf2, 0x36, 0xf3, 0x43, + 0x0e, 0x5b, 0xef, 0x08, 0xde, 0x06, 0x35, 0x69, 0x11, 0x38, 0x61, 0x3c, + 0x36, 0x64, 0x42, 0x16, 0x8c, 0x8f, 0x77, 0x98, 0x52, 0xa4, 0x69, 0x13, + 0x4b, 0x8a, 0xd4, 0x2e, 0x98, 0x43, 0xd8, 0xe2, 0xde, 0x3e, 0x6f, 0xe3, + 0xe9, 0x18, 0xe8, 0x37, 0x28, 0xab, 0xd2, 0x9c, 0xda, 0x42, 0x09, 0x48, + 0xd9, 0x78, 0x14, 0x6f, 0xf7, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0xa7, 0x17, + 0xf9, 0x90, 0xcc, 0xe0, 0x8f, 0x1c, 0xbe, 0xcd, 0xa9, 0x23, 0x97, 0xfe, + 0x4d, 0x3e, 0xfb, 0x98, 0x2b, 0x39, 0x7e, 0x66, 0xb5, 0x9b, 0x39, 0x7f, + 0xfe, 0xe8, 0x3d, 0xa8, 0xf6, 0xf1, 0x7b, 0x8d, 0x2c, 0xe5, 0xff, 0x6d, + 0x15, 0xc9, 0x47, 0xfb, 0x39, 0x7f, 0xff, 0x7b, 0x26, 0x14, 0xdf, 0xa1, + 0x44, 0xd4, 0xd1, 0xd3, 0x97, 0xf9, 0x18, 0x18, 0xd8, 0x04, 0xe5, 0xfc, + 0xfc, 0xef, 0xe6, 0xd4, 0x39, 0x7e, 0xf7, 0x32, 0x86, 0xce, 0x5f, 0xce, + 0xa6, 0x71, 0x8d, 0x9c, 0xac, 0x3d, 0x90, 0x15, 0x5f, 0xf9, 0x39, 0xd8, + 0xe0, 0x7a, 0xed, 0x9c, 0xbf, 0xfe, 0xc9, 0xf3, 0x9f, 0x6d, 0x06, 0x3f, + 0x76, 0x1c, 0xa5, 0x51, 0x1f, 0xb3, 0xfb, 0xff, 0x67, 0x63, 0x59, 0xf5, + 0xb6, 0xdb, 0x29, 0x72, 0x36, 0x72, 0xe9, 0xfe, 0xc2, 0xb9, 0x39, 0x1a, + 0x84, 0x8f, 0x0f, 0x16, 0x51, 0xca, 0xb2, 0x1d, 0x75, 0x73, 0xf3, 0x21, + 0x84, 0x5f, 0xa1, 0x60, 0xd0, 0x93, 0x81, 0x0e, 0xfd, 0xa5, 0xbb, 0xac, + 0xd1, 0x5e, 0x2f, 0xff, 0xec, 0x0f, 0x61, 0x4f, 0xbe, 0x17, 0xff, 0x7b, + 0x8f, 0xca, 0x5b, 0xee, 0x22, 0x4d, 0xa1, 0xa5, 0xff, 0xdf, 0x5e, 0x5f, + 0x73, 0x4b, 0x77, 0x59, 0xa2, 0x47, 0x5e, 0x5e, 0x30, 0xe5, 0xe4, 0xfe, + 0x0e, 0x5e, 0x5e, 0x30, 0xa7, 0xd2, 0xf2, 0xfd, 0xa5, 0xbb, 0xac, 0xd1, + 0x24, 0x2f, 0xff, 0xe8, 0x4d, 0x27, 0x04, 0x0c, 0xf1, 0xe4, 0xeb, 0xce, + 0x72, 0xff, 0xf3, 0xfa, 0x6d, 0xe0, 0x42, 0x07, 0xd4, 0x8e, 0x5f, 0xfe, + 0x1c, 0xfd, 0xa6, 0x6a, 0x27, 0x7d, 0x2c, 0xe5, 0xd2, 0xfb, 0x09, 0xaa, + 0x61, 0x6f, 0x4d, 0x3f, 0x5c, 0xf2, 0x5d, 0xfb, 0x3b, 0xf7, 0x18, 0x72, + 0xdf, 0x61, 0x50, 0x6b, 0xc7, 0x19, 0xe5, 0x8b, 0xff, 0xbe, 0xbc, 0xbe, + 0xe6, 0x96, 0xee, 0xb3, 0x44, 0x94, 0xbf, 0x69, 0x6e, 0xeb, 0x34, 0x5e, + 0x2b, 0xfe, 0x97, 0xdc, 0xd2, 0xdd, 0xd6, 0x68, 0x93, 0x56, 0xfb, 0x87, + 0xf6, 0xe6, 0x97, 0xfd, 0xa5, 0xc4, 0xf9, 0x83, 0xe3, 0x97, 0xf4, 0x6d, + 0x19, 0x13, 0x1c, 0xb7, 0x4e, 0x52, 0x1f, 0xb3, 0x0e, 0x1b, 0x2d, 0xbf, + 0xec, 0xfc, 0x3d, 0x81, 0x86, 0xce, 0x5f, 0x7f, 0xbc, 0x13, 0x95, 0x07, + 0xb6, 0x87, 0x37, 0xff, 0x20, 0x17, 0xbd, 0xbe, 0xbd, 0x0a, 0x9c, 0xbe, + 0x90, 0x23, 0x93, 0x97, 0xff, 0xc0, 0x7e, 0x73, 0x15, 0x55, 0xe5, 0x9c, + 0xf8, 0xe5, 0x49, 0x1b, 0x41, 0x20, 0x99, 0x17, 0x64, 0x77, 0xfe, 0x48, + 0x67, 0x70, 0x21, 0x4e, 0x4e, 0x5f, 0x70, 0x24, 0x2a, 0x72, 0xf4, 0xb9, + 0x54, 0xe5, 0xe0, 0x07, 0x93, 0x97, 0xff, 0x3f, 0xeb, 0xea, 0x68, 0x53, + 0xdb, 0x39, 0x70, 0xce, 0x72, 0xa1, 0x17, 0xa1, 0x25, 0x41, 0xf7, 0x1e, + 0x51, 0x12, 0xde, 0x39, 0x76, 0xb0, 0xe5, 0x68, 0xd3, 0xfe, 0x23, 0x7f, + 0xed, 0x01, 0x9d, 0x48, 0x63, 0x89, 0xcb, 0xfe, 0xdc, 0x30, 0x72, 0x50, + 0x27, 0x2b, 0x47, 0xe7, 0xe3, 0xdb, 0xcd, 0x38, 0x66, 0xce, 0x56, 0x1e, + 0x3f, 0x01, 0x15, 0xfb, 0xc9, 0xd8, 0xe2, 0x72, 0xe1, 0x9c, 0xe5, 0xef, + 0x46, 0x8e, 0x54, 0x1e, 0xe4, 0xc5, 0x20, 0x17, 0xb9, 0xd6, 0x72, 0xfe, + 0x58, 0x41, 0x3a, 0x8c, 0x39, 0x7c, 0x1c, 0xec, 0x1c, 0xa8, 0x3e, 0x8c, + 0x16, 0x73, 0x1b, 0xf4, 0xdb, 0xda, 0x30, 0xe5, 0xff, 0xf4, 0xed, 0xbc, + 0xb7, 0xbc, 0xd3, 0x71, 0xa5, 0x4e, 0x58, 0x4e, 0x5c, 0xa2, 0x87, 0x2b, + 0x11, 0x4c, 0xe5, 0x3f, 0xaa, 0x28, 0x21, 0x73, 0x4f, 0xb0, 0xbc, 0x1d, + 0x91, 0xb2, 0x68, 0xfb, 0xb0, 0xfb, 0x76, 0xf1, 0x86, 0xe6, 0xe1, 0x01, + 0xe8, 0x4b, 0xa9, 0x0d, 0x2a, 0x87, 0x5c, 0xc5, 0x3a, 0x0c, 0xab, 0xc6, + 0x60, 0xc7, 0x22, 0x92, 0xf5, 0x26, 0x8d, 0x8d, 0x85, 0x9d, 0x94, 0xc3, + 0xe3, 0xe0, 0x43, 0x3d, 0x49, 0xea, 0xca, 0x89, 0xde, 0x65, 0xb9, 0xe5, + 0xa1, 0xca, 0x7b, 0xbc, 0x33, 0xe0, 0xd9, 0x8d, 0x22, 0xf5, 0x69, 0x03, + 0x2b, 0xbf, 0x6d, 0x0e, 0x6b, 0xdb, 0xd4, 0xa6, 0x98, 0xb5, 0xca, 0x3e, + 0x9a, 0xf1, 0xef, 0x35, 0x6c, 0xae, 0xd9, 0xa8, 0x64, 0xab, 0xb4, 0xfa, + 0xf7, 0xbc, 0xa5, 0xff, 0xe9, 0x84, 0xfc, 0x3c, 0xbd, 0xc1, 0xaf, 0xad, + 0x77, 0x68, 0x91, 0xbd, 0x7f, 0x1c, 0x20, 0xbc, 0x8d, 0xce, 0x34, 0xf2, + 0xd6, 0xe9, 0x09, 0xcd, 0x27, 0x46, 0x54, 0xa4, 0xf9, 0xf0, 0x5a, 0xf1, + 0xea, }; -static const unsigned kPreloadedHSTSBits = 394224; +static const unsigned kPreloadedHSTSBits = 394279; -static const unsigned kHSTSRootPosition = 393600; +static const unsigned kHSTSRootPosition = 393655; #endif // NET_HTTP_TRANSPORT_SECURITY_STATE_STATIC_H_
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json index cd69dd64..792ebd9 100644 --- a/net/http/transport_security_state_static.json +++ b/net/http/transport_security_state_static.json
@@ -5522,7 +5522,8 @@ { "name": "genxbeats.com", "include_subdomains": true, "mode": "force-https" }, { "name": "gm-assicurazioni.it", "include_subdomains": true, "mode": "force-https" }, { "name": "goggs.eu", "include_subdomains": true, "mode": "force-https" }, - { "name": "gpo.gov", "include_subdomains": true, "mode": "force-https" }, + { "name": "gpo.gov", "include_subdomains": false, "mode": "force-https" }, + { "name": "www.gpo.gov", "include_subdomains": true, "mode": "force-https" }, { "name": "grannyshouse.de", "include_subdomains": true, "mode": "force-https" }, { "name": "gurom.lv", "include_subdomains": true, "mode": "force-https" }, { "name": "haozi.me", "include_subdomains": true, "mode": "force-https" },
diff --git a/net/quic/quic_http_stream.cc b/net/quic/quic_http_stream.cc index 3cc204f..20d1e36 100644 --- a/net/quic/quic_http_stream.cc +++ b/net/quic/quic_http_stream.cc
@@ -449,6 +449,10 @@ if (rv < 0) return rv; + // If the stream is already closed, don't read the request the body. + if (!stream_) + return response_status_; + next_state_ = request_body_stream_ ? STATE_READ_REQUEST_BODY : STATE_OPEN; return OK;
diff --git a/net/quic/quic_network_transaction_unittest.cc b/net/quic/quic_network_transaction_unittest.cc index e4ccdc71..d6f5c3c 100644 --- a/net/quic/quic_network_transaction_unittest.cc +++ b/net/quic/quic_network_transaction_unittest.cc
@@ -10,6 +10,7 @@ #include "base/run_loop.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" +#include "net/base/chunked_upload_data_stream.h" #include "net/base/network_quality_estimator.h" #include "net/base/socket_performance_watcher.h" #include "net/base/test_completion_callback.h" @@ -2259,5 +2260,34 @@ EXPECT_TRUE(rtt_observer_.rtt_notification_received()); } +TEST_P(QuicNetworkTransactionTest, QuicUpload) { + params_.origin_to_force_quic_on = + HostPortPair::FromString("mail.example.com:443"); + + MockRead reads[] = {MockRead(SYNCHRONOUS, ERR_IO_PENDING, 0)}; + MockWrite writes[] = {MockWrite(SYNCHRONOUS, ERR_FAILED, 1)}; + SequencedSocketData socket_data(reads, arraysize(reads), writes, + arraysize(writes)); + socket_factory_.AddSocketDataProvider(&socket_data); + + // The non-alternate protocol job needs to hang in order to guarantee that + // the alternate-protocol job will "win". + AddHangingNonAlternateProtocolSocketData(); + + CreateSession(); + request_.method = "POST"; + ChunkedUploadDataStream upload_data(0); + upload_data.AppendData("1", 1, true); + + request_.upload_data_stream = &upload_data; + + scoped_ptr<HttpNetworkTransaction> trans( + new HttpNetworkTransaction(DEFAULT_PRIORITY, session_.get())); + TestCompletionCallback callback; + int rv = trans->Start(&request_, callback.callback(), net_log_.bound()); + EXPECT_EQ(ERR_IO_PENDING, rv); + EXPECT_NE(OK, callback.WaitForResult()); +} + } // namespace test } // namespace net
diff --git a/net/quic/quic_stream_factory.cc b/net/quic/quic_stream_factory.cc index f05c1176..858f1cb9 100644 --- a/net/quic/quic_stream_factory.cc +++ b/net/quic/quic_stream_factory.cc
@@ -566,7 +566,7 @@ int threshold_timeouts_with_open_streams, int socket_receive_buffer_size, bool delay_tcp_race, - bool store_server_configs_in_properties, + int max_server_configs_stored_in_properties, bool close_sessions_on_ip_change, int idle_connection_timeout_seconds, bool migrate_sessions_on_network_change, @@ -615,7 +615,6 @@ yield_after_packets_(kQuicYieldAfterPacketsRead), yield_after_duration_(QuicTime::Delta::FromMilliseconds( kQuicYieldAfterDurationMilliseconds)), - store_server_configs_in_properties_(store_server_configs_in_properties), close_sessions_on_ip_change_(close_sessions_on_ip_change), migrate_sessions_on_network_change_( migrate_sessions_on_network_change && @@ -653,7 +652,7 @@ // When disk cache is used to store the server configs, HttpCache code calls // |set_quic_server_info_factory| if |quic_server_info_factory_| wasn't // created. - if (store_server_configs_in_properties_) { + if (max_server_configs_stored_in_properties > 0) { quic_server_info_factory_.reset( new PropertiesBasedQuicServerInfoFactory(http_server_properties_)); } @@ -1546,7 +1545,7 @@ } } - if (!store_server_configs_in_properties_) + if (http_server_properties_->max_server_configs_stored_in_properties() == 0) return; // Create a temporary QuicServerInfo object to deserialize and to populate the // in-memory crypto server config cache.
diff --git a/net/quic/quic_stream_factory.h b/net/quic/quic_stream_factory.h index b0a8999d..9a7cfe5 100644 --- a/net/quic/quic_stream_factory.h +++ b/net/quic/quic_stream_factory.h
@@ -147,7 +147,7 @@ int threshold_public_resets_post_handshake, int socket_receive_buffer_size, bool delay_tcp_race, - bool store_server_configs_in_properties, + int max_server_configs_stored_in_properties, bool close_sessions_on_ip_change, int idle_connection_timeout_seconds, bool migrate_sessions_on_network_change, @@ -276,7 +276,7 @@ bool enable_port_selection() const { return enable_port_selection_; } bool has_quic_server_info_factory() { - return !quic_server_info_factory_.get(); + return quic_server_info_factory_.get() != nullptr; } void set_quic_server_info_factory( @@ -291,10 +291,6 @@ bool delay_tcp_race() const { return delay_tcp_race_; } - bool store_server_configs_in_properties() const { - return store_server_configs_in_properties_; - } - private: class Job; friend class test::QuicStreamFactoryPeer; @@ -482,9 +478,6 @@ int yield_after_packets_; QuicTime::Delta yield_after_duration_; - // Set if server configs are to be stored in HttpServerProperties. - bool store_server_configs_in_properties_; - // Set if all sessions should be closed when any local IP address changes. const bool close_sessions_on_ip_change_;
diff --git a/net/quic/quic_stream_factory_test.cc b/net/quic/quic_stream_factory_test.cc index 1e1e1d61..8754453 100644 --- a/net/quic/quic_stream_factory_test.cc +++ b/net/quic/quic_stream_factory_test.cc
@@ -217,7 +217,6 @@ threshold_public_resets_post_handshake_(2), receive_buffer_size_(0), delay_tcp_race_(false), - store_server_configs_in_properties_(false), close_sessions_on_ip_change_(false), idle_connection_timeout_seconds_(kIdleConnectionTimeoutSeconds), migrate_sessions_on_network_change_(false) { @@ -239,11 +238,13 @@ max_number_of_lossy_connections_, packet_loss_threshold_, max_disabled_reasons_, threshold_timeouts_with_open_streams_, threshold_public_resets_post_handshake_, receive_buffer_size_, - delay_tcp_race_, store_server_configs_in_properties_, + delay_tcp_race_, /*max_server_configs_stored_in_properties*/ 0, close_sessions_on_ip_change_, idle_connection_timeout_seconds_, migrate_sessions_on_network_change_, QuicTagVector())); factory_->set_require_confirmation(false); + EXPECT_FALSE(factory_->has_quic_server_info_factory()); factory_->set_quic_server_info_factory(new MockQuicServerInfoFactory()); + EXPECT_TRUE(factory_->has_quic_server_info_factory()); } void InitializeConnectionMigrationTest( @@ -411,7 +412,6 @@ int threshold_public_resets_post_handshake_; int receive_buffer_size_; bool delay_tcp_race_; - bool store_server_configs_in_properties_; bool close_sessions_on_ip_change_; int idle_connection_timeout_seconds_; bool migrate_sessions_on_network_change_; @@ -3099,7 +3099,6 @@ } TEST_P(QuicStreamFactoryTest, MaybeInitialize) { - store_server_configs_in_properties_ = true; idle_connection_timeout_seconds_ = 500; Initialize(); ProofVerifyDetailsChromium verify_details = DefaultProofVerifyDetails(); @@ -3118,6 +3117,8 @@ http_server_properties_.SetAlternativeServices( host_port_pair_, alternative_service_info_vector); + http_server_properties_.SetMaxServerConfigsStoredInProperties( + kMaxQuicServersToPersist); QuicServerId quic_server_id(kDefaultServerHostName, 80, PRIVACY_MODE_DISABLED);
diff --git a/net/tools/quic/quic_dispatcher.cc b/net/tools/quic/quic_dispatcher.cc index d4e71b5..a02955b 100644 --- a/net/tools/quic/quic_dispatcher.cc +++ b/net/tools/quic/quic_dispatcher.cc
@@ -385,7 +385,6 @@ << " does not exist in the session map. Error: " << QuicUtils::ErrorToString(error); QUIC_BUG << base::debug::StackTrace().ToString(); - ; return; }
diff --git a/net/url_request/url_request_context_builder.cc b/net/url_request/url_request_context_builder.cc index f00cad5..3112f1f 100644 --- a/net/url_request/url_request_context_builder.cc +++ b/net/url_request/url_request_context_builder.cc
@@ -182,7 +182,7 @@ next_protos(NextProtosDefaults()), use_alternative_services(true), enable_quic(false), - quic_store_server_configs_in_properties(false), + quic_max_server_configs_stored_in_properties(0), quic_delay_tcp_race(false), quic_max_number_of_lossy_connections(0), quic_packet_loss_threshold(1.0f), @@ -391,8 +391,8 @@ http_network_session_params_.trusted_spdy_proxy; network_session_params.next_protos = http_network_session_params_.next_protos; network_session_params.enable_quic = http_network_session_params_.enable_quic; - network_session_params.quic_store_server_configs_in_properties = - http_network_session_params_.quic_store_server_configs_in_properties; + network_session_params.quic_max_server_configs_stored_in_properties = + http_network_session_params_.quic_max_server_configs_stored_in_properties; network_session_params.quic_delay_tcp_race = http_network_session_params_.quic_delay_tcp_race; network_session_params.quic_max_number_of_lossy_connections =
diff --git a/net/url_request/url_request_context_builder.h b/net/url_request/url_request_context_builder.h index 0a58c81..b955c96 100644 --- a/net/url_request/url_request_context_builder.h +++ b/net/url_request/url_request_context_builder.h
@@ -88,7 +88,7 @@ std::string trusted_spdy_proxy; bool use_alternative_services; bool enable_quic; - bool quic_store_server_configs_in_properties; + int quic_max_server_configs_stored_in_properties; bool quic_delay_tcp_race; int quic_max_number_of_lossy_connections; std::unordered_set<std::string> quic_host_whitelist; @@ -198,10 +198,10 @@ quic_connection_options; } - void set_quic_store_server_configs_in_properties( - bool quic_store_server_configs_in_properties) { - http_network_session_params_.quic_store_server_configs_in_properties = - quic_store_server_configs_in_properties; + void set_quic_max_server_configs_stored_in_properties( + int quic_max_server_configs_stored_in_properties) { + http_network_session_params_.quic_max_server_configs_stored_in_properties = + quic_max_server_configs_stored_in_properties; } void set_quic_delay_tcp_race(bool quic_delay_tcp_race) {
diff --git a/pdf/document_loader.cc b/pdf/document_loader.cc index b5f80e41..f450503 100644 --- a/pdf/document_loader.cc +++ b/pdf/document_loader.cc
@@ -449,9 +449,9 @@ // memory fragmentation issues on the large files and OOM exceptions. // To fix this, we collect all chunks of the file to the list and // concatenate them together after request is complete. - chunk_buffer_.push_back(std::vector<unsigned char>()); - chunk_buffer_.back().resize(length); - memcpy(&(chunk_buffer_.back()[0]), start, length); + std::vector<unsigned char> buf(length); + memcpy(buf.data(), start, length); + chunk_buffer_.push_back(std::move(buf)); } current_pos_ += length; current_chunk_read_ += length; @@ -511,7 +511,7 @@ chunk_stream_.Preallocate(current_pos_); uint32_t pos = 0; for (auto& chunk : chunk_buffer_) { - chunk_stream_.WriteData(pos, &(chunk[0]), chunk.size()); + chunk_stream_.WriteData(pos, chunk.data(), chunk.size()); pos += chunk.size(); } chunk_buffer_.clear();
diff --git a/pdf/document_loader.h b/pdf/document_loader.h index c9d355b..af39390e 100644 --- a/pdf/document_loader.h +++ b/pdf/document_loader.h
@@ -128,7 +128,7 @@ bool is_multipart_; std::string multipart_boundary_; uint32_t requests_count_; - std::list<std::vector<unsigned char> > chunk_buffer_; + std::vector<std::vector<unsigned char> > chunk_buffer_; }; } // namespace chrome_pdf
diff --git a/ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_entry.c b/ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_entry.c index d56329b..0fb2b5e 100644 --- a/ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_entry.c +++ b/ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_entry.c
@@ -8,7 +8,6 @@ #include "native_client/src/include/elf32.h" #include "native_client/src/include/elf_auxv.h" -#include "native_client/src/include/nacl_macros.h" #include "native_client/src/untrusted/nacl/nacl_startup.h" #include "ppapi/native_client/src/untrusted/pnacl_irt_shim/shim_ppapi.h"
diff --git a/remoting/BUILD.gn b/remoting/BUILD.gn index 2dbbecf..155af30 100644 --- a/remoting/BUILD.gn +++ b/remoting/BUILD.gn
@@ -41,7 +41,7 @@ ] } - if (is_android && !is_component_build) { + if (is_android) { deps += [ "//remoting/android:remoting_apk", "//remoting/android:remoting_test_apk",
diff --git a/remoting/android/BUILD.gn b/remoting/android/BUILD.gn index e4542d1..a933e3d6 100644 --- a/remoting/android/BUILD.gn +++ b/remoting/android/BUILD.gn
@@ -9,8 +9,6 @@ import("//remoting/remoting_options.gni") import("//remoting/tools/build/remoting_localize.gni") -assert(!is_component_build, "Remoting requires static library build.") - generate_jni("jni_headers") { sources = [ "java/src/org/chromium/chromoting/jni/Client.java",
diff --git a/remoting/android/remoting_apk_tmpl.gni b/remoting/android/remoting_apk_tmpl.gni index bc440c3..ee2f5b5 100644 --- a/remoting/android/remoting_apk_tmpl.gni +++ b/remoting/android/remoting_apk_tmpl.gni
@@ -4,23 +4,21 @@ import("//build/config/android/rules.gni") -if (!is_component_build) { - template("remoting_apk_tmpl") { - android_apk(target_name) { - forward_variables_from(invoker, "*") +template("remoting_apk_tmpl") { + android_apk(target_name) { + forward_variables_from(invoker, "*") - android_manifest = "$root_gen_dir/remoting/android/AndroidManifest.xml" - native_libs = [ "libremoting_client_jni.so" ] + android_manifest = "$root_gen_dir/remoting/android/AndroidManifest.xml" + native_libs = [ "libremoting_client_jni.so" ] - deps += [ - "//remoting/android:remoting_apk_manifest", - "//remoting/android:remoting_client_jni", - ] + deps += [ + "//remoting/android:remoting_apk_manifest", + "//remoting/android:remoting_client_jni", + ] - if (target_cpu == "arm") { - deps += [ "//remoting/android:remoting_cardboard_extract_native_lib" ] - native_libs += [ "libvrtoolkit.so" ] - } + if (target_cpu == "arm") { + deps += [ "//remoting/android:remoting_cardboard_extract_native_lib" ] + loadable_modules = [ "$root_out_dir/libvrtoolkit.so" ] } } }
diff --git a/remoting/protocol/chromium_socket_factory.cc b/remoting/protocol/chromium_socket_factory.cc index 6f9dfeb..773657d 100644 --- a/remoting/protocol/chromium_socket_factory.cc +++ b/remoting/protocol/chromium_socket_factory.cc
@@ -10,12 +10,14 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/scoped_ptr.h" +#include "base/time/time.h" #include "jingle/glue/utils.h" #include "net/base/io_buffer.h" #include "net/base/ip_endpoint.h" #include "net/base/net_errors.h" #include "net/udp/udp_server_socket.h" #include "remoting/protocol/socket_util.h" +#include "third_party/libjingle/source/talk/media/base/rtputils.h" #include "third_party/webrtc/base/asyncpacketsocket.h" #include "third_party/webrtc/base/nethelpers.h" @@ -194,7 +196,12 @@ return EWOULDBLOCK; } - send_queue_.push_back(PendingPacket(data, data_size, endpoint)); + PendingPacket packet(data, data_size, endpoint); + cricket::ApplyPacketOptions( + reinterpret_cast<uint8_t*>(packet.data->data()), data_size, + options.packet_time_params, + (base::TimeTicks::Now() - base::TimeTicks()).InMilliseconds()); + send_queue_.push_back(packet); send_queue_size_ += data_size; DoSend();
diff --git a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java index bdba1e0..00d5c78 100644 --- a/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java +++ b/testing/android/native_test/java/src/org/chromium/native_test/NativeTestActivity.java
@@ -15,6 +15,7 @@ import org.chromium.base.CommandLine; import org.chromium.base.Log; import org.chromium.base.annotations.JNINamespace; +import org.chromium.base.multidex.ChromiumMultiDexInstaller; import org.chromium.test.reporter.TestStatusReporter; import java.io.File; @@ -50,7 +51,9 @@ @Override public void onCreate(Bundle savedInstanceState) { + ChromiumMultiDexInstaller.install(this); super.onCreate(savedInstanceState); + CommandLine.init(new String[]{}); parseArgumentsFromIntent(getIntent());
diff --git a/testing/test.gni b/testing/test.gni index 7ce5d85a..6739bfe 100644 --- a/testing/test.gni +++ b/testing/test.gni
@@ -66,6 +66,7 @@ [ "android_manifest", "deps", + "enable_multidex", "use_default_launcher", "write_asset_list", ])
diff --git a/third_party/WebKit/LayoutTests/LeakExpectations b/third_party/WebKit/LayoutTests/LeakExpectations index 97c9b005..5d1126cd 100644 --- a/third_party/WebKit/LayoutTests/LeakExpectations +++ b/third_party/WebKit/LayoutTests/LeakExpectations
@@ -147,3 +147,7 @@ crbug.com/451577 [ Linux ] inspector/elements/user-properties.html [ Slow ] crbug.com/451577 [ Linux ] inspector/extensions/extensions-reload.html [ Slow ] crbug.com/451577 [ Linux ] inspector/extensions/extensions-sidebar.html [ Slow ] + +crbug.com/578297 [ Linux ] media/video-autoplay-experiment-modes.html [ Slow ] +crbug.com/578297 [ Linux ] virtual/threaded/printing/webgl-oversized-printing.html [ Slow ] +crbug.com/578297 [ Linux ] http/tests/media/media-source/mediasource-appendstream-quota-exceeded.html [ Slow ]
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations index 0736a7f..b01a8cd 100644 --- a/third_party/WebKit/LayoutTests/TestExpectations +++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -356,6 +356,7 @@ # SPv2 paint properties are still being implemented. crbug.com/537409 virtual/spv2/ [ Skip ] +crbug.com/563667 virtual/spv2/fast/block/basic/001.html [ Pass ] # In imported/web-platform-tests/html/, we prefer checking in failure # expectation files. The following tests with [ Failure ] don't have failure @@ -1422,6 +1423,10 @@ crbug.com/569950 svg/batik/filters/feTile.svg [ NeedsRebaseline ] crbug.com/569950 svg/filters/feTile.svg [ NeedsRebaseline ] +crbug.com/570611 fast/inline/inline-box-background-repeat-x.html [ NeedsRebaseline ] +crbug.com/570611 [ Mac Linux Android XP Win7 ] fast/text/emphasis-combined-text.html [ NeedsRebaseline ] +crbug.com/570611 ietestcenter/css3/bordersbackgrounds/background-repeat-space-padding-box.htm [ NeedsRebaseline ] + crbug.com/568867 [ Win Debug ] transforms/3d/point-mapping/3d-point-mapping-deep.html [ Failure ] crbug.com/568867 [ Win Debug ] transforms/3d/point-mapping/3d-point-mapping-preserve-3d.html [ Failure ]
diff --git a/third_party/WebKit/LayoutTests/VirtualTestSuites b/third_party/WebKit/LayoutTests/VirtualTestSuites index 3bc9cb8..48c7271 100644 --- a/third_party/WebKit/LayoutTests/VirtualTestSuites +++ b/third_party/WebKit/LayoutTests/VirtualTestSuites
@@ -194,6 +194,11 @@ "args": ["--enable-slimming-paint-v2"] }, { + "prefix": "spv2", + "base": "fast/block", + "args": ["--enable-slimming-paint-v2"] + }, + { "prefix": "scalefactor200", "base": "fast/hidpi/static", "args": ["--force-device-scale-factor=2"]
diff --git a/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html b/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html index 28a46a8..55c695b 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html +++ b/third_party/WebKit/LayoutTests/bluetooth/connectGATT.html
@@ -123,4 +123,17 @@ .then(device => device.connectGATT()) .then(gattServer => assert_true(gattServer.connected)); }, 'Device will connect'); + +promise_test(() => { + testRunner.setBluetoothMockDataSet(''); + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => { + return Promise.all([device.connectGATT(), device.connectGATT()]) + }).then(gattServers => { + // connectGATT should return the same object if it was created earlier. + // TODO(ortuno): change to assert_equals. + assert_not_equals(gattServers[0], gattServers[1]); + }); +}); </script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/disconnect.html b/third_party/WebKit/LayoutTests/bluetooth/disconnect.html new file mode 100644 index 0000000..94e69de --- /dev/null +++ b/third_party/WebKit/LayoutTests/bluetooth/disconnect.html
@@ -0,0 +1,51 @@ +<!DOCTYPE html> +<script src="../resources/testharness.js"></script> +<script src="../resources/testharnessreport.js"></script> +<script src="resources/bluetooth-helpers.js"></script> +<script> +'use strict'; + +test(t => { assert_true(window.testRunner instanceof Object); t.done(); }, + 'window.testRunner is required for the following tests.'); + +// TODO(ortuno): Write tests to check that "Disconnect" was actually +// called on the device. +// http://crbug.com/569716 +promise_test(() => { + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => device.connectGATT()) + .then(gattServer => { + gattServer.disconnect(); + assert_false(gattServer.connected); + }); +}, '\'connected\' is set to false after disconnect is called.'); + +promise_test(() => { + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => device.connectGATT()) + .then(gattServer => { + gattServer.disconnect(); + assert_false(gattServer.connected); + gattServer.disconnect(); + assert_false(gattServer.connected); + }); +}, 'Calling disconnect twice in a row still results in \'connected\' ' + + 'being false.'); + +promise_test(() => { + testRunner.setBluetoothMockDataSet('HeartRateAdapter'); + return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]}) + .then(device => { + return device.connectGATT().then(gattServer => { + gattServer.disconnect(); + assert_false(gattServer.connected); + }) + .then(() => device.connectGATT()).then(gattServer => { + gattServer.disconnect(); + assert_false(gattServer.connected); + }); + }); +}, 'Connect + Disconnect twice still results in \'connected\' being false.'); +</script>
diff --git a/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService.html b/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService.html index 389a12e..5a282f3 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService.html +++ b/third_party/WebKit/LayoutTests/bluetooth/getPrimaryService.html
@@ -5,6 +5,15 @@ <script> 'use strict' +// Services Discovered +// We use a connection to trigger a service discovered event and test +// getPrimaryService. Sometimes the previous test left a connection to the +// device open, so the event doesn't get triggered. To avoid this some tests +// clean the state before starting the test. +// In the future we will avoid this by +// (1) Separating each test into it's own file. http://crbug.com/554240 +// (2) Implementing Dynamic mocks so that we can trigger the +// discovery event manually. http://crbug.com/569709 test(t => { assert_true(window.testRunner instanceof Object); t.done(); }, 'window.testRunner is required for the following tests.'); @@ -23,6 +32,8 @@ }, 'Device goes out of range. Reject with NetworkError.'); promise_test(() => { + // See Services Discovered note above. + testRunner.setBluetoothMockDataSet(''); testRunner.setBluetoothMockDataSet('HeartRateAdapter'); let expected = new DOMException('Service not found in device.', 'NotFoundError'); @@ -38,13 +49,7 @@ }, 'Request for wrong service. Reject with NotFoundError.'); promise_test(() => { - // Because state doesn't get cleaned after each test in a file, we need to - // clean it ourselves. In this case, the services for a HeartRateDevice had - // been discovered in the previous test, since the state doesn't get cleaned - // it appears as if the services had been discovered for the device in this - // test. - // TODO(ortuno): split tests into different files. - // http://crbug.com/554240 + // See services discovered note above. testRunner.setBluetoothMockDataSet(''); testRunner.setBluetoothMockDataSet('DelayedServicesDiscoveryAdapter'); return requestDeviceWithKeyDown({filters: [{services: ['heart_rate']}]})
diff --git a/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothDevice.html b/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothDevice.html index 4c533ec..3dbcbb2 100644 --- a/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothDevice.html +++ b/third_party/WebKit/LayoutTests/bluetooth/idl-BluetoothDevice.html
@@ -21,6 +21,7 @@ // Attempt (and fail) to overwrite all members, verifying they are // readonly. + var old_device_id = device.id; device.id = 'overwritten'; device.name = 'overwritten'; device.deviceClass = 'overwritten'; @@ -29,7 +30,7 @@ device.productID = 'overwritten'; device.productVersion = 'overwritten'; device.uuids = 'overwritten'; - assert_equals(device.id, '00:00:00:00:00:00'); + assert_equals(device.id, old_device_id); assert_equals(device.name, 'Heart Rate Device'); assert_equals(device.deviceClass, 0x1F00); assert_equals(device.vendorIDSource, 'bluetooth');
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-with-sub-pixel-offset-positioning-expected.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-with-sub-pixel-offset-positioning-expected.html new file mode 100644 index 0000000..007a8a5 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-with-sub-pixel-offset-positioning-expected.html
@@ -0,0 +1,18 @@ +<!DOCTYPE html> +<style> +#float { + background: url('resources/bgimg1x50.png') 100% 0px no-repeat #FFF; + height: 1px; + width: 1px; + transform: scale(50); +} +#container { + margin-left: 3px; + overflow: hidden; + width: 9px; + height: 10px; +} +</style> +<div id="container"> + <div id="float"></div> +</div> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/backgrounds/background-with-sub-pixel-offset-positioning.html b/third_party/WebKit/LayoutTests/fast/backgrounds/background-with-sub-pixel-offset-positioning.html new file mode 100644 index 0000000..7c83584 --- /dev/null +++ b/third_party/WebKit/LayoutTests/fast/backgrounds/background-with-sub-pixel-offset-positioning.html
@@ -0,0 +1,20 @@ +<!DOCTYPE html> +<style> +#float { + background: url('resources/bgimg1x50.png') 100% 0px no-repeat #FFF; + height: 1px; + width: 1.5px; + position: relative; + left: 50px; + transform: scale(50); +} +#container { + margin-left: 1.5px; + overflow: hidden; + width: 10px; + height: 10px; +} +</style> +<div id="container"> + <div id="float"></div> +</div> \ No newline at end of file
diff --git a/third_party/WebKit/LayoutTests/fast/dom/icon-url-list-apple-touch.html b/third_party/WebKit/LayoutTests/fast/dom/icon-url-list-apple-touch.html index 2168c3c..9bac9ce 100644 --- a/third_party/WebKit/LayoutTests/fast/dom/icon-url-list-apple-touch.html +++ b/third_party/WebKit/LayoutTests/fast/dom/icon-url-list-apple-touch.html
@@ -20,16 +20,14 @@ return } - if (window.internals && window.internals.runtimeFlags.touchIconLoadingEnabled) { - if (!actualURLs[1] || actualURLs[1] != "http://test.com/i/touch.png") { - debug("Test failed.. apple touch icon missing or invalid.") - return - } + if (!actualURLs[1] || actualURLs[1] != "http://test.com/i/touch.png") { + debug("Test failed.. apple touch icon missing or invalid.") + return + } - if (!actualURLs[2] || actualURLs[2] != "http://test.com/i/touch-precomposed.png") { - debug("Test failed.. apple touch icon missing or invalid.") - return - } + if (!actualURLs[2] || actualURLs[2] != "http://test.com/i/touch-precomposed.png") { + debug("Test failed.. apple touch icon missing or invalid.") + return } debug("All icons are preset and in-order in document.iconURLs()")
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-cross-origin-response-handling.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-cross-origin-response-handling.html index 0a04534e..130f87f8 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-cross-origin-response-handling.html +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-cross-origin-response-handling.html
@@ -14,6 +14,7 @@ function openXHR() { xhr.open('GET', '/'); + openAndSendCrossOriginSimpleXHR(); } function openAndSendCrossOriginSimpleXHR() {
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-preflight-handling.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-preflight-handling.html index 170b256..697f401 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-preflight-handling.html +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-preflight-handling.html
@@ -13,6 +13,7 @@ function openXHR() { xhr.open('GET', '/'); + openAndSendCrossOriginNonSimpleXHR(); } function openAndSendCrossOriginNonSimpleXHR() {
diff --git a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling.html b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling.html index 095a68e..4478fdc6 100644 --- a/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling.html +++ b/third_party/WebKit/LayoutTests/http/tests/xmlhttprequest/open-in-body-onload-sync-to-invalid-redirect-response-handling.html
@@ -14,6 +14,7 @@ function openXHR() { xhr.open('GET', '/'); + openAndSendCrossOriginSimpleXHRExpectingRedirect(); } function openAndSendCrossOriginSimpleXHRExpectingRedirect() {
diff --git a/third_party/WebKit/LayoutTests/netinfo/connection-types-expected.txt b/third_party/WebKit/LayoutTests/netinfo/connection-types-expected.txt index 30b810f..8a7c3b6 100644 --- a/third_party/WebKit/LayoutTests/netinfo/connection-types-expected.txt +++ b/third_party/WebKit/LayoutTests/netinfo/connection-types-expected.txt
@@ -35,6 +35,14 @@ PASS connection.downlinkMax is types[count][1] PASS connection.type is types[count][0] PASS connection.downlinkMax is types[count][1] +PASS connection.type is types[count][0] +PASS connection.downlinkMax is types[count][1] +PASS connection.type is types[count][0] +PASS connection.downlinkMax is types[count][1] +PASS connection.type is types[count][0] +PASS connection.downlinkMax is types[count][1] +PASS connection.type is types[count][0] +PASS connection.downlinkMax is types[count][1] PASS successfullyParsed is true TEST COMPLETE
diff --git a/third_party/WebKit/LayoutTests/netinfo/connection-types.html b/third_party/WebKit/LayoutTests/netinfo/connection-types.html index 8c9f7c5..c6039ed 100644 --- a/third_party/WebKit/LayoutTests/netinfo/connection-types.html +++ b/third_party/WebKit/LayoutTests/netinfo/connection-types.html
@@ -18,7 +18,9 @@ ['wimax', 5.0], ['other', 6.0], ['none', 7.0], - ['unknown', 8.0] + ['unknown', 8.0], + ['wimax', 8.0], + ['wimax', 9.0] ]; // ontypechange is deprecated but this test is here to
diff --git a/third_party/WebKit/LayoutTests/virtual/spv2/fast/block/README.txt b/third_party/WebKit/LayoutTests/virtual/spv2/fast/block/README.txt new file mode 100644 index 0000000..89dba61c --- /dev/null +++ b/third_party/WebKit/LayoutTests/virtual/spv2/fast/block/README.txt
@@ -0,0 +1,3 @@ +# This suite runs tests with --enable-slimming-paint-v2 +# We also have try bots running full set of layout tests for spv2: +# https://codereview.chromium.org/1283823002
diff --git a/third_party/WebKit/Source/core/animation/Animation.h b/third_party/WebKit/Source/core/animation/Animation.h index 402df1ad..0d88db1 100644 --- a/third_party/WebKit/Source/core/animation/Animation.h +++ b/third_party/WebKit/Source/core/animation/Animation.h
@@ -208,6 +208,7 @@ // WebCompositorAnimationDelegate implementation. void notifyAnimationStarted(double monotonicTime, int group) override; void notifyAnimationFinished(double monotonicTime, int group) override { } + void notifyAnimationAborted(double monotonicTime, int group) override { } double startClipInternal() const { return m_startClip; } double endClipInternal() const { return m_endClip; }
diff --git a/third_party/WebKit/Source/core/core.gypi b/third_party/WebKit/Source/core/core.gypi index 4909759..52a04778 100644 --- a/third_party/WebKit/Source/core/core.gypi +++ b/third_party/WebKit/Source/core/core.gypi
@@ -3645,6 +3645,7 @@ 'html/MediaKeyEventInit.idl', 'html/canvas/CanvasContextCreationAttributes.idl', 'html/track/TrackEventInit.idl', + 'imagebitmap/ImageBitmapOptions.idl', 'input/InputDeviceCapabilitiesInit.idl', 'page/EventSourceInit.idl', 'timing/PerformanceObserverInit.idl', @@ -3742,6 +3743,8 @@ '<(blink_core_output_dir)/html/canvas/CanvasContextCreationAttributes.h', '<(blink_core_output_dir)/html/track/TrackEventInit.cpp', '<(blink_core_output_dir)/html/track/TrackEventInit.h', + '<(blink_core_output_dir)/imagebitmap/ImageBitmapOptions.cpp', + '<(blink_core_output_dir)/imagebitmap/ImageBitmapOptions.h', '<(blink_core_output_dir)/input/InputDeviceCapabilitiesInit.cpp', '<(blink_core_output_dir)/input/InputDeviceCapabilitiesInit.h', '<(blink_core_output_dir)/page/EventSourceInit.cpp',
diff --git a/third_party/WebKit/Source/core/dom/ContainerNode.cpp b/third_party/WebKit/Source/core/dom/ContainerNode.cpp index 832952dc1..2ee12572 100644 --- a/third_party/WebKit/Source/core/dom/ContainerNode.cpp +++ b/third_party/WebKit/Source/core/dom/ContainerNode.cpp
@@ -606,7 +606,7 @@ AttachContext context; context.clearInvalidation = true; - if (!needsAttach() || !oldChild.needsAttach()) + if (!oldChild.needsAttach()) oldChild.detach(context); if (nextChild)
diff --git a/third_party/WebKit/Source/core/dom/Document.cpp b/third_party/WebKit/Source/core/dom/Document.cpp index a67c7794..303f98e0 100644 --- a/third_party/WebKit/Source/core/dom/Document.cpp +++ b/third_party/WebKit/Source/core/dom/Document.cpp
@@ -4767,8 +4767,6 @@ continue; if (linkElement->href().isEmpty()) continue; - if (!RuntimeEnabledFeatures::touchIconLoadingEnabled() && linkElement->iconType() != Favicon) - continue; IconURL newURL(linkElement->href(), linkElement->iconSizes(), linkElement->type(), linkElement->iconType()); if (linkElement->iconType() == Favicon) {
diff --git a/third_party/WebKit/Source/core/dom/Element.cpp b/third_party/WebKit/Source/core/dom/Element.cpp index 652c7083..821c32e 100644 --- a/third_party/WebKit/Source/core/dom/Element.cpp +++ b/third_party/WebKit/Source/core/dom/Element.cpp
@@ -1530,6 +1530,9 @@ if (isUpgradedCustomElement()) CustomElement::didDetach(this, insertionPoint->document()); + + if (needsStyleInvalidation()) + document().styleEngine().styleInvalidator().clearInvalidation(*this); } document().removeFromTopLayer(this);
diff --git a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp index 8b11fa6a..ca638e9 100644 --- a/third_party/WebKit/Source/core/editing/VisibleUnits.cpp +++ b/third_party/WebKit/Source/core/editing/VisibleUnits.cpp
@@ -56,6 +56,7 @@ #include "core/layout/api/LineLayoutItem.h" #include "core/layout/line/InlineIterator.h" #include "core/layout/line/InlineTextBox.h" +#include "core/paint/LineLayoutPaintShim.h" #include "core/paint/PaintLayer.h" #include "platform/Logging.h" #include "platform/RuntimeEnabledFeatures.h" @@ -401,7 +402,7 @@ return previousBox; while (1) { - Node* startNode = startBox->layoutObject().nonPseudoNode(); + Node* startNode = startBox->lineLayoutItem().nonPseudoNode(); if (!startNode) break; @@ -442,7 +443,7 @@ return nextBox; while (1) { - Node* startNode =startBox->layoutObject().nonPseudoNode(); + Node* startNode =startBox->lineLayoutItem().nonPseudoNode(); if (!startNode) break; @@ -981,7 +982,7 @@ if (!startBox) return PositionWithAffinityTemplate<Strategy>(); - startNode = startBox->layoutObject().nonPseudoNode(); + startNode = startBox->lineLayoutItem().nonPseudoNode(); if (startNode) break; @@ -1078,7 +1079,7 @@ if (!endBox) return VisiblePositionTemplate<Strategy>(); - endNode = endBox->layoutObject().nonPseudoNode(); + endNode = endBox->lineLayoutItem().nonPseudoNode(); if (endNode) break; @@ -2123,7 +2124,7 @@ InlineBoxPosition boxPosition = computeInlineBoxPosition(position.position(), position.affinity()); if (boxPosition.inlineBox) - layoutObject = &boxPosition.inlineBox->layoutObject(); + layoutObject = LineLayoutPaintShim::layoutObjectFrom(boxPosition.inlineBox->lineLayoutItem()); return layoutObject->localCaretRect(boxPosition.inlineBox, boxPosition.offsetInBox); } @@ -2535,7 +2536,7 @@ otherBox = otherBox->nextLeafChild(); if (!otherBox) break; - if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() > textOffset)) + if (otherBox == lastTextBox || (LineLayoutPaintShim::layoutObjectFrom(otherBox->lineLayoutItem()) == textLayoutObject && toInlineTextBox(otherBox)->start() > textOffset)) continuesOnNextLine = false; } @@ -2544,7 +2545,7 @@ otherBox = otherBox->prevLeafChild(); if (!otherBox) break; - if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() > textOffset)) + if (otherBox == lastTextBox || (LineLayoutPaintShim::layoutObjectFrom(otherBox->lineLayoutItem()) == textLayoutObject && toInlineTextBox(otherBox)->start() > textOffset)) continuesOnNextLine = false; } @@ -2666,7 +2667,7 @@ otherBox = otherBox->nextLeafChild(); if (!otherBox) break; - if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() >= textOffset)) + if (otherBox == lastTextBox || (LineLayoutPaintShim::layoutObjectFrom(otherBox->lineLayoutItem()) == textLayoutObject && toInlineTextBox(otherBox)->start() >= textOffset)) continuesOnNextLine = false; } @@ -2675,7 +2676,7 @@ otherBox = otherBox->prevLeafChild(); if (!otherBox) break; - if (otherBox == lastTextBox || (otherBox->layoutObject() == textLayoutObject && toInlineTextBox(otherBox)->start() >= textOffset)) + if (otherBox == lastTextBox || (LineLayoutPaintShim::layoutObjectFrom(otherBox->lineLayoutItem()) == textLayoutObject && toInlineTextBox(otherBox)->start() >= textOffset)) continuesOnNextLine = false; } @@ -3083,7 +3084,7 @@ if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(deepPosition) : previousVisuallyDistinctCandidate(deepPosition); - LayoutObject* layoutObject = &box->layoutObject(); + LayoutObject* layoutObject = LineLayoutPaintShim::layoutObjectFrom(box->lineLayoutItem()); while (true) { if ((layoutObject->isAtomicInlineLevel() || layoutObject->isBR()) && offset == box->caretLeftmostOffset()) @@ -3093,7 +3094,7 @@ box = box->nextLeafChild(); if (!box) return primaryDirection == LTR ? nextVisuallyDistinctCandidate(deepPosition) : previousVisuallyDistinctCandidate(deepPosition); - layoutObject = &box->layoutObject(); + layoutObject = LineLayoutPaintShim::layoutObjectFrom(box->lineLayoutItem()); offset = box->caretLeftmostOffset(); continue; } @@ -3123,7 +3124,7 @@ // Reposition at the other logical position corresponding to our // edge's visual position and go for another round. box = nextBox; - layoutObject = &box->layoutObject(); + layoutObject = LineLayoutPaintShim::layoutObjectFrom(box->lineLayoutItem()); offset = nextBox->caretLeftmostOffset(); continue; } @@ -3138,7 +3139,7 @@ InlineBox* logicalEnd = 0; if (primaryDirection == LTR ? box->root().getLogicalEndBoxWithNode(logicalEnd) : box->root().getLogicalStartBoxWithNode(logicalEnd)) { box = logicalEnd; - layoutObject = &box->layoutObject(); + layoutObject = LineLayoutPaintShim::layoutObjectFrom(box->lineLayoutItem()); offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); } break; @@ -3160,19 +3161,19 @@ // For example, abc 123 ^ CBA or 123 ^ CBA abc box = nextBox; - layoutObject = &box->layoutObject(); + layoutObject = LineLayoutPaintShim::layoutObjectFrom(box->lineLayoutItem()); offset = box->caretLeftmostOffset(); if (box->direction() == primaryDirection) break; continue; } - while (nextBox && !nextBox->layoutObject().node()) + while (nextBox && !nextBox->lineLayoutItem().node()) nextBox = nextBox->nextLeafChild(); if (nextBox) { box = nextBox; - layoutObject = &box->layoutObject(); + layoutObject = LineLayoutPaintShim::layoutObjectFrom(box->lineLayoutItem()); offset = box->caretLeftmostOffset(); if (box->bidiLevel() > level) { @@ -3203,7 +3204,7 @@ break; level = box->bidiLevel(); } - layoutObject = &box->layoutObject(); + layoutObject = LineLayoutPaintShim::layoutObjectFrom(box->lineLayoutItem()); offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); } break;
diff --git a/third_party/WebKit/Source/core/fetch/FetchContext.cpp b/third_party/WebKit/Source/core/fetch/FetchContext.cpp index 9f148584..b477978 100644 --- a/third_party/WebKit/Source/core/fetch/FetchContext.cpp +++ b/third_party/WebKit/Source/core/fetch/FetchContext.cpp
@@ -93,7 +93,7 @@ { } -void FetchContext::didLoadResource() +void FetchContext::didLoadResource(Resource*) { }
diff --git a/third_party/WebKit/Source/core/fetch/FetchContext.h b/third_party/WebKit/Source/core/fetch/FetchContext.h index 94dde64..e6ade47b 100644 --- a/third_party/WebKit/Source/core/fetch/FetchContext.h +++ b/third_party/WebKit/Source/core/fetch/FetchContext.h
@@ -84,7 +84,7 @@ virtual bool shouldLoadNewResource(Resource::Type) const { return false; } virtual void willStartLoadingResource(ResourceRequest&); - virtual void didLoadResource(); + virtual void didLoadResource(Resource*); virtual void addResourceTiming(const ResourceTimingInfo&); virtual bool allowImage(bool, const KURL&) const { return false; }
diff --git a/third_party/WebKit/Source/core/fetch/Resource.cpp b/third_party/WebKit/Source/core/fetch/Resource.cpp index ac996b9..eeb252f 100644 --- a/third_party/WebKit/Source/core/fetch/Resource.cpp +++ b/third_party/WebKit/Source/core/fetch/Resource.cpp
@@ -1132,16 +1132,31 @@ bool Resource::shouldBlockLoadEvent() const { - return !m_avoidBlockingOnLoad && isNonBlockingResourceType(); + return !m_avoidBlockingOnLoad && isLoadEventBlockingResourceType(); } -bool Resource::isNonBlockingResourceType() const +bool Resource::isLoadEventBlockingResourceType() const { - return type() != LinkPrefetch - && type() != LinkSubresource - && type() != Media - && type() != Raw - && type() != TextTrack; + switch (m_type) { + case Resource::MainResource: + case Resource::Image: + case Resource::CSSStyleSheet: + case Resource::Script: + case Resource::Font: + case Resource::SVGDocument: + case Resource::XSLStyleSheet: + case Resource::ImportResource: + return true; + case Resource::Raw: + case Resource::LinkPrefetch: + case Resource::LinkSubresource: + case Resource::TextTrack: + case Resource::Media: + case Resource::Manifest: + return false; + } + ASSERT_NOT_REACHED(); + return false; } #if !LOG_DISABLED
diff --git a/third_party/WebKit/Source/core/fetch/Resource.h b/third_party/WebKit/Source/core/fetch/Resource.h index aad2bc44..6bc6282 100644 --- a/third_party/WebKit/Source/core/fetch/Resource.h +++ b/third_party/WebKit/Source/core/fetch/Resource.h
@@ -176,7 +176,7 @@ virtual bool isImage() const { return false; } bool shouldBlockLoadEvent() const; - bool isNonBlockingResourceType() const; + bool isLoadEventBlockingResourceType() const; // Computes the status of an object after loading. // Updates the expire date on the cache entry file
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp index 5ae5049..58f0257 100644 --- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp +++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.cpp
@@ -329,7 +329,7 @@ void ResourceFetcher::moveCachedNonBlockingResourceToBlocking(Resource* resource, const FetchRequest& request) { // TODO(yoav): Test that non-blocking resources (video/audio/track) continue to not-block even after being preloaded and discovered. - if (resource && resource->loader() && resource->isNonBlockingResourceType() && resource->avoidBlockingOnLoad() && !request.forPreload()) { + if (resource && resource->loader() && resource->isLoadEventBlockingResourceType() && resource->avoidBlockingOnLoad() && !request.forPreload()) { if (m_nonBlockingLoaders) m_nonBlockingLoaders->remove(resource->loader()); if (!m_loaders) @@ -791,9 +791,9 @@ it->value->addRedirect(redirectResponse); } -void ResourceFetcher::didLoadResource() +void ResourceFetcher::didLoadResource(Resource* resource) { - context().didLoadResource(); + context().didLoadResource(resource); } int ResourceFetcher::requestCount() const @@ -944,7 +944,7 @@ m_nonBlockingLoaders = ResourceLoaderSet::create(); m_nonBlockingLoaders->add(loader); m_loaders->remove(loader); - context().didLoadResource(); + didLoadResource(loader->cachedResource()); } void ResourceFetcher::didInitializeResourceLoader(ResourceLoader* loader)
diff --git a/third_party/WebKit/Source/core/fetch/ResourceFetcher.h b/third_party/WebKit/Source/core/fetch/ResourceFetcher.h index 98d1582..2f5a284 100644 --- a/third_party/WebKit/Source/core/fetch/ResourceFetcher.h +++ b/third_party/WebKit/Source/core/fetch/ResourceFetcher.h
@@ -105,7 +105,7 @@ void stopFetching(); bool isFetching() const; - void didLoadResource(); + void didLoadResource(Resource*); void redirectReceived(Resource*, const ResourceResponse&); void didFinishLoading(Resource*, double finishTime, int64_t encodedDataLength); void didFailLoading(const Resource*, const ResourceError&);
diff --git a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp index a3ae8717..40696f8 100644 --- a/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp +++ b/third_party/WebKit/Source/core/fetch/ResourceLoader.cpp
@@ -95,7 +95,7 @@ { ASSERT(m_state != Terminated); ASSERT(m_notifiedLoadComplete); - m_fetcher->didLoadResource(); + m_fetcher->didLoadResource(m_resource.get()); if (m_state == Terminated) return; m_resource->clearLoader();
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp index 8b15261..7f848ba 100644 --- a/third_party/WebKit/Source/core/frame/ImageBitmap.cpp +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.cpp
@@ -45,13 +45,13 @@ return StaticBitmapImage::create(adoptRef(surface->newImageSnapshot())); } -ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect, Document* document) +ImageBitmap::ImageBitmap(HTMLImageElement* image, const IntRect& cropRect, Document* document, const ImageBitmapOptions& options) { m_image = cropImage(image->cachedImage()->image(), cropRect); m_image->setOriginClean(!image->wouldTaintOrigin(document->securityOrigin())); } -ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect, Document* document) +ImageBitmap::ImageBitmap(HTMLVideoElement* video, const IntRect& cropRect, Document* document, const ImageBitmapOptions& options) { IntSize playerSize; if (video->webMediaPlayer()) @@ -69,14 +69,14 @@ m_image->setOriginClean(!video->wouldTaintOrigin(document->securityOrigin())); } -ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect) +ImageBitmap::ImageBitmap(HTMLCanvasElement* canvas, const IntRect& cropRect, const ImageBitmapOptions& options) { ASSERT(canvas->isPaintable()); m_image = cropImage(canvas->copiedImage(BackBuffer, PreferAcceleration).get(), cropRect); m_image->setOriginClean(canvas->originClean()); } -ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect) +ImageBitmap::ImageBitmap(ImageData* data, const IntRect& cropRect, const ImageBitmapOptions& options) { IntRect srcRect = intersection(cropRect, IntRect(IntPoint(), data->size())); @@ -98,13 +98,13 @@ m_image = StaticBitmapImage::create(buffer->newSkImageSnapshot(PreferNoAcceleration)); } -ImageBitmap::ImageBitmap(ImageBitmap* bitmap, const IntRect& cropRect) +ImageBitmap::ImageBitmap(ImageBitmap* bitmap, const IntRect& cropRect, const ImageBitmapOptions& options) { m_image = cropImage(bitmap->bitmapImage(), cropRect); m_image->setOriginClean(bitmap->originClean()); } -ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, const IntRect& cropRect) +ImageBitmap::ImageBitmap(PassRefPtr<StaticBitmapImage> image, const IntRect& cropRect, const ImageBitmapOptions& options) { m_image = cropImage(image.get(), cropRect); m_image->setOriginClean(image->originClean()); @@ -126,40 +126,40 @@ { } -PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(HTMLImageElement* image, const IntRect& cropRect, Document* document) +PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(HTMLImageElement* image, const IntRect& cropRect, Document* document, const ImageBitmapOptions& options) { IntRect normalizedCropRect = normalizeRect(cropRect); - return adoptRefWillBeNoop(new ImageBitmap(image, normalizedCropRect, document)); + return adoptRefWillBeNoop(new ImageBitmap(image, normalizedCropRect, document, options)); } -PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(HTMLVideoElement* video, const IntRect& cropRect, Document* document) +PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(HTMLVideoElement* video, const IntRect& cropRect, Document* document, const ImageBitmapOptions& options) { IntRect normalizedCropRect = normalizeRect(cropRect); - return adoptRefWillBeNoop(new ImageBitmap(video, normalizedCropRect, document)); + return adoptRefWillBeNoop(new ImageBitmap(video, normalizedCropRect, document, options)); } -PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(HTMLCanvasElement* canvas, const IntRect& cropRect) +PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(HTMLCanvasElement* canvas, const IntRect& cropRect, const ImageBitmapOptions& options) { IntRect normalizedCropRect = normalizeRect(cropRect); - return adoptRefWillBeNoop(new ImageBitmap(canvas, normalizedCropRect)); + return adoptRefWillBeNoop(new ImageBitmap(canvas, normalizedCropRect, options)); } -PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(ImageData* data, const IntRect& cropRect) +PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(ImageData* data, const IntRect& cropRect, const ImageBitmapOptions& options) { IntRect normalizedCropRect = normalizeRect(cropRect); - return adoptRefWillBeNoop(new ImageBitmap(data, normalizedCropRect)); + return adoptRefWillBeNoop(new ImageBitmap(data, normalizedCropRect, options)); } -PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(ImageBitmap* bitmap, const IntRect& cropRect) +PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(ImageBitmap* bitmap, const IntRect& cropRect, const ImageBitmapOptions& options) { IntRect normalizedCropRect = normalizeRect(cropRect); - return adoptRefWillBeNoop(new ImageBitmap(bitmap, normalizedCropRect)); + return adoptRefWillBeNoop(new ImageBitmap(bitmap, normalizedCropRect, options)); } -PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(PassRefPtr<StaticBitmapImage> image, const IntRect& cropRect) +PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(PassRefPtr<StaticBitmapImage> image, const IntRect& cropRect, const ImageBitmapOptions& options) { IntRect normalizedCropRect = normalizeRect(cropRect); - return adoptRefWillBeNoop(new ImageBitmap(image, normalizedCropRect)); + return adoptRefWillBeNoop(new ImageBitmap(image, normalizedCropRect, options)); } PassRefPtrWillBeRawPtr<ImageBitmap> ImageBitmap::create(PassRefPtr<StaticBitmapImage> image) @@ -191,13 +191,13 @@ return IntSize(m_image->width(), m_image->height()); } -ScriptPromise ImageBitmap::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) +ScriptPromise ImageBitmap::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, const ImageBitmapOptions& options, ExceptionState& exceptionState) { if (!sw || !sh) { exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } - return ImageBitmapSource::fulfillImageBitmap(scriptState, create(this, IntRect(sx, sy, sw, sh))); + return ImageBitmapSource::fulfillImageBitmap(scriptState, create(this, IntRect(sx, sy, sw, sh), options)); } void ImageBitmap::notifyImageSourceChanged()
diff --git a/third_party/WebKit/Source/core/frame/ImageBitmap.h b/third_party/WebKit/Source/core/frame/ImageBitmap.h index 6af36c0f..5d272ca 100644 --- a/third_party/WebKit/Source/core/frame/ImageBitmap.h +++ b/third_party/WebKit/Source/core/frame/ImageBitmap.h
@@ -9,6 +9,7 @@ #include "core/CoreExport.h" #include "core/html/HTMLImageElement.h" #include "core/html/canvas/CanvasImageSource.h" +#include "core/imagebitmap/ImageBitmapOptions.h" #include "core/imagebitmap/ImageBitmapSource.h" #include "platform/geometry/IntRect.h" #include "platform/graphics/Image.h" @@ -28,13 +29,13 @@ DEFINE_WRAPPERTYPEINFO(); WILL_BE_USING_GARBAGE_COLLECTED_MIXIN(ImageBitmap); public: - static PassRefPtrWillBeRawPtr<ImageBitmap> create(HTMLImageElement*, const IntRect&, Document*); - static PassRefPtrWillBeRawPtr<ImageBitmap> create(HTMLVideoElement*, const IntRect&, Document*); - static PassRefPtrWillBeRawPtr<ImageBitmap> create(HTMLCanvasElement*, const IntRect&); - static PassRefPtrWillBeRawPtr<ImageBitmap> create(ImageData*, const IntRect&); - static PassRefPtrWillBeRawPtr<ImageBitmap> create(ImageBitmap*, const IntRect&); + static PassRefPtrWillBeRawPtr<ImageBitmap> create(HTMLImageElement*, const IntRect&, Document*, const ImageBitmapOptions& = ImageBitmapOptions()); + static PassRefPtrWillBeRawPtr<ImageBitmap> create(HTMLVideoElement*, const IntRect&, Document*, const ImageBitmapOptions& = ImageBitmapOptions()); + static PassRefPtrWillBeRawPtr<ImageBitmap> create(HTMLCanvasElement*, const IntRect&, const ImageBitmapOptions& = ImageBitmapOptions()); + static PassRefPtrWillBeRawPtr<ImageBitmap> create(ImageData*, const IntRect&, const ImageBitmapOptions& = ImageBitmapOptions()); + static PassRefPtrWillBeRawPtr<ImageBitmap> create(ImageBitmap*, const IntRect&, const ImageBitmapOptions& = ImageBitmapOptions()); static PassRefPtrWillBeRawPtr<ImageBitmap> create(PassRefPtr<StaticBitmapImage>); - static PassRefPtrWillBeRawPtr<ImageBitmap> create(PassRefPtr<StaticBitmapImage>, const IntRect&); + static PassRefPtrWillBeRawPtr<ImageBitmap> create(PassRefPtr<StaticBitmapImage>, const IntRect&, const ImageBitmapOptions& = ImageBitmapOptions()); StaticBitmapImage* bitmapImage() const { return (m_image) ? m_image.get() : nullptr; } unsigned long width() const; @@ -55,18 +56,18 @@ // ImageBitmapSource implementation IntSize bitmapSourceSize() const override { return size(); } - ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, ExceptionState&) override; + ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&) override; DECLARE_VIRTUAL_TRACE(); private: - ImageBitmap(HTMLImageElement*, const IntRect&, Document*); - ImageBitmap(HTMLVideoElement*, const IntRect&, Document*); - ImageBitmap(HTMLCanvasElement*, const IntRect&); - ImageBitmap(ImageData*, const IntRect&); - ImageBitmap(ImageBitmap*, const IntRect&); + ImageBitmap(HTMLImageElement*, const IntRect&, Document*, const ImageBitmapOptions&); + ImageBitmap(HTMLVideoElement*, const IntRect&, Document*, const ImageBitmapOptions&); + ImageBitmap(HTMLCanvasElement*, const IntRect&, const ImageBitmapOptions&); + ImageBitmap(ImageData*, const IntRect&, const ImageBitmapOptions&); + ImageBitmap(ImageBitmap*, const IntRect&, const ImageBitmapOptions&); ImageBitmap(PassRefPtr<StaticBitmapImage>); - ImageBitmap(PassRefPtr<StaticBitmapImage>, const IntRect&); + ImageBitmap(PassRefPtr<StaticBitmapImage>, const IntRect&, const ImageBitmapOptions&); // ImageLoaderClient void notifyImageSourceChanged() override;
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp index 07a62ea..7d05c511 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.cpp
@@ -43,6 +43,7 @@ #include "core/html/canvas/CanvasFontCache.h" #include "core/html/canvas/CanvasRenderingContext.h" #include "core/html/canvas/CanvasRenderingContextFactory.h" +#include "core/imagebitmap/ImageBitmapOptions.h" #include "core/layout/LayoutHTMLCanvas.h" #include "core/paint/PaintLayer.h" #include "platform/MIMETypeRegistry.h" @@ -1000,14 +1001,14 @@ return IntSize(width(), height()); } -ScriptPromise HTMLCanvasElement::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) +ScriptPromise HTMLCanvasElement::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, const ImageBitmapOptions& options, ExceptionState& exceptionState) { ASSERT(eventTarget.toDOMWindow()); if (!sw || !sh) { exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } - return ImageBitmapSource::fulfillImageBitmap(scriptState, isPaintable() ? ImageBitmap::create(this, IntRect(sx, sy, sw, sh)) : nullptr); + return ImageBitmapSource::fulfillImageBitmap(scriptState, isPaintable() ? ImageBitmap::create(this, IntRect(sx, sy, sw, sh), options) : nullptr); } bool HTMLCanvasElement::isOpaque() const
diff --git a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h index a4a0f64..24e646da 100644 --- a/third_party/WebKit/Source/core/html/HTMLCanvasElement.h +++ b/third_party/WebKit/Source/core/html/HTMLCanvasElement.h
@@ -57,6 +57,7 @@ class GraphicsContext; class HTMLCanvasElement; class Image; +class ImageBitmapOptions; class ImageBuffer; class ImageBufferSurface; class ImageData; @@ -166,7 +167,7 @@ // ImageBitmapSource implementation IntSize bitmapSourceSize() const override; - ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, ExceptionState&) override; + ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&) override; DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp index 6568ae8..5b7fa06f 100644 --- a/third_party/WebKit/Source/core/html/HTMLImageElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLImageElement.cpp
@@ -42,6 +42,7 @@ #include "core/html/HTMLSourceElement.h" #include "core/html/parser/HTMLParserIdioms.h" #include "core/html/parser/HTMLSrcsetParser.h" +#include "core/imagebitmap/ImageBitmapOptions.h" #include "core/inspector/ConsoleMessage.h" #include "core/layout/LayoutBlockFlow.h" #include "core/layout/LayoutImage.h" @@ -684,7 +685,7 @@ imageLoader().updateFromElement(ImageLoader::UpdateForcedReload, m_referrerPolicy); } -ScriptPromise HTMLImageElement::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) +ScriptPromise HTMLImageElement::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, const ImageBitmapOptions& options, ExceptionState& exceptionState) { ASSERT(eventTarget.toDOMWindow()); if (!cachedImage()) { @@ -699,7 +700,7 @@ exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } - return ImageBitmapSource::fulfillImageBitmap(scriptState, ImageBitmap::create(this, IntRect(sx, sy, sw, sh), eventTarget.toDOMWindow()->document())); + return ImageBitmapSource::fulfillImageBitmap(scriptState, ImageBitmap::create(this, IntRect(sx, sy, sw, sh), eventTarget.toDOMWindow()->document(), options)); } void HTMLImageElement::selectSourceURL(ImageLoader::UpdateFromElementBehavior behavior)
diff --git a/third_party/WebKit/Source/core/html/HTMLImageElement.h b/third_party/WebKit/Source/core/html/HTMLImageElement.h index 1191799e6..d97b870 100644 --- a/third_party/WebKit/Source/core/html/HTMLImageElement.h +++ b/third_party/WebKit/Source/core/html/HTMLImageElement.h
@@ -39,6 +39,7 @@ class HTMLFormElement; class ImageCandidate; class ShadowRoot; +class ImageBitmapOptions; class CORE_EXPORT HTMLImageElement final : public HTMLElement, public CanvasImageSource, public ImageBitmapSource { DEFINE_WRAPPERTYPEINFO(); @@ -119,7 +120,7 @@ // ImageBitmapSource implementation IntSize bitmapSourceSize() const override; - ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, ExceptionState&) override; + ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&) override; protected: explicit HTMLImageElement(Document&, HTMLFormElement* = 0, bool createdByParser = false);
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp b/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp index 38bda79..ab6deeb1 100644 --- a/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp +++ b/third_party/WebKit/Source/core/html/HTMLVideoElement.cpp
@@ -36,6 +36,7 @@ #include "core/frame/ImageBitmap.h" #include "core/frame/Settings.h" #include "core/html/parser/HTMLParserIdioms.h" +#include "core/imagebitmap/ImageBitmapOptions.h" #include "core/layout/LayoutImage.h" #include "core/layout/LayoutVideo.h" #include "platform/RuntimeEnabledFeatures.h" @@ -325,7 +326,7 @@ return IntSize(videoWidth(), videoHeight()); } -ScriptPromise HTMLVideoElement::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) +ScriptPromise HTMLVideoElement::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, const ImageBitmapOptions& options, ExceptionState& exceptionState) { ASSERT(eventTarget.toDOMWindow()); if (networkState() == HTMLMediaElement::NETWORK_EMPTY) { @@ -340,7 +341,7 @@ exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); return ScriptPromise(); } - return ImageBitmapSource::fulfillImageBitmap(scriptState, ImageBitmap::create(this, IntRect(sx, sy, sw, sh), eventTarget.toDOMWindow()->document())); + return ImageBitmapSource::fulfillImageBitmap(scriptState, ImageBitmap::create(this, IntRect(sx, sy, sw, sh), eventTarget.toDOMWindow()->document(), options)); } } // namespace blink
diff --git a/third_party/WebKit/Source/core/html/HTMLVideoElement.h b/third_party/WebKit/Source/core/html/HTMLVideoElement.h index b7c0dc5..bd0eb79 100644 --- a/third_party/WebKit/Source/core/html/HTMLVideoElement.h +++ b/third_party/WebKit/Source/core/html/HTMLVideoElement.h
@@ -39,6 +39,7 @@ class WebGraphicsContext3D; class ExceptionState; class GraphicsContext; +class ImageBitmapOptions; // GL types as defined in OpenGL ES 2.0 header file gl2.h from khronos.org. // That header cannot be included directly due to a conflict with NPAPI headers. @@ -89,7 +90,7 @@ // ImageBitmapSource implementation IntSize bitmapSourceSize() const override; - ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, ExceptionState&) override; + ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&) override; private: HTMLVideoElement(Document&);
diff --git a/third_party/WebKit/Source/core/html/ImageData.cpp b/third_party/WebKit/Source/core/html/ImageData.cpp index 13987f5..5909815 100644 --- a/third_party/WebKit/Source/core/html/ImageData.cpp +++ b/third_party/WebKit/Source/core/html/ImageData.cpp
@@ -32,6 +32,7 @@ #include "bindings/core/v8/V8Uint8ClampedArray.h" #include "core/dom/ExceptionCode.h" #include "core/frame/ImageBitmap.h" +#include "core/imagebitmap/ImageBitmapOptions.h" #include "platform/RuntimeEnabledFeatures.h" namespace blink { @@ -146,7 +147,7 @@ return new ImageData(IntSize(width, height), data); } -ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) +ScriptPromise ImageData::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, const ImageBitmapOptions& options, ExceptionState& exceptionState) { if (!sw || !sh) { exceptionState.throwDOMException(IndexSizeError, String::format("The source %s provided is 0.", sw ? "height" : "width")); @@ -156,7 +157,7 @@ exceptionState.throwDOMException(InvalidStateError, "The source data has been neutered."); return ScriptPromise(); } - return ImageBitmapSource::fulfillImageBitmap(scriptState, ImageBitmap::create(this, IntRect(sx, sy, sw, sh))); + return ImageBitmapSource::fulfillImageBitmap(scriptState, ImageBitmap::create(this, IntRect(sx, sy, sw, sh), options)); } v8::Local<v8::Object> ImageData::associateWithWrapper(v8::Isolate* isolate, const WrapperTypeInfo* wrapperType, v8::Local<v8::Object> wrapper)
diff --git a/third_party/WebKit/Source/core/html/ImageData.h b/third_party/WebKit/Source/core/html/ImageData.h index 9c14119..cac3ed6 100644 --- a/third_party/WebKit/Source/core/html/ImageData.h +++ b/third_party/WebKit/Source/core/html/ImageData.h
@@ -41,6 +41,7 @@ namespace blink { class ExceptionState; +class ImageBitmapOptions; class CORE_EXPORT ImageData final : public GarbageCollectedFinalized<ImageData>, public ScriptWrappable, public ImageBitmapSource { DEFINE_WRAPPERTYPEINFO(); @@ -59,7 +60,7 @@ // ImageBitmapSource implementation IntSize bitmapSourceSize() const override { return m_size; } - ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, ExceptionState&) override; + ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&) override; DEFINE_INLINE_TRACE() { }
diff --git a/third_party/WebKit/Source/core/html/LinkRelAttribute.cpp b/third_party/WebKit/Source/core/html/LinkRelAttribute.cpp index 0c87a40..8dc7556 100644 --- a/third_party/WebKit/Source/core/html/LinkRelAttribute.cpp +++ b/third_party/WebKit/Source/core/html/LinkRelAttribute.cpp
@@ -86,11 +86,9 @@ } else if (equalIgnoringCase(linkType, "next")) { m_isLinkNext = true; } else if (equalIgnoringCase(linkType, "apple-touch-icon")) { - if (RuntimeEnabledFeatures::touchIconLoadingEnabled()) - m_iconType = TouchIcon; + m_iconType = TouchIcon; } else if (equalIgnoringCase(linkType, "apple-touch-icon-precomposed")) { - if (RuntimeEnabledFeatures::touchIconLoadingEnabled()) - m_iconType = TouchPrecomposedIcon; + m_iconType = TouchPrecomposedIcon; } else if (equalIgnoringCase(linkType, "manifest")) { m_isManifest = true; }
diff --git a/third_party/WebKit/Source/core/html/LinkRelAttributeTest.cpp b/third_party/WebKit/Source/core/html/LinkRelAttributeTest.cpp index d1e4cd0..a710de2 100644 --- a/third_party/WebKit/Source/core/html/LinkRelAttributeTest.cpp +++ b/third_party/WebKit/Source/core/html/LinkRelAttributeTest.cpp
@@ -36,22 +36,6 @@ namespace blink { -class LinkRelAttributeTest : public testing::Test { -protected: - void SetUp() override - { - m_touchIconLoadingEnabled = RuntimeEnabledFeatures::touchIconLoadingEnabled(); - } - - void TearDown() override - { - RuntimeEnabledFeatures::setTouchIconLoadingEnabled(m_touchIconLoadingEnabled); - } - -private: - bool m_touchIconLoadingEnabled; -}; - static inline void testLinkRelAttribute(String value, bool isStyleSheet, IconType iconType, bool isAlternate, bool isDNSPrefetch, bool isLinkSubresource, bool isLinkPrerender, bool isImport = false, bool isPreconnect = false) { LinkRelAttribute linkRelAttribute(value); @@ -65,47 +49,8 @@ ASSERT_EQ(isPreconnect, linkRelAttribute.isPreconnect()) << value.utf8().data(); } -TEST_F(LinkRelAttributeTest, Constructor) +TEST(LinkRelAttributeTest, Constructor) { - RuntimeEnabledFeatures::setTouchIconLoadingEnabled(false); - - testLinkRelAttribute("stylesheet", true, InvalidIcon, false, false, false, false); - testLinkRelAttribute("sTyLeShEeT", true, InvalidIcon, false, false, false, false); - - testLinkRelAttribute("icon", false, Favicon, false, false, false, false); - testLinkRelAttribute("iCoN", false, Favicon, false, false, false, false); - testLinkRelAttribute("shortcut icon", false, Favicon, false, false, false, false); - testLinkRelAttribute("sHoRtCuT iCoN", false, Favicon, false, false, false, false); - - testLinkRelAttribute("dns-prefetch", false, InvalidIcon, false, true, false, false); - testLinkRelAttribute("dNs-pReFeTcH", false, InvalidIcon, false, true, false, false); - - testLinkRelAttribute("apple-touch-icon", false, InvalidIcon, false, false, false, false); - testLinkRelAttribute("aPpLe-tOuCh-IcOn", false, InvalidIcon, false, false, false, false); - testLinkRelAttribute("apple-touch-icon-precomposed", false, InvalidIcon, false, false, false, false); - testLinkRelAttribute("aPpLe-tOuCh-IcOn-pReCoMpOsEd", false, InvalidIcon, false, false, false, false); - - testLinkRelAttribute("alternate stylesheet", true, InvalidIcon, true, false, false, false); - testLinkRelAttribute("stylesheet alternate", true, InvalidIcon, true, false, false, false); - testLinkRelAttribute("aLtErNaTe sTyLeShEeT", true, InvalidIcon, true, false, false, false); - testLinkRelAttribute("sTyLeShEeT aLtErNaTe", true, InvalidIcon, true, false, false, false); - - testLinkRelAttribute("stylesheet icon prerender aLtErNaTe", true, Favicon, true, false, false, true); - testLinkRelAttribute("alternate subresource", false, InvalidIcon, true, false, true, false); - testLinkRelAttribute("alternate icon stylesheet", true, Favicon, true, false, false, false); - - testLinkRelAttribute("import", false, InvalidIcon, false, false, false, false, true); - // "import" is mutually exclusive and "stylesheet" wins when they conflict. - testLinkRelAttribute("stylesheet import", true, InvalidIcon, false, false, false, false, false); - - testLinkRelAttribute("preconnect", false, InvalidIcon, false, false, false, false, false, true); - testLinkRelAttribute("pReCoNnEcT", false, InvalidIcon, false, false, false, false, false, true); -} - -TEST_F(LinkRelAttributeTest, ConstructorTouchIconLoadingEnabled) -{ - RuntimeEnabledFeatures::setTouchIconLoadingEnabled(true); - testLinkRelAttribute("stylesheet", true, InvalidIcon, false, false, false, false); testLinkRelAttribute("sTyLeShEeT", true, InvalidIcon, false, false, false, false);
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp index ce2457d..2d6fa0d 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.cpp
@@ -39,6 +39,7 @@ #include "core/html/HTMLImageElement.h" #include "core/html/HTMLVideoElement.h" #include "core/html/ImageData.h" +#include "core/imagebitmap/ImageBitmapOptions.h" #include "core/workers/WorkerGlobalScope.h" #include "platform/SharedBuffer.h" #include "platform/graphics/ImageSource.h" @@ -66,26 +67,38 @@ ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, const ImageBitmapSourceUnion& bitmapSource, ExceptionState& exceptionState) { + ImageBitmapOptions options; + return createImageBitmap(scriptState, eventTarget, bitmapSource, options, exceptionState); +} + +ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, const ImageBitmapSourceUnion& bitmapSource, const ImageBitmapOptions& options, ExceptionState& exceptionState) +{ ImageBitmapSource* bitmapSourceInternal = toImageBitmapSourceInternal(bitmapSource); if (bitmapSourceInternal->isBlob()) { Blob* blob = static_cast<Blob*>(bitmapSourceInternal); - ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::create(from(eventTarget), IntRect(), scriptState); + ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::create(from(eventTarget), IntRect(), options, scriptState); ScriptPromise promise = loader->promise(); from(eventTarget).addLoader(loader); loader->loadBlobAsync(eventTarget.executionContext(), blob); return promise; } IntSize srcSize = bitmapSourceInternal->bitmapSourceSize(); - return createImageBitmap(scriptState, eventTarget, bitmapSourceInternal, 0, 0, srcSize.width(), srcSize.height(), exceptionState); + return createImageBitmap(scriptState, eventTarget, bitmapSourceInternal, 0, 0, srcSize.width(), srcSize.height(), options, exceptionState); } ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, const ImageBitmapSourceUnion& bitmapSource, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) { - ImageBitmapSource* bitmapSourceInternal = toImageBitmapSourceInternal(bitmapSource); - return createImageBitmap(scriptState, eventTarget, bitmapSourceInternal, sx, sy, sw, sh, exceptionState); + ImageBitmapOptions options; + return createImageBitmap(scriptState, eventTarget, bitmapSource, sx, sy, sw, sh, options, exceptionState); } -ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, ImageBitmapSource* bitmapSource, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) +ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, const ImageBitmapSourceUnion& bitmapSource, int sx, int sy, int sw, int sh, const ImageBitmapOptions& options, ExceptionState& exceptionState) +{ + ImageBitmapSource* bitmapSourceInternal = toImageBitmapSourceInternal(bitmapSource); + return createImageBitmap(scriptState, eventTarget, bitmapSourceInternal, sx, sy, sw, sh, options, exceptionState); +} + +ScriptPromise ImageBitmapFactories::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, ImageBitmapSource* bitmapSource, int sx, int sy, int sw, int sh, const ImageBitmapOptions& options, ExceptionState& exceptionState) { if (bitmapSource->isBlob()) { if (!sw || !sh) { @@ -93,14 +106,14 @@ return ScriptPromise(); } Blob* blob = static_cast<Blob*>(bitmapSource); - ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::create(from(eventTarget), IntRect(sx, sy, sw, sh), scriptState); + ImageBitmapLoader* loader = ImageBitmapFactories::ImageBitmapLoader::create(from(eventTarget), IntRect(sx, sy, sw, sh), options, scriptState); ScriptPromise promise = loader->promise(); from(eventTarget).addLoader(loader); loader->loadBlobAsync(eventTarget.executionContext(), blob); return promise; } - return bitmapSource->createImageBitmap(scriptState, eventTarget, sx, sy, sw, sh, exceptionState); + return bitmapSource->createImageBitmap(scriptState, eventTarget, sx, sy, sw, sh, options, exceptionState); } const char* ImageBitmapFactories::supplementName() @@ -139,11 +152,12 @@ m_pendingLoaders.remove(loader); } -ImageBitmapFactories::ImageBitmapLoader::ImageBitmapLoader(ImageBitmapFactories& factory, const IntRect& cropRect, ScriptState* scriptState) +ImageBitmapFactories::ImageBitmapLoader::ImageBitmapLoader(ImageBitmapFactories& factory, const IntRect& cropRect, ScriptState* scriptState, const ImageBitmapOptions& options) : m_loader(FileReaderLoader::ReadAsArrayBuffer, this) , m_factory(&factory) , m_resolver(ScriptPromiseResolver::create(scriptState)) , m_cropRect(cropRect) + , m_options(options) { } @@ -190,7 +204,7 @@ m_cropRect = IntRect(IntPoint(), image->size()); } - RefPtrWillBeRawPtr<ImageBitmap> imageBitmap = ImageBitmap::create(image, m_cropRect); + RefPtrWillBeRawPtr<ImageBitmap> imageBitmap = ImageBitmap::create(image, m_cropRect, m_options); m_resolver->resolve(imageBitmap.release()); m_factory->didFinishLoading(this); }
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h index 3a311c1..f133854b 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.h
@@ -37,16 +37,18 @@ #include "bindings/core/v8/UnionTypesCore.h" #include "core/fileapi/FileReaderLoader.h" #include "core/fileapi/FileReaderLoaderClient.h" +#include "core/imagebitmap/ImageBitmapOptions.h" #include "platform/Supplementable.h" #include "platform/geometry/IntRect.h" namespace blink { -class ImageBitmapSource; class Blob; class EventTarget; class ExceptionState; class ExecutionContext; +class ImageBitmapSource; +class ImageBitmapOptions; typedef HTMLImageElementOrHTMLVideoElementOrHTMLCanvasElementOrBlobOrImageDataOrImageBitmap ImageBitmapSourceUnion; @@ -56,8 +58,10 @@ public: static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, const ImageBitmapSourceUnion&, ExceptionState&); + static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, const ImageBitmapSourceUnion&, const ImageBitmapOptions&, ExceptionState&); static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, const ImageBitmapSourceUnion&, int sx, int sy, int sw, int sh, ExceptionState&); - static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, ImageBitmapSource*, int sx, int sy, int sw, int sh, ExceptionState&); + static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, const ImageBitmapSourceUnion&, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&); + static ScriptPromise createImageBitmap(ScriptState*, EventTarget&, ImageBitmapSource*, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&); virtual ~ImageBitmapFactories() { } @@ -69,9 +73,9 @@ private: class ImageBitmapLoader final : public GarbageCollectedFinalized<ImageBitmapLoader>, public FileReaderLoaderClient { public: - static ImageBitmapLoader* create(ImageBitmapFactories& factory, const IntRect& cropRect, ScriptState* scriptState) + static ImageBitmapLoader* create(ImageBitmapFactories& factory, const IntRect& cropRect, const ImageBitmapOptions& options, ScriptState* scriptState) { - return new ImageBitmapLoader(factory, cropRect, scriptState); + return new ImageBitmapLoader(factory, cropRect, scriptState, options); } void loadBlobAsync(ExecutionContext*, Blob*); @@ -82,7 +86,7 @@ ~ImageBitmapLoader() override { } private: - ImageBitmapLoader(ImageBitmapFactories&, const IntRect&, ScriptState*); + ImageBitmapLoader(ImageBitmapFactories&, const IntRect&, ScriptState*, const ImageBitmapOptions&); void rejectPromise(); @@ -96,6 +100,7 @@ RawPtrWillBeMember<ImageBitmapFactories> m_factory; Member<ScriptPromiseResolver> m_resolver; IntRect m_cropRect; + ImageBitmapOptions m_options; }; static ImageBitmapFactories& from(EventTarget&);
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl index fa642d1..703fc5a 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapFactories.idl
@@ -44,7 +44,11 @@ RuntimeEnabled=ExperimentalCanvasFeatures, ] interface ImageBitmapFactories { [CallWith=ScriptState, RaisesException] Promise createImageBitmap(ImageBitmapSource imageBitmap); + [CallWith=ScriptState, RaisesException, RuntimeEnabled=ExperimentalCanvasFeatures] Promise createImageBitmap( + ImageBitmapSource imageBitmap, ImageBitmapOptions options); [CallWith=ScriptState, RaisesException] Promise createImageBitmap(ImageBitmapSource imageBitmap, long sx, long sy, long sw, long sh); + [CallWith=ScriptState, RaisesException, RuntimeEnabled=ExperimentalCanvasFeatures] Promise createImageBitmap( + ImageBitmapSource imageBitmap, long sx, long sy, long sw, long sh, ImageBitmapOptions options); }; Window implements ImageBitmapFactories;
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapOptions.idl b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapOptions.idl new file mode 100644 index 0000000..2f54dd07 --- /dev/null +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapOptions.idl
@@ -0,0 +1,7 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +dictionary ImageBitmapOptions { + boolean premuiltiplyAlpha; +};
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapSource.cpp b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapSource.cpp index d01c4cd2..b80d4b0b 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapSource.cpp +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapSource.cpp
@@ -5,6 +5,7 @@ #include "core/imagebitmap/ImageBitmapSource.h" #include "core/frame/ImageBitmap.h" +#include "core/imagebitmap/ImageBitmapOptions.h" namespace blink { @@ -20,7 +21,7 @@ return promise; } -ScriptPromise ImageBitmapSource::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, ExceptionState& exceptionState) +ScriptPromise ImageBitmapSource::createImageBitmap(ScriptState* scriptState, EventTarget& eventTarget, int sx, int sy, int sw, int sh, const ImageBitmapOptions& options, ExceptionState& exceptionState) { return ScriptPromise(); }
diff --git a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapSource.h b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapSource.h index d0043dd..e3194345 100644 --- a/third_party/WebKit/Source/core/imagebitmap/ImageBitmapSource.h +++ b/third_party/WebKit/Source/core/imagebitmap/ImageBitmapSource.h
@@ -15,11 +15,12 @@ namespace blink { class ImageBitmap; +class ImageBitmapOptions; class CORE_EXPORT ImageBitmapSource { public: virtual IntSize bitmapSourceSize() const { return IntSize(); } - virtual ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, ExceptionState&); + virtual ScriptPromise createImageBitmap(ScriptState*, EventTarget&, int sx, int sy, int sw, int sh, const ImageBitmapOptions&, ExceptionState&); virtual bool isBlob() const { return false; }
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h index d7b6be42..95b43d8 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlow.h
@@ -413,6 +413,16 @@ bool everHadLayout; }; + // MarginValues holds the margins in the block direction + // used during collapsing margins computation. + // CSS mandates to keep track of both positive and negative margins: + // "When two or more margins collapse, the resulting margin width is the + // maximum of the collapsing margins' widths. In the case of negative + // margins, the maximum of the absolute values of the negative adjoining + // margins is deducted from the maximum of the positive adjoining margins. + // If there are no positive margins, the maximum of the absolute values of + // the adjoining margins is deducted from zero." + // https://drafts.csswg.org/css2/box.html#collapsing-margins class MarginValues { DISALLOW_NEW(); public:
diff --git a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp index 89797029..a1b50a2 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBlockFlowLine.cpp
@@ -95,7 +95,7 @@ if (r->m_object->isText()) { unsigned opportunitiesInRun = m_runsWithExpansions[i++]; - ASSERT(opportunitiesInRun <= m_totalOpportunities); + RELEASE_ASSERT(opportunitiesInRun <= m_totalOpportunities); // Don't justify for white-space: pre. if (r->m_object->style()->whiteSpace() != PRE) {
diff --git a/third_party/WebKit/Source/core/layout/LayoutBox.h b/third_party/WebKit/Source/core/layout/LayoutBox.h index 6317d15a..2a9e559 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBox.h +++ b/third_party/WebKit/Source/core/layout/LayoutBox.h
@@ -531,6 +531,10 @@ LayoutUnit adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const; LayoutUnit adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit height) const; + // ComputedMarginValues holds the actual values for margins. It ignores + // margin collapsing as they are handled in LayoutBlockFlow. + // The margins are stored in logical coordinates (see COORDINATE + // SYSTEMS in LayoutBoxModel) for use during layout. struct ComputedMarginValues { DISALLOW_NEW(); ComputedMarginValues() { } @@ -540,14 +544,28 @@ LayoutUnit m_start; LayoutUnit m_end; }; + + // LogicalExtentComputedValues is used both for the + // block-flow and inline-direction axis. struct LogicalExtentComputedValues { STACK_ALLOCATED(); LogicalExtentComputedValues() { } + // This is the dimension in the measured direction + // (logical height or logical width). LayoutUnit m_extent; + + // This is the offset in the measured direction + // (logical top or logical left). LayoutUnit m_position; + + // |m_margins| represents the margins in the measured direction. + // Note that ComputedMarginValues has also the margins in + // the orthogonal direction to have clearer names but they are + // ignored in the code. ComputedMarginValues m_margins; }; + // Resolve auto margins in the chosen direction of the containing block so that objects can be pushed to the start, middle or end // of the containing block. void computeMarginsForDirection(MarginDirection forDirection, const LayoutBlock* containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd, Length marginStartLength, Length marginStartEnd) const;
diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp index fc3ee5d..4a4187ff 100644 --- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObject.cpp
@@ -349,7 +349,7 @@ return; bool establishesNewPaintInvalidationContainer = isPaintInvalidationContainer(); - const LayoutBoxModelObject& newPaintInvalidationContainer = *adjustCompositedContainerForSpecialAncestors(establishesNewPaintInvalidationContainer ? this : &paintInvalidationState.paintInvalidationContainer()); + const LayoutBoxModelObject& newPaintInvalidationContainer = establishesNewPaintInvalidationContainer ? *this : paintInvalidationState.paintInvalidationContainer(); // FIXME: This assert should be re-enabled when we move paint invalidation to after compositing update. crbug.com/360286 // ASSERT(&newPaintInvalidationContainer == &containerForPaintInvalidation());
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.cpp b/third_party/WebKit/Source/core/layout/LayoutObject.cpp index a53c6468..505b5a3 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutObject.cpp
@@ -1076,10 +1076,17 @@ { RELEASE_ASSERT(isRooted()); - const LayoutBoxModelObject* paintInvalidationContainer = adjustCompositedContainerForSpecialAncestors(enclosingCompositedContainer()); - ASSERT(paintInvalidationContainer); + if (const LayoutBoxModelObject* paintInvalidationContainer = enclosingCompositedContainer()) + return *paintInvalidationContainer; - return *paintInvalidationContainer; + // If the current frame is not composited, we send just return + // the main frame's LayoutView so that we generate invalidations + // on the window. + const LayoutView* layoutView = view(); + while (layoutView->frame()->ownerLayoutObject()) + layoutView = layoutView->frame()->ownerLayoutObject()->view(); + ASSERT(layoutView); + return *layoutView; } const LayoutBoxModelObject* LayoutObject::enclosingCompositedContainer() const @@ -1093,17 +1100,6 @@ return container; } -const LayoutBoxModelObject* LayoutObject::adjustCompositedContainerForSpecialAncestors(const LayoutBoxModelObject* paintInvalidationContainer) const -{ - if (paintInvalidationContainer) - return paintInvalidationContainer; - - LayoutView* layoutView = view(); - while (layoutView->frame()->ownerLayoutObject()) - layoutView = layoutView->frame()->ownerLayoutObject()->view(); - return layoutView; -} - String LayoutObject::decoratedName() const { StringBuilder name;
diff --git a/third_party/WebKit/Source/core/layout/LayoutObject.h b/third_party/WebKit/Source/core/layout/LayoutObject.h index ccf060bc..ad307f07 100644 --- a/third_party/WebKit/Source/core/layout/LayoutObject.h +++ b/third_party/WebKit/Source/core/layout/LayoutObject.h
@@ -1040,12 +1040,15 @@ void getTextDecorations(unsigned decorations, AppliedTextDecoration& underline, AppliedTextDecoration& overline, AppliedTextDecoration& linethrough, bool quirksMode = false, bool firstlineStyle = false); - // Return the LayoutBoxModelObject in the container chain which is responsible for painting this object, or layout view - // if painting is root-relative. This is the container that should be passed to the 'forPaintInvalidation' - // methods. + // Return the LayoutBoxModelObject in the container chain which + // is responsible for painting this object. The function crosses + // frames boundaries so the returned value can be in a + // different document. + // + // This is the container that should be passed to + // the '*forPaintInvalidation' methods. const LayoutBoxModelObject& containerForPaintInvalidation() const; - const LayoutBoxModelObject* adjustCompositedContainerForSpecialAncestors(const LayoutBoxModelObject* paintInvalidationContainer) const; bool isPaintInvalidationContainer() const; LayoutRect computePaintInvalidationRect()
diff --git a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp index 2e12b16..d4ccc10 100644 --- a/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp +++ b/third_party/WebKit/Source/core/layout/LayoutScrollbarPart.cpp
@@ -197,7 +197,7 @@ void LayoutScrollbarPart::setNeedsPaintInvalidation() { if (m_scrollbar) { - m_scrollbar->setNeedsPaintInvalidation(); + m_scrollbar->setNeedsPaintInvalidation(AllParts); return; }
diff --git a/third_party/WebKit/Source/core/layout/PaintInvalidationState.h b/third_party/WebKit/Source/core/layout/PaintInvalidationState.h index 22962f2a..39d1c62c 100644 --- a/third_party/WebKit/Source/core/layout/PaintInvalidationState.h +++ b/third_party/WebKit/Source/core/layout/PaintInvalidationState.h
@@ -17,6 +17,15 @@ class LayoutSVGModelObject; class LayoutView; +// PaintInvalidationState is an optimization used during the paint +// invalidation phase. +// +// This class is extremely close to LayoutState so see the documentation +// of LayoutState for the class existence and performance benefits. +// +// The main difference with LayoutState is that it was customized for the +// needs of the paint invalidation systems (keeping visual rectangles +// instead of layout specific information). class PaintInvalidationState { DISALLOW_NEW_EXCEPT_PLACEMENT_NEW(); WTF_MAKE_NONCOPYABLE(PaintInvalidationState); @@ -77,6 +86,9 @@ // x/y offset from paint invalidation container. Includes relative positioning and scroll offsets. LayoutSize m_paintOffset; + // The current paint invalidation container. + // + // It is the enclosing composited object. const LayoutBoxModelObject& m_paintInvalidationContainer; // Transform from the initial viewport coordinate system of an outermost
diff --git a/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp b/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp index 5a8bb315..90d4b5b 100644 --- a/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp +++ b/third_party/WebKit/Source/core/layout/TracedLayoutObject.cpp
@@ -9,6 +9,7 @@ #include "core/layout/LayoutText.h" #include "core/layout/LayoutView.h" #include "platform/JSONValues.h" +#include <inttypes.h> namespace blink { @@ -26,7 +27,7 @@ } TracedLayoutObject::TracedLayoutObject(const LayoutObject& object, bool traceGeometry) - : m_address(&object) + : m_address(reinterpret_cast<uintptr_t>(&object)) , m_isAnonymous(object.isAnonymous()) , m_isPositioned(object.isOutOfFlowPositioned()) , m_isRelPositioned(object.isRelPositioned()) @@ -86,7 +87,7 @@ PassRefPtr<JSONObject> TracedLayoutObject::toJSON() const { RefPtr<JSONObject> json(JSONObject::create()); - json->setString("address", String::format("%p", m_address)); + json->setString("address", String::format("%" PRIxPTR, m_address)); json->setString("name", m_name); if (!m_tag.isEmpty()) json->setString("tag", m_tag);
diff --git a/third_party/WebKit/Source/core/layout/TracedLayoutObject.h b/third_party/WebKit/Source/core/layout/TracedLayoutObject.h index b65be70..0861f9c 100644 --- a/third_party/WebKit/Source/core/layout/TracedLayoutObject.h +++ b/third_party/WebKit/Source/core/layout/TracedLayoutObject.h
@@ -27,7 +27,7 @@ PassRefPtr<JSONObject> toJSON() const; - const LayoutObject* m_address; + uintptr_t m_address; bool m_isAnonymous; bool m_isPositioned; bool m_isRelPositioned;
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp index 32b90b90..27d73c6 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.cpp
@@ -338,9 +338,10 @@ m_documentLoader->applicationCacheHost()->willStartLoadingResource(request); } -void FrameFetchContext::didLoadResource() +void FrameFetchContext::didLoadResource(Resource* resource) { - frame()->loader().checkCompleted(); + if (resource->isLoadEventBlockingResourceType()) + frame()->loader().checkCompleted(); } void FrameFetchContext::addResourceTiming(const ResourceTimingInfo& info)
diff --git a/third_party/WebKit/Source/core/loader/FrameFetchContext.h b/third_party/WebKit/Source/core/loader/FrameFetchContext.h index 2807f141..d1d33284 100644 --- a/third_party/WebKit/Source/core/loader/FrameFetchContext.h +++ b/third_party/WebKit/Source/core/loader/FrameFetchContext.h
@@ -82,7 +82,7 @@ bool shouldLoadNewResource(Resource::Type) const override; void willStartLoadingResource(ResourceRequest&) override; - void didLoadResource() override; + void didLoadResource(Resource*) override; void addResourceTiming(const ResourceTimingInfo&) override; bool allowImage(bool imagesEnabled, const KURL&) const override;
diff --git a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h index 3f85998..d83f852b 100644 --- a/third_party/WebKit/Source/core/loader/FrameLoaderClient.h +++ b/third_party/WebKit/Source/core/loader/FrameLoaderClient.h
@@ -185,7 +185,7 @@ virtual bool allowPlugins(bool enabledPerSettings) { return enabledPerSettings; } virtual bool allowImage(bool enabledPerSettings, const KURL&) { return enabledPerSettings; } virtual bool allowMedia(const KURL&) { return true; } - virtual bool allowDisplayingInsecureContent(bool enabledPerSettings, SecurityOrigin*, const KURL&) { return enabledPerSettings; } + virtual bool allowDisplayingInsecureContent(bool enabledPerSettings, const KURL&) { return enabledPerSettings; } virtual bool allowRunningInsecureContent(bool enabledPerSettings, SecurityOrigin*, const KURL&) { return enabledPerSettings; } // This callback notifies the client that the frame was about to run
diff --git a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp index bd14f03..0b0dd21 100644 --- a/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp +++ b/third_party/WebKit/Source/core/loader/MixedContentChecker.cpp
@@ -326,7 +326,7 @@ switch (contextType) { case ContextTypeOptionallyBlockable: - allowed = !strictMode && client->allowDisplayingInsecureContent(settings && settings->allowDisplayOfInsecureContent(), securityOrigin, url); + allowed = !strictMode && client->allowDisplayingInsecureContent(settings && settings->allowDisplayOfInsecureContent(), url); if (allowed) client->didDisplayInsecureContent(); break;
diff --git a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp index 8f37b54..36909481 100644 --- a/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp +++ b/third_party/WebKit/Source/core/paint/BackgroundImageGeometry.cpp
@@ -276,6 +276,7 @@ EFillRepeat backgroundRepeatX = fillLayer.repeatX(); EFillRepeat backgroundRepeatY = fillLayer.repeatY(); + positioningAreaSize = LayoutSize(snapSizeToPixel(positioningAreaSize.width(), m_destRect.x()), snapSizeToPixel(positioningAreaSize.height(), m_destRect.y())); LayoutUnit availableWidth = positioningAreaSize.width() - tileSize().width(); LayoutUnit availableHeight = positioningAreaSize.height() - tileSize().height();
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes index 9a450dd..4c578777 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/optimize_png.hashes
@@ -2,7 +2,7 @@ "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28", "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45", "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485", - "toolbarButtonGlyphs.svg": "77caea74e2048455f89bbd727f67f760", + "toolbarButtonGlyphs.svg": "55b01beb3c00d0f82b773216f990526d", "breakpoint.svg": "69cd92d807259c022791112809b97799", "responsiveDesign.svg": "1d6e963f88e5e448a7cff85f75a0e6b0" } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes index 9a450dd..4c578777 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/svg2png.hashes
@@ -2,7 +2,7 @@ "breakpointConditional.svg": "4cf90210b2af2ed84db2f60b07bcde28", "errorWave.svg": "e183fa242a22ed4784a92f6becbc2c45", "settingsListRemove.svg": "ce9e7c5c5cdaef28e6ee51d9478d5485", - "toolbarButtonGlyphs.svg": "77caea74e2048455f89bbd727f67f760", + "toolbarButtonGlyphs.svg": "55b01beb3c00d0f82b773216f990526d", "breakpoint.svg": "69cd92d807259c022791112809b97799", "responsiveDesign.svg": "1d6e963f88e5e448a7cff85f75a0e6b0" } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg index bd4c59dd..fe1e492 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg +++ b/third_party/WebKit/Source/devtools/front_end/Images/src/toolbarButtonGlyphs.svg
@@ -21,13 +21,13 @@ rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><sodipodi:namedview showgrid="true" id="namedview3397" - inkscape:zoom="3.3551137" - inkscape:cx="205.87081" - inkscape:cy="41.561776" - inkscape:window-width="2560" - inkscape:window-height="1547" - inkscape:window-x="0" - inkscape:window-y="0" + inkscape:zoom="4.7448473" + inkscape:cx="225.17445" + inkscape:cy="59.825604" + inkscape:window-width="2495" + inkscape:window-height="1576" + inkscape:window-x="65" + inkscape:window-y="24" inkscape:window-maximized="1" inkscape:current-layer="svg3395" inkscape:snap-global="false" @@ -851,11 +851,6 @@ sodipodi:ry="1.0606602" d="m 209.92234,31.304852 a 1.0606602,1.0606602 0 1 1 -2.12132,0 1.0606602,1.0606602 0 1 1 2.12132,0 z" transform="matrix(1.4142135,0,0,1.4142135,-86.874986,-2.771743)" /><path - inkscape:connector-curvature="0" - d="m 335,138 -3.66666,0 C 330.59667,138 330,137.40333 330,136.66667 l 0,-9.33334 C 330,126.59667 330.59667,126 331.33334,126 l 9.33333,0 c 0.73667,0 1.33333,0.59667 1.33333,1.33333 l 0,3.66667 -2,-0.6 0,-2.4 -8,-3.4e-4 0,8.00017 2.22223,3.4e-4 z m 5.25657,-2.70598 2.40637,-2.40638 L 334,130 l 2.88765,8.66294 2.40637,-2.40638 L 343.03746,140 344,139.03745 z" - id="inspect_element" - sketch:type="MSShapeGroup" - sodipodi:nodetypes="cssssssccccccccccccccc" /><path d="m 23,157 -2,0 0,2 2,0 z" id="path3288" /><path d="m 23,161 -2,0 0,2 c 1,0 2,-1 2,-2 z" @@ -933,12 +928,6 @@ id="path3486" d="m 119.56171,198.24443 -5.5,14 h 2.25 l 1.12,-3 h 6.25 l 1.12,3 h 2.25 l -5.49,-14 h -2 z m -1.38,9 2.38,-6.33 2.38,6.33 h -4.76 z" inkscape:connector-curvature="0" /></g><path - inkscape:connector-curvature="0" - d="m 210.99916,149.68 c 2.18912,1.03333 3.75564,3.14666 3.99665,5.65334 H 216 C 215.65857,151.22667 212.21088,148 208,148 l -0.44184,0.02 2.55062,2.54 0.89038,-0.88 z m -4.1841,-0.51333 c -0.39497,-0.39333 -1.03096,-0.39333 -1.41924,0 l -4.25775,4.24 c -0.39497,0.39333 -0.39497,1.02666 0,1.41333 l 8.04686,8.01333 c 0.39498,0.39333 1.03097,0.39333 1.41925,0 l 4.25774,-4.23999 c 0.39498,-0.39334 0.39498,-1.02667 0,-1.41334 l -8.04686,-8.01333 z m 3.0795,12.96 -8.04686,-8.01333 4.25774,-4.24001 8.04686,8.01333 -4.25774,4.24001 z m -4.89373,0.19333 c -2.18911,-1.02667 -3.75564,-3.14666 -3.99664,-5.65334 H 200 c 0.34143,4.10667 3.78912,7.33334 8,7.33334 l 0.44183,-0.02 -2.55062,-2.54 -0.89038,0.88 z" - id="path6" /><path - inkscape:connector-curvature="0" - d="m 267,110 h -2 v 5 h 5 v -2 h -3 v -3 z m -2,-4 h 2 v -3 h 3 v -2 h -5 v 5 z m 12,7 h -3 v 2 h 5 v -5 h -2 v 3 z m -3,-12 v 2 h 3 v 3 h 2 v -5 h -5 z" - id="path6-6" /><path style="fill:none" inkscape:connector-curvature="0" d="m 166,147 h 18 v 18 h -18 z" @@ -985,22 +974,77 @@ style="fill:none" inkscape:connector-curvature="0" d="m 231,75 h 18 v 18 h -18 z" - id="path4367" /><path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 300,100.99977 0,4.00012 0,1.00007 3.34345,0.53115 -0.0156,8.04683 L 302,114.99977 c 0.006,0.59278 0.43931,1.01145 1,1 l 8,0 c 0.57896,0.002 0.98177,-0.42708 1,-1 l 0,-14 c -0.0102,-0.53477 -0.48177,-0.99739 -1,-1 l -10,0 c -0.53297,0.008 -0.99716,0.45677 -1,1 z m 1,0 10,0 0,13.9995 -8,0 0.71845,-0.42179 0.0937,-8.4218 -2.8122,-0.1561 0,-0.99993 z" - id="rect3641-2-5-28" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccccccccccccccccccccc" /><path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 297,105.99954 0,9 c 0.006,0.59278 0.43931,1.01145 1,1 l 5,0 c 0.57896,0.002 0.98177,-0.42708 1,-1 l 0,-9 c -0.0102,-0.53477 -0.48177,-0.99739 -1,-1 l -5,0 c -0.53297,0.008 -0.99716,0.45677 -1,1 z m 1,1.00023 5,0 0,7 -5,0 z" - id="rect3641-2-5-28-7" - inkscape:connector-curvature="0" - sodipodi:nodetypes="cccccccccccccc" /><path - style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" - d="m 299,150 0,12 c 0.006,0.62742 0.46004,1 1,1 l 7,0 c 0.51693,-5.4e-4 1,-0.46004 1,-1 l 0,-12 c 0,-0.54731 -0.43242,-1 -1,-1 l -7,0 c -0.54731,0 -1,0.42137 -1,1 z m 1,1 7,0 0,9 -7,0 z m 2,10 3,0 0,1 -3,0 z" - id="rect3641-2-5-2" - inkscape:connector-curvature="0" - sodipodi:nodetypes="sccccsssscccccccccc" /><path + id="path4367" /><g + id="g3680" + transform="translate(31,0)"><path + sodipodi:nodetypes="cccccccccccccccccccccc" + inkscape:connector-curvature="0" + id="rect3641-2-5-28" + d="m 300,100.99977 0,4.00012 0,1.00007 3.34345,0.53115 -0.0156,8.04683 L 302,114.99977 c 0.006,0.59278 0.43931,1.01145 1,1 l 8,0 c 0.57896,0.002 0.98177,-0.42708 1,-1 l 0,-14 c -0.0102,-0.53477 -0.48177,-0.99739 -1,-1 l -10,0 c -0.53297,0.008 -0.99716,0.45677 -1,1 z m 1,0 10,0 0,13.9995 -8,0 0.71845,-0.42179 0.0937,-8.4218 -2.8122,-0.1561 0,-0.99993 z" + style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /><path + sodipodi:nodetypes="cccccccccccccc" + inkscape:connector-curvature="0" + id="rect3641-2-5-28-7" + d="m 297,105.99954 0,9 c 0.006,0.59278 0.43931,1.01145 1,1 l 5,0 c 0.57896,0.002 0.98177,-0.42708 1,-1 l 0,-9 c -0.0102,-0.53477 -0.48177,-0.99739 -1,-1 l -5,0 c -0.53297,0.008 -0.99716,0.45677 -1,1 z m 1,1.00023 5,0 0,7 -5,0 z" + style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" /></g><path inkscape:connector-curvature="0" d="M 169,16.08946 V 19 h 2.91054 L 180.1944,10.71614 177.28385,7.8055997 169,16.08946 z m 13.76911,-7.9387003 c 0.30785,-0.30785 0.30785,-0.79294 0,-1.1007901 l -1.81908,-1.81909 c -0.30785,-0.3078399 -0.79295,-0.3078399 -1.10078,0 l -1.52058,1.52991 2.91054,2.9105401 1.5299,-1.52057 z" - id="path4" /></svg> \ No newline at end of file + id="path4" /><g + style="fill:none;stroke:none" + id="Page-1-82" + sketch:type="MSPage" + transform="translate(264,100)"><g + style="fill:#000000" + id="Full" + sketch:type="MSLayerGroup"><path + inkscape:connector-curvature="0" + d="m 6.1674972,9.1763856 -2.2250867,2.2088114 0,-2.9960346 c 0,-0.26 -0.2112,-0.4677587 -0.4712052,-0.4677587 C 3.2112,7.9214037 3,8.1289899 3,8.3891624 l 0,4.1244826 c 0,0.119655 0.045158,0.239483 0.1375579,0.331035 0.0924,0.09172 0.2129368,0.136551 0.3336474,0.136551 l 4.1567842,0 c 0.2600052,0 0.4712052,-0.209482 0.4712052,-0.467758 0,-0.258276 -0.2110263,-0.467759 -0.4712052,-0.467759 l -3.0181106,0 5.1332369,-5.0975861 c 0.046878,-0.04601 0.081864,-0.099497 0.1049588,-0.1566711 l 2.2095154,-2.1933534 0,2.9962069 c 0,0.2582759 0.211026,0.4677587 0.471205,0.4677587 C 12.788974,8.062069 13,7.8525862 13,7.5943103 L 13,3.467931 C 13,3.3481035 12.954842,3.2282759 12.862442,3.1365517 12.770216,3.0448276 12.649505,3 12.528795,3 L 8.3720105,3 C 8.1118316,3 7.9008053,3.2096552 7.9008053,3.4681035 c 0,0.2581034 0.2110263,0.4677586 0.4712052,0.4677586 l 3.0179365,0 -5.1162154,5.0806896 c -0.047773,0.046933 -0.083184,0.101519 -0.1062344,0.1598339 z M 1,15 1,1 15,1 15,15 1,15 z M 1.6326531,0 C 0.73925744,0 0.00747187,0.82461191 5.6852594e-5,1.8357304 1.8975867e-5,1.8408953 0,14.14876 0,14.14876 0,15.166942 0.73469388,16 1.6326531,16 L 14.367347,16 C 15.265306,16 16,15.166942 16,14.14876 L 16,1.8512397 C 16,0.83305785 15.265306,0.0092562 14.367347,0.0092562 L 1.6326531,0 z" + sketch:type="MSShapeGroup" + id="path3590" /></g></g><g + transform="translate(330,126)" + style="fill:none;stroke:none" + id="Page-1-3" + sketch:type="MSPage"><g + id="inspect-element" + sketch:type="MSLayerGroup" + transform="translate(-2,-2)"><path + style="opacity:0.5" + inkscape:connector-curvature="0" + d="M 0,0 16,0 16,16 0,16 0,0 z" + id="bounds-9" + sketch:type="MSShapeGroup" /><path + style="fill:#000000" + inkscape:connector-curvature="0" + d="M 6,14 3.5,14 C 2.5,14 2,13.5 2,12.5 l 0,-9 C 2,2.5 2.5,2 3.5,2 l 9,0 C 14,2 14,3.4678488 14,3.5 14,2 14,6 14,6 l -1,0 0,-3 -10,0 0,10 3,0 0,1 z m 8.999992,-5 -2.999984,1.99997 3,3 -1,1 -3,-3 L 8.9999924,15 l -2,-7.9999695 L 14.999992,9 l 0,0 z" + sketch:type="MSShapeGroup" + id="path3750" /></g></g><g + transform="translate(297,101)" + style="fill:none;stroke:none" + id="Page-1-9" + sketch:type="MSPage"><g + id="Responsive" + sketch:type="MSLayerGroup" + transform="translate(-1,-1)"><path + style="opacity:0.5" + inkscape:connector-curvature="0" + d="M 0,0 16,0 16,16 0,16 0,0 z" + id="bounds" + sketch:type="MSShapeGroup" /><path + style="fill:#000000" + inkscape:connector-curvature="0" + d="M 4.3095238,0 C 3.5892857,0 3,0.573 3,1.273 L 3,14.727 C 3,15.427 3.5892857,16 4.3095238,16 l 7.3809522,0 C 12.410714,16 13,15.427 13,14.727 L 13,1.273 C 13,0.573 12.410714,0.0063636 11.690476,0 z M 12,15 4,15 4,1 12,1 z m 2,-11 1,0 0,8 -1,0 z M 1,4 2,4 2,12 1,12 z" + id="responsive" + sketch:type="MSShapeGroup" + sodipodi:nodetypes="ssssssscsccccccccccccccc" /></g></g><g + style="fill:none;stroke:none" + id="Page-1-97" + sketch:type="MSPage" + transform="translate(201,149)"><g + style="fill:#000000" + id="Rotate-8" + sketch:type="MSLayerGroup" + transform="translate(-1,-1)"><path + inkscape:connector-curvature="0" + d="m 10.624268,2.47 c 1.915481,0.9041667 3.286192,2.7533333 3.497071,4.9466667 l 0.878661,0 C 14.701255,3.8233333 11.684519,1 8,1 L 7.6133891,1.0175 9.8451883,3.24 10.624268,2.47 l 0,0 z M 6.9631799,2.0208333 c -0.3456067,-0.3441666 -0.902092,-0.3441666 -1.241841,0 l -3.725523,3.71 C 1.6502092,6.075 1.6502092,6.6291667 1.9958159,6.9675 l 7.0410042,7.011667 c 0.3456067,0.344166 0.902092,0.344166 1.2418409,0 l 3.725523,-3.71 c 0.345607,-0.344167 0.345607,-0.8983337 0,-1.236667 l -7.0410041,-7.0116667 0,0 z M 9.6577406,13.360833 2.6167364,6.3491667 l 3.725523,-3.71 7.0410046,7.0116666 -3.7255234,3.7099997 0,0 z M 5.3757322,13.53 C 3.4602511,12.631667 2.0895398,10.776667 1.8786611,8.5833333 L 1,8.5833333 C 1.2987448,12.176667 4.3154812,15 8,15 L 8.3866109,14.9825 6.1548117,12.76 l -0.7790795,0.77 0,0 z" + id="rotate" + sketch:type="MSShapeGroup" /></g></g></svg> \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png index 798c3f2..f1e0e54 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png +++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs.png Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png index 95bea78b..7ab785f 100644 --- a/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png +++ b/third_party/WebKit/Source/devtools/front_end/Images/toolbarButtonGlyphs_2x.png Binary files differ
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js b/third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js index e4313a6..7683b93 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ClassesPaneWidget.js
@@ -187,6 +187,7 @@ { this._button = new WebInspector.ToolbarToggle(WebInspector.UIString("Element Classes"), ""); this._button.setText(".cls"); + this._button.element.classList.add("monospace"); this._button.addEventListener("click", this._clicked, this); this._view = new WebInspector.ClassesPaneWidget(this.item()); WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this._nodeChanged, this);
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementStatePaneWidget.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementStatePaneWidget.js index a291808..a7eb282 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ElementStatePaneWidget.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementStatePaneWidget.js
@@ -124,8 +124,9 @@ */ WebInspector.ElementStatePaneWidget.ButtonProvider = function() { - this._button = new WebInspector.ToolbarToggle(WebInspector.UIString("Toggle Element State"), "pin-toolbar-item"); + this._button = new WebInspector.ToolbarToggle(WebInspector.UIString("Toggle Element State"), "", WebInspector.UIString(":hov")); this._button.addEventListener("click", this._clicked, this); + this._button.element.classList.add("monospace"); this._view = new WebInspector.ElementStatePaneWidget(this.item()); WebInspector.context.addFlavorChangeListener(WebInspector.DOMNode, this._nodeChanged, this); this._nodeChanged();
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js index 99d9e78..6b1ece1 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js +++ b/third_party/WebKit/Source/devtools/front_end/elements/ElementsPanel.js
@@ -112,7 +112,7 @@ var filterInput = WebInspector.StylesSidebarPane.createPropertyFilterElement(WebInspector.UIString("Filter"), hbox, ssp.onFilterChanged.bind(ssp)); filterContainerElement.appendChild(filterInput); var toolbar = new WebInspector.ExtensibleToolbar("styles-sidebarpane-toolbar", hbox); - toolbar.appendToolbarItem(WebInspector.StylesSidebarPane.createAddNewRuleButton(ssp)); + toolbar.onLoad().then(() => toolbar.appendToolbarItem(WebInspector.StylesSidebarPane.createAddNewRuleButton(ssp))); toolbar.element.classList.add("styles-pane-toolbar"); toolbar.makeToggledGray(); var toolbarPaneContainer = container.createChild("div", "styles-sidebar-toolbar-pane-container"); @@ -939,6 +939,7 @@ } this._splitWidget.setVertical(!horizontally); + this.showToolbarPane(null); var computedPane = new WebInspector.SidebarPane(WebInspector.UIString("Computed")); computedPane.element.classList.add("composite");
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 1c8c6029..ca1ca3d 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css +++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsPanel.css
@@ -423,7 +423,7 @@ .styles-element-state-pane { overflow: hidden; - height: 60px; + height: 66px; padding-left: 2px; border-bottom: 1px solid rgb(189, 189, 189); } @@ -467,7 +467,7 @@ .styles-element-classes-pane { background-color: #f3f3f3; border-bottom: 1px solid rgb(189, 189, 189); - padding: 2px 4px; + padding: 6px 2px 2px; } .styles-element-classes-container { @@ -486,12 +486,14 @@ .styles-element-classes-pane .new-class-input { padding-left: 3px; - width: 100%; border: 1px solid #ddd; + line-height: 15px; + margin-left: 3px; + width: calc(100% - 7px); } .styles-element-state-pane > div { - margin: 6px 4px 2px; + margin: 8px 4px 6px; } .styles-element-state-pane > table {
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css index e4309b3..b515992 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css +++ b/third_party/WebKit/Source/devtools/front_end/elements/elementsTreeOutline.css
@@ -25,6 +25,16 @@ margin-left: -13px; } +.elements-disclosure li.selected:after { + font-style: italic; + content: " == $0"; + color: #555; +} + +.elements-disclosure ol:focus li.selected:after { + color: white; +} + .elements-disclosure li.parent::before { box-sizing: border-box; }
diff --git a/third_party/WebKit/Source/devtools/front_end/elements/module.json b/third_party/WebKit/Source/devtools/front_end/elements/module.json index fdebcfe0..565d0bf 100644 --- a/third_party/WebKit/Source/devtools/front_end/elements/module.json +++ b/third_party/WebKit/Source/devtools/front_end/elements/module.json
@@ -75,14 +75,14 @@ }, { "type": "@WebInspector.ToolbarItem.Provider", - "className": "WebInspector.ClassesPaneWidget.ButtonProvider", + "className": "WebInspector.ElementStatePaneWidget.ButtonProvider", "order": 1, "location": "styles-sidebarpane-toolbar" }, { "type": "@WebInspector.ToolbarItem.Provider", - "className": "WebInspector.ElementStatePaneWidget.ButtonProvider", - "order": 1, + "className": "WebInspector.ClassesPaneWidget.ButtonProvider", + "order": 2, "location": "styles-sidebarpane-toolbar" }, {
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js index 2911c50f..c7a5096 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js +++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeModel.js
@@ -428,6 +428,17 @@ }, /** + * @param {number} width + * @param {number} height + */ + setSizeAndScaleToFit: function(width, height) + { + var scale = Math.min(width ? this._preferredSize.width / width: 1, height ? this._preferredSize.height / height : 1); + this._scaleSetting.set(scale); + this.setWidth(width); + }, + + /** * @param {string} userAgent */ _applyUserAgent: function(userAgent)
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js index 4b4e3ee7..66884aa 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js +++ b/third_party/WebKit/Source/devtools/front_end/emulation/DeviceModeView.js
@@ -37,6 +37,8 @@ this.contentElement.appendChild(this._toolbar.element()); this._contentClip = this.contentElement.createChild("div", "device-mode-content-clip vbox"); + this._responsivePresetsContainer = this._contentClip.createChild("div", "device-mode-presets-container"); + this._populatePresetsContainer(); this._mediaInspectorContainer = this._contentClip.createChild("div", "device-mode-media-container"); this._contentArea = this._contentClip.createChild("div", "device-mode-content-area"); @@ -63,6 +65,40 @@ this._pageArea.createChild("content"); }, + _populatePresetsContainer: function() + { + var sizes = [320, 375, 425, 768, 1024, 1440, 2560]; + var titles = [WebInspector.UIString("Mobile S"), + WebInspector.UIString("Mobile M"), + WebInspector.UIString("Mobile L"), + WebInspector.UIString("Tablet"), + WebInspector.UIString("Laptop"), + WebInspector.UIString("Laptop L"), + WebInspector.UIString("4K")] + this._presetBlocks = []; + var inner = this._responsivePresetsContainer.createChild("div", "device-mode-presets-container-inner") + for (var i = sizes.length - 1; i >= 0; --i) { + var outer = inner.createChild("div", "fill device-mode-preset-bar-outer"); + var block = outer.createChild("div", "device-mode-preset-bar"); + block.createChild("span").textContent = titles[i] + " \u2013 " + sizes[i] + "px"; + block.addEventListener("click", applySize.bind(this, sizes[i]), false); + block.__width = sizes[i]; + this._presetBlocks.push(block); + } + + /** + * @param {number} width + * @param {!Event} e + * @this {WebInspector.DeviceModeView} + */ + function applySize(width, e) + { + this._model.emulate(WebInspector.DeviceModeModel.Type.Responsive, null, null); + this._model.setSizeAndScaleToFit(width, 0); + e.consume(); + } + }, + toggleDeviceMode: function() { this._toolbar.toggleDeviceMode(); @@ -204,6 +240,8 @@ if (this._model.scale() !== this._cachedScale) { updateRulers = true; + for (var block of this._presetBlocks) + block.style.width = block.__width * this._model.scale() + "px"; this._cachedScale = this._model.scale(); } @@ -218,6 +256,14 @@ } if (contentAreaResized) this._contentAreaResized(); + + if (this._model.type() !== this._cachedModelType) { + this._cachedModelType = this._model.type(); + this._contentArea.classList.toggle("device-mode-type-none", this._cachedModelType === WebInspector.DeviceModeModel.Type.None); + this._contentArea.classList.toggle("device-mode-type-responsive", this._cachedModelType === WebInspector.DeviceModeModel.Type.Responsive); + this._contentArea.classList.toggle("device-mode-type-device", this._cachedModelType === WebInspector.DeviceModeModel.Type.Device); + this._responsivePresetsContainer.classList.toggle("hidden", this._cachedModelType === WebInspector.DeviceModeModel.Type.None); + } }, /** @@ -303,7 +349,7 @@ this._lastMode = new Map(); /** @type {?WebInspector.EmulatedDevice} */ this._lastDevice = null; - /** @type {!Array<!WebInspector.ToolbarLabel>} */ + /** @type {!Array<!WebInspector.ToolbarButton>} */ this._appliedSizeItems = []; /** @type {!Array<!WebInspector.ToolbarMenuButton>} */ this._scaleItems = []; @@ -334,11 +380,11 @@ rightContainer.createChild("div", "device-mode-toolbar-spacer"); var rightToolbar = new WebInspector.Toolbar("", rightContainer); rightToolbar.makeWrappable(true); - this._uaItem = new WebInspector.ToolbarLabel(); + this._uaItem = new WebInspector.ToolbarText(); this._uaItem.setVisible(false); this._uaItem.setTitle(WebInspector.UIString("User agent type")); rightToolbar.appendToolbarItem(this._uaItem); - this._deviceScaleItem = new WebInspector.ToolbarLabel(); + this._deviceScaleItem = new WebInspector.ToolbarText(); this._deviceScaleItem.setVisible(false); this._deviceScaleItem.setTitle(WebInspector.UIString("Device pixel ratio")); rightToolbar.appendToolbarItem(this._deviceScaleItem); @@ -516,7 +562,7 @@ */ _appendAppliedSizeItems: function(toolbar) { - var item = new WebInspector.ToolbarLabel(); + var item = new WebInspector.ToolbarText(""); this._appliedSizeItems.push(item); toolbar.appendToolbarItem(item); }, @@ -529,8 +575,6 @@ var scaleItem = new WebInspector.ToolbarMenuButton(this._appendScaleMenuItems.bind(this)); scaleItem.setTitle(WebInspector.UIString("Zoom")); scaleItem.setGlyph(""); - scaleItem.setBold(false); - scaleItem.setDimmed(true); scaleItem.addDropDownArrow(); toolbar.appendToolbarItem(scaleItem); this._scaleItems.push(scaleItem); @@ -875,28 +919,23 @@ } if (this._model.scale() !== this._cachedScale) { - for (var item of this._scaleItems) + for (var item of this._scaleItems) { item.setText(WebInspector.UIString("%.0f%%", this._model.scale() * 100)); + item.setState(this._model.scale() === 1 ? "off" : "on"); + } this._cachedScale = this._model.scale(); } - var offscreen = this._model.screenRect().width > this._model.visiblePageRect().width || this._model.screenRect().height > this._model.visiblePageRect().height; - if (offscreen !== this._cachedOffscreen) { - for (var item of this._scaleItems) - item.setDimmed(!offscreen); - this._cachedOffscreen = offscreen; - } - var deviceScale = this._model.deviceScaleFactorSetting().get(); + this._deviceScaleItem.setVisible(this._model.type() === WebInspector.DeviceModeModel.Type.Responsive && !!deviceScale); if (deviceScale !== this._cachedDeviceScale) { - this._deviceScaleItem.setVisible(!!deviceScale); this._deviceScaleItem.setText(WebInspector.UIString("DPR: %.1f", deviceScale)); this._cachedDeviceScale = deviceScale; } var uaType = this._model.type() === WebInspector.DeviceModeModel.Type.Responsive ? this._model.uaSetting().get() : WebInspector.DeviceModeModel.UA.Mobile; + this._uaItem.setVisible(this._model.type() === WebInspector.DeviceModeModel.Type.Responsive && uaType !== WebInspector.DeviceModeModel.UA.Mobile); if (uaType !== this._cachedUaType) { - this._uaItem.setVisible(uaType !== WebInspector.DeviceModeModel.UA.Mobile); this._uaItem.setText(uaType === WebInspector.DeviceModeModel.UA.Desktop ? WebInspector.UIString("Desktop") : WebInspector.UIString("Touch")); this._cachedUaType = uaType; }
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeToolbar.css b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeToolbar.css index a9de7ee..72fb661 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeToolbar.css +++ b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeToolbar.css
@@ -11,6 +11,13 @@ width: 39px !important; margin: 0 3px; text-align: center; + box-shadow: 0px 0px 1px 0px hsla(0, 0%, 0%, 0.13); + border-radius: 1px; + height: 18px; +} + +.device-mode-size-input:focus::-webkit-input-placeholder { + color: transparent; } .device-mode-size-input.error-input {
diff --git a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css index da0afe2..a57a5f5 100644 --- a/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css +++ b/third_party/WebKit/Source/devtools/front_end/emulation/deviceModeView.css
@@ -8,12 +8,12 @@ overflow: hidden; align-items: stretch; flex: auto; - background-color: #fcfcfc; + background-color: hsl(0, 0%, 98%); } .device-mode-toolbar { flex: none; - background-color: #f3f3f3; + background-color: hsl(0, 0%, 98%); border-bottom: 1px solid #ccc; display: flex; flex-direction: row; @@ -68,12 +68,70 @@ box-shadow: inset 0 -1px #ccc; } +.device-mode-presets-container { + flex: 0 0 20px; + display: flex; +} + +.device-mode-presets-container-inner { + flex: auto; + background-color: red; + justify-content: center; + position: relative; + background-color: hsl(0, 0%, 90%); ++} + +.device-mode-presets-container:hover { + transition: opacity 0.1s; + transition-delay: 50ms; + opacity: 1; +} + +.device-mode-preset-bar-outer { + pointer-events: none; + display: flex; + justify-content: center; +} + +.device-mode-preset-bar { + border: 2px solid hsl(0, 0%, 98%); + pointer-events: auto; + text-align: center; + flex: none; + cursor: pointer; + color: #333; + display: flex; + align-items: center; + justify-content: center; + white-space: nowrap; +} + +.device-mode-preset-bar:hover { + transition: background-color 0.1s; + transition-delay: 50ms; + background-color: #d6d6d6; +} + +.device-mode-preset-bar > span { + visibility: hidden; +} + +.device-mode-preset-bar:hover > span { + transition: visibility 0.1s; + transition-delay: 50ms; + visibility: visible; +} + .device-mode-content-area { flex: auto; position: relative; margin: 0; } +.device-mode-content-area:not(.device-mode-type-none):not(.device-mode-rulers-visible) { + margin-top: 20px; +} + .device-mode-screen-area { position: absolute; left: 0;
diff --git a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js index 7b562574..35ab5da1 100644 --- a/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js +++ b/third_party/WebKit/Source/devtools/front_end/profiler/HeapSnapshotView.js
@@ -149,7 +149,7 @@ this._constructorsDataGrid.setNameFilter(this._classNameFilter); this._diffDataGrid.setNameFilter(this._classNameFilter); - this._selectedSizeText = new WebInspector.ToolbarLabel(); + this._selectedSizeText = new WebInspector.ToolbarText(); this._popoverHelper = new WebInspector.ObjectPopoverHelper(this.element, this._getHoverAnchor.bind(this), this._resolveObjectForPopover.bind(this), undefined, true);
diff --git a/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js b/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js index 880d9a0f..9659f09 100644 --- a/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js +++ b/third_party/WebKit/Source/devtools/front_end/sdk/ConsoleModel.js
@@ -125,7 +125,7 @@ return false; // ignore Chromecast's cast_sender spam - if (msg.url.includes("://boadgeojelhgndaghljhdicfkmllpafd") || msg.url.includes("://dliochdbjfkdbacpmhlcpmleaejidimm") || msg.url.includes("://pkedcjkdefgpdelpbcmbmeomcjbeemfm") || msg.url.includes("://ekpaaapppgpmolpcldedioblbkmijaca")) + if (msg.url.includes("://boadgeojelhgndaghljhdicfkmllpafd") || msg.url.includes("://dliochdbjfkdbacpmhlcpmleaejidimm") || msg.url.includes("://pkedcjkdefgpdelpbcmbmeomcjbeemfm") || msg.url.includes("://fjhoaacokmgbjemoflkofnenfaiekifl") || msg.url.includes("://ekpaaapppgpmolpcldedioblbkmijaca")) return true; return false;
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js b/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js index 07d34fe..77f2c7f 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/FontView.js
@@ -40,7 +40,7 @@ this._url = contentProvider.contentURL(); this._mimeType = mimeType; this._contentProvider = contentProvider; - this._mimeTypeLabel = new WebInspector.ToolbarLabel(mimeType); + this._mimeTypeLabel = new WebInspector.ToolbarText(mimeType); } WebInspector.FontView._fontPreviewLines = [ "ABCDEFGHIJKLM", "NOPQRSTUVWXYZ", "abcdefghijklm", "nopqrstuvwxyz", "1234567890" ];
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js b/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js index 04542bc1..a07ef54e 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/ImageView.js
@@ -41,9 +41,9 @@ this._parsedURL = new WebInspector.ParsedURL(this._url); this._mimeType = mimeType; this._contentProvider = contentProvider; - this._sizeLabel = new WebInspector.ToolbarLabel(); - this._dimensionsLabel = new WebInspector.ToolbarLabel(); - this._mimeTypeLabel = new WebInspector.ToolbarLabel(mimeType); + this._sizeLabel = new WebInspector.ToolbarText(); + this._dimensionsLabel = new WebInspector.ToolbarText(); + this._mimeTypeLabel = new WebInspector.ToolbarText(mimeType); } WebInspector.ImageView.prototype = {
diff --git a/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js b/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js index 23dde482..462e2ec2 100644 --- a/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js +++ b/third_party/WebKit/Source/devtools/front_end/source_frame/SourceFrame.js
@@ -53,7 +53,7 @@ this._shortcuts = {}; this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false); - this._sourcePosition = new WebInspector.ToolbarLabel(); + this._sourcePosition = new WebInspector.ToolbarText(); } WebInspector.SourceFrame.Events = {
diff --git a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js index 4651c17..355d5ba 100644 --- a/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js +++ b/third_party/WebKit/Source/devtools/front_end/sources/JavaScriptSourceFrame.js
@@ -91,7 +91,7 @@ if (originURL) { var parsedURL = originURL.asParsedURL(); if (parsedURL) - result.push(new WebInspector.ToolbarLabel(WebInspector.UIString("(source mapped from %s)", parsedURL.displayName))); + result.push(new WebInspector.ToolbarText(WebInspector.UIString("(source mapped from %s)", parsedURL.displayName))); } return result; },
diff --git a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js index 15700fb9..4914bb5 100644 --- a/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js +++ b/third_party/WebKit/Source/devtools/front_end/timeline/TimelineTreeView.js
@@ -1113,7 +1113,7 @@ header.textContent = WebInspector.UIString("Heaviest stack"); this._treeView = treeView; var columns = [ - {id: "total", title: WebInspector.UIString("Total Time"), width: "80px"}, + {id: "total", title: WebInspector.UIString("Total Time"), width: "110px"}, {id: "activity", title: WebInspector.UIString("Activity")} ]; this._dataGrid = new WebInspector.ViewportDataGrid(columns);
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js index 0280446..7175fe9 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js +++ b/third_party/WebKit/Source/devtools/front_end/ui/Toolbar.js
@@ -106,7 +106,7 @@ */ appendText: function(text) { - this.appendToolbarItem(new WebInspector.ToolbarLabel(text)); + this.appendToolbarItem(new WebInspector.ToolbarText(text)); }, removeToolbarItems: function() @@ -182,6 +182,17 @@ } WebInspector.ToolbarItem.prototype = { + /** + * @param {string} title + */ + setTitle: function(title) + { + if (this._title === title) + return; + this._title = title; + WebInspector.Tooltip.install(this.element, title); + }, + _mouseEnter: function() { this.element.classList.add("hover"); @@ -236,21 +247,52 @@ * @constructor * @extends {WebInspector.ToolbarItem} * @param {string=} text - * @param {string=} glyph */ -WebInspector.ToolbarLabel = function(text, glyph) +WebInspector.ToolbarText = function(text) { - WebInspector.ToolbarItem.call(this, createElementWithClass("button", "toolbar-text-glyph")); + WebInspector.ToolbarItem.call(this, createElementWithClass("div", "toolbar-text")); + this.element.classList.add("toolbar-text"); + this.setText(text || ""); +} + +WebInspector.ToolbarText.prototype = { + /** + * @param {string} text + */ + setText: function(text) + { + this.element.textContent = text; + }, + + __proto__: WebInspector.ToolbarItem.prototype +} + +/** + * @constructor + * @extends {WebInspector.ToolbarItem} + * @param {string} title + * @param {string=} glyph + * @param {string=} text + */ +WebInspector.ToolbarButton = function(title, glyph, text) +{ + WebInspector.ToolbarItem.call(this, createElementWithClass("button", "toolbar-button")); + this.element.addEventListener("click", this._clicked.bind(this), false); + this.element.addEventListener("mousedown", this._mouseDown.bind(this), false); + this.element.addEventListener("mouseup", this._mouseUp.bind(this), false); + this._glyphElement = this.element.createChild("div", "toolbar-glyph hidden"); this._textElement = this.element.createChild("div", "toolbar-text hidden"); - this.setText(text || ""); + + this.setTitle(title); if (glyph) this.setGlyph(glyph); + this.setText(text || ""); this._state = ""; this._title = ""; } -WebInspector.ToolbarLabel.prototype = { +WebInspector.ToolbarButton.prototype = { /** * @param {string} text */ @@ -308,25 +350,6 @@ }, /** - * @param {string} title - */ - setTitle: function(title) - { - if (this._title === title) - return; - this._title = title; - WebInspector.Tooltip.install(this.element, title); - }, - - /** - * @param {boolean} bold - */ - setBold: function(bold) - { - this.element.classList.toggle("toolbar-bold", bold); - }, - - /** * @param {boolean} dimmed */ setDimmed: function(dimmed) @@ -340,28 +363,6 @@ this.element.createChild("div", "toolbar-dropdown-arrow"); }, - __proto__: WebInspector.ToolbarItem.prototype -} - -/** - * @constructor - * @extends {WebInspector.ToolbarLabel} - * @param {string} title - * @param {string} glyph - */ -WebInspector.ToolbarButton = function(title, glyph) -{ - WebInspector.ToolbarLabel.call(this); - this.element.classList.add("toolbar-button"); - this.element.addEventListener("click", this._clicked.bind(this), false); - this.element.addEventListener("mousedown", this._mouseDown.bind(this), false); - this.element.addEventListener("mouseup", this._mouseUp.bind(this), false); - this.setBold(true); - this.setTitle(title); - this.setGlyph(glyph); -} - -WebInspector.ToolbarButton.prototype = { /** * @param {!Event} event */ @@ -387,7 +388,7 @@ this.dispatchEventToListeners("mouseup", event); }, - __proto__: WebInspector.ToolbarLabel.prototype + __proto__: WebInspector.ToolbarItem.prototype } /** @@ -440,10 +441,13 @@ /** * @constructor * @extends {WebInspector.ToolbarButton} + * @param {string} title + * @param {string=} glyph + * @param {string=} text */ -WebInspector.ToolbarToggle = function(title, glyph) +WebInspector.ToolbarToggle = function(title, glyph, text) { - WebInspector.ToolbarButton.call(this, title, glyph); + WebInspector.ToolbarButton.call(this, title, glyph, text); this._toggled = false; this.setState("off"); } @@ -903,7 +907,7 @@ if (extensions[i].descriptor()["location"] === location) promises.push(resolveItem(extensions[i])); } - Promise.all(promises).then(appendItemsInOrder.bind(this)); + this._promise = Promise.all(promises).then(appendItemsInOrder.bind(this)); /** * @param {!Runtime.Extension} extension @@ -941,5 +945,13 @@ } }, + /** + * @return {!Promise} + */ + onLoad: function() + { + return this._promise; + }, + __proto__: WebInspector.Toolbar.prototype } \ No newline at end of file
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/infobar.css b/third_party/WebKit/Source/devtools/front_end/ui/infobar.css index c3ab2d7f..bc1992f9 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/infobar.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/infobar.css
@@ -47,14 +47,14 @@ } .infobar-details-rows { - padding-top: 5px; + padding: 5px 5px 0 5px; } .infobar-details-row { display: flex; flex-direction: column; line-height: 18px; - padding: 5px 6px 6px 6px; + padding-bottom: 6px; } .close-button { @@ -85,5 +85,5 @@ .icon { -webkit-mask-size: 18px 18px; width: 18px; - height: 18px; + height: 19px; }
diff --git a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css index ad85935..f452d71c 100644 --- a/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css +++ b/third_party/WebKit/Source/devtools/front_end/ui/toolbar.css
@@ -51,7 +51,7 @@ -webkit-mask-image: url(Images/toolbarButtonGlyphs.png); -webkit-mask-size: 352px 168px; -webkit-mask-position: -18px -96px; - background-color: #444; + background-color: #6D6D6D; width: 12px; height: 12px; display: inline-block; @@ -65,9 +65,9 @@ } } /* media */ -/* Text-glyph item */ +/* Toolbar item */ -.toolbar-text-glyph { +.toolbar-button { white-space: nowrap; overflow: hidden; min-width: 28px; @@ -88,10 +88,14 @@ margin-left: 0; } -.toolbar-bold .toolbar-text { +.toolbar-button:not(.toolbar-has-glyph):not(.toolbar-has-dropdown):not(.menu-toolbar-item) { font-weight: bold; } +.toolbar-button:not(.toolbar-has-glyph).hover { + background-color: #f3f3f3; +} + .toolbar-dimmed .toolbar-text { color: #999; } @@ -422,7 +426,7 @@ } .phone-toolbar-item.toolbar-glyph { - -webkit-mask-position: -288px -144px; + -webkit-mask-position: -320px -96px; } .rotate-screen-toolbar-item.toolbar-glyph {
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.cpp b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.cpp index ed091b8..862d9031 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.cpp +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.cpp
@@ -29,6 +29,13 @@ return new BluetoothGATTRemoteServer(webGATT); } +void BluetoothGATTRemoteServer::disconnect(ScriptState* scriptState) +{ + m_webGATT->connected = false; + WebBluetooth* webbluetooth = BluetoothSupplement::fromScriptState(scriptState); + webbluetooth->disconnect(m_webGATT->deviceId); +} + ScriptPromise BluetoothGATTRemoteServer::getPrimaryService(ScriptState* scriptState, const StringOrUnsignedLong& service, ExceptionState& exceptionState) { WebBluetooth* webbluetooth = BluetoothSupplement::fromScriptState(scriptState); @@ -39,7 +46,7 @@ ScriptPromiseResolver* resolver = ScriptPromiseResolver::create(scriptState); ScriptPromise promise = resolver->promise(); - webbluetooth->getPrimaryService(m_webGATT->deviceInstanceID, serviceUUID, new CallbackPromiseAdapter<BluetoothGATTService, BluetoothError>(resolver)); + webbluetooth->getPrimaryService(m_webGATT->deviceId, serviceUUID, new CallbackPromiseAdapter<BluetoothGATTService, BluetoothError>(resolver)); return promise; }
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.h b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.h index 6c1f74c5..5cad459 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.h +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.h
@@ -41,6 +41,7 @@ // IDL exposed interface: bool connected() { return m_webGATT->connected; } + void disconnect(ScriptState*); ScriptPromise getPrimaryService(ScriptState*, const StringOrUnsignedLong& service, ExceptionState&); private:
diff --git a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.idl b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.idl index 9f94604..9c878fdb 100644 --- a/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.idl +++ b/third_party/WebKit/Source/modules/bluetooth/BluetoothGATTRemoteServer.idl
@@ -15,7 +15,7 @@ { // readonly attribute BluetoothDevice device; readonly attribute boolean connected; - // void disconnect (); + [CallWith=ScriptState] void disconnect (); [CallWith=ScriptState, RaisesException] Promise<BluetoothGATTService> getPrimaryService (BluetoothServiceUUID service); // Promise<sequence<BluetoothGATTService>> getPrimaryServices (optional BluetoothServiceUUID service); };
diff --git a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp index 2c04714..641a599 100644 --- a/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp +++ b/third_party/WebKit/Source/modules/webgl/WebGLRenderingContextBase.cpp
@@ -672,6 +672,7 @@ GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT32F, GL_DEPTH24_STENCIL8, + GL_DEPTH32F_STENCIL8, }; // ES2 enums @@ -747,6 +748,7 @@ GL_UNSIGNED_INT_10F_11F_11F_REV, GL_UNSIGNED_INT_5_9_9_9_REV, GL_UNSIGNED_INT_24_8, + GL_FLOAT_32_UNSIGNED_INT_24_8_REV, }; // ES2 enums @@ -860,6 +862,7 @@ { GL_DEPTH_COMPONENT24, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT }, { GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT }, { GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8 }, + { GL_DEPTH32F_STENCIL8, GL_DEPTH_STENCIL, GL_FLOAT_32_UNSIGNED_INT_24_8_REV }, }; bool isUnsignedIntegerFormat(GLenum internalformat) @@ -5906,6 +5909,9 @@ return false; } break; + case GL_FLOAT_32_UNSIGNED_INT_24_8_REV: + synthesizeGLError(GL_INVALID_OPERATION, functionName, "type FLOAT_32_UNSIGNED_INT_24_8_REV but ArrayBufferView is not NULL"); + return false; default: ASSERT_NOT_REACHED(); }
diff --git a/third_party/WebKit/Source/platform/BUILD.gn b/third_party/WebKit/Source/platform/BUILD.gn index b3ee24c..7b85d693 100644 --- a/third_party/WebKit/Source/platform/BUILD.gn +++ b/third_party/WebKit/Source/platform/BUILD.gn
@@ -204,6 +204,7 @@ "//third_party/WebKit/Source/platform/heap", "//third_party/harfbuzz-ng", "//third_party/icu", + "//ui/gfx", "//ui/gfx/geometry", ]
diff --git a/third_party/WebKit/Source/platform/DEPS b/third_party/WebKit/Source/platform/DEPS index df608cc..08bfc6f 100644 --- a/third_party/WebKit/Source/platform/DEPS +++ b/third_party/WebKit/Source/platform/DEPS
@@ -12,7 +12,7 @@ "+skia/ext", "+third_party/khronos", "+third_party/skia", - "+ui/gfx/geometry", + "+ui/gfx", "+url", "+webp", "-bindings",
diff --git a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in index 9f8148d..99b9416 100644 --- a/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in +++ b/third_party/WebKit/Source/platform/RuntimeEnabledFeatures.in
@@ -194,7 +194,6 @@ // Chromium sets this conditionally (eg. based on the presence of a // touchscreen) in ApplyWebPreferences. Touch status=stable -TouchIconLoading TrustedEvents status=stable TrustedEventsDefaultAction UnsafeES3APIs
diff --git a/third_party/WebKit/Source/platform/blink_platform.gyp b/third_party/WebKit/Source/platform/blink_platform.gyp index f0b31814..3985ea4 100644 --- a/third_party/WebKit/Source/platform/blink_platform.gyp +++ b/third_party/WebKit/Source/platform/blink_platform.gyp
@@ -136,6 +136,7 @@ '<(DEPTH)/third_party/libwebp/libwebp.gyp:libwebp', '<(DEPTH)/third_party/ots/ots.gyp:ots', '<(DEPTH)/third_party/qcms/qcms.gyp:qcms', + '<(DEPTH)/ui/gfx/gfx.gyp:gfx', '<(DEPTH)/ui/gfx/gfx.gyp:gfx_geometry', '<(DEPTH)/url/url.gyp:url_lib', '<(DEPTH)/v8/tools/gyp/v8.gyp:v8',
diff --git a/third_party/WebKit/Source/platform/fonts/Font.cpp b/third_party/WebKit/Source/platform/fonts/Font.cpp index 1715079..4028270 100644 --- a/third_party/WebKit/Source/platform/fonts/Font.cpp +++ b/third_party/WebKit/Source/platform/fonts/Font.cpp
@@ -409,10 +409,14 @@ CodePath Font::codePath(const TextRunPaintInfo& runInfo) const { +// TODO(eae): Disable the always use complex text feature on Android for now as +// it caused a memory regression for webview. crbug.com/577306 +#if !OS(ANDROID) if (RuntimeEnabledFeatures::alwaysUseComplexTextEnabled() || LayoutTestSupport::alwaysUseComplexTextForTest()) { return ComplexPath; } +#endif const TextRun& run = runInfo.run;
diff --git a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h index f3d1750..1e778a5 100644 --- a/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h +++ b/third_party/WebKit/Source/platform/fonts/shaping/ShapeCache.h
@@ -228,15 +228,8 @@ // unique words [1]. 1: http://www.mine-control.com/zack/guttenberg/ // Our definition of a word is somewhat different from the norm in that we // only segment on space. Thus "foo", "foo-", and "foo)" would count as - // three separate words. Given that 10,000 seems like a reasonable maximum - // for desktop. -#if !OS(ANDROID) + // three separate words. Given that 10,000 seems like a reasonable maximum. static const unsigned s_maxSize = 10000; -#else - // On Android, we use a more conservative value of 2,500 due to memory - // constraints. crbug.com/577306 - static const unsigned s_maxSize = 2500; -#endif SingleCharMap m_singleCharMap; SmallStringMap m_shortStringMap;
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp index 1f51612..c9a9515f 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp +++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -1213,6 +1213,12 @@ m_scrollableArea->notifyCompositorAnimationFinished(group); } +void GraphicsLayer::notifyAnimationAborted(double, int group) +{ + if (m_scrollableArea) + m_scrollableArea->notifyCompositorAnimationAborted(group); +} + void GraphicsLayer::didScroll() { if (m_scrollableArea) {
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h index be04751..b30629e 100644 --- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h +++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.h
@@ -245,6 +245,7 @@ // WebCompositorAnimationDelegate implementation. void notifyAnimationStarted(double monotonicTime, int group) override; void notifyAnimationFinished(double monotonicTime, int group) override; + void notifyAnimationAborted(double monotonicTime, int group) override; // WebLayerScrollClient implementation. void didScroll() override;
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp index 0bce706..a78ac79 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.cpp
@@ -4,16 +4,54 @@ #include "platform/graphics/compositing/PaintArtifactCompositor.h" +#include "cc/layers/content_layer_client.h" #include "cc/layers/layer.h" #include "cc/layers/layer_settings.h" +#include "cc/layers/picture_layer.h" +#include "cc/playback/display_item_list.h" +#include "cc/playback/display_item_list_settings.h" +#include "cc/playback/drawing_display_item.h" #include "platform/RuntimeEnabledFeatures.h" +#include "platform/graphics/paint/DisplayItem.h" +#include "platform/graphics/paint/DrawingDisplayItem.h" +#include "platform/graphics/paint/PaintArtifact.h" #include "public/platform/Platform.h" #include "public/platform/WebCompositorSupport.h" #include "public/platform/WebLayer.h" +#include "skia/ext/refptr.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/skia_util.h" +#include "wtf/Allocator.h" +#include "wtf/Noncopyable.h" #include "wtf/PassOwnPtr.h" namespace blink { +class PaintArtifactCompositor::ContentLayerClientImpl : public cc::ContentLayerClient { + WTF_MAKE_NONCOPYABLE(ContentLayerClientImpl); + USING_FAST_MALLOC(ContentLayerClientImpl); +public: + ContentLayerClientImpl(scoped_refptr<cc::DisplayItemList> list, const gfx::Rect& paintableRegion) + : m_ccDisplayItemList(std::move(list)), m_paintableRegion(paintableRegion) { } + + // cc::ContentLayerClient + gfx::Rect PaintableRegion() override { return m_paintableRegion; } + scoped_refptr<cc::DisplayItemList> PaintContentsToDisplayList(PaintingControlSetting) override + { + return m_ccDisplayItemList; + } + bool FillsBoundsCompletely() const override { return false; } + size_t GetApproximateUnsharedMemoryUsage() const override + { + // TODO(jbroman): Actually calculate memory usage. + return 0; + } + +private: + scoped_refptr<cc::DisplayItemList> m_ccDisplayItemList; + gfx::Rect m_paintableRegion; +}; + PaintArtifactCompositor::PaintArtifactCompositor() { } @@ -32,10 +70,56 @@ m_webLayer = adoptPtr(Platform::current()->compositorSupport()->createLayerFromCCLayer(m_rootLayer.get())); } +static void appendDisplayItemToCcDisplayItemList(const DisplayItem& displayItem, cc::DisplayItemList* list, gfx::Rect& combinedBounds) +{ + if (DisplayItem::isDrawingType(displayItem.type())) { + const SkPicture* picture = static_cast<const DrawingDisplayItem&>(displayItem).picture(); + if (!picture) + return; + gfx::Rect bounds = gfx::SkIRectToRect(picture->cullRect().roundOut()); + list->CreateAndAppendItem<cc::DrawingDisplayItem>(bounds, skia::SharePtr(picture)); + combinedBounds.Union(bounds); + } +} + +static scoped_refptr<cc::DisplayItemList> recordPaintChunk(const PaintArtifact& artifact, const PaintChunk& chunk, gfx::Rect& combinedBounds) +{ + cc::DisplayItemListSettings settings; + scoped_refptr<cc::DisplayItemList> list = cc::DisplayItemList::Create(gfx::Rect(), settings); + + const DisplayItemList& displayItems = artifact.displayItemList(); + for (size_t i = chunk.beginIndex; i < chunk.endIndex; i++) + appendDisplayItemToCcDisplayItemList(displayItems[i], list.get(), combinedBounds); + + list->Finalize(); + return list; +} + void PaintArtifactCompositor::update(const PaintArtifact& paintArtifact) { - initializeIfNeeded(); ASSERT(m_rootLayer); + + // TODO(jbroman): This should be incremental. + m_rootLayer->RemoveAllChildren(); + m_contentLayerClients.clear(); + + m_contentLayerClients.reserveCapacity(paintArtifact.paintChunks().size()); + for (const PaintChunk& paintChunk : paintArtifact.paintChunks()) { + // TODO(jbroman): This only really works well for chunks without an + // offset. That really needs to be fixed. + gfx::Rect combinedBounds; + scoped_refptr<cc::DisplayItemList> displayList = recordPaintChunk(paintArtifact, paintChunk, combinedBounds); + OwnPtr<ContentLayerClientImpl> contentLayerClient = adoptPtr( + new ContentLayerClientImpl(std::move(displayList), combinedBounds)); + scoped_refptr<cc::PictureLayer> layer = cc::PictureLayer::Create(cc::LayerSettings(), contentLayerClient.get()); + layer->SetPosition(gfx::PointF()); + layer->SetBounds(combinedBounds.size()); + // TODO(jbroman): Layer transforms would be nice. + layer->SetIsDrawable(true); + layer->SetNeedsDisplay(); + m_contentLayerClients.append(contentLayerClient.release()); + m_rootLayer->AddChild(std::move(layer)); + } } } // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h index 6f6f0018..bbcfd9c 100644 --- a/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h +++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintArtifactCompositor.h
@@ -9,6 +9,7 @@ #include "platform/PlatformExport.h" #include "wtf/Noncopyable.h" #include "wtf/OwnPtr.h" +#include "wtf/Vector.h" namespace cc { class Layer; @@ -49,8 +50,14 @@ WebLayer* webLayer() const { return m_webLayer.get(); } private: + class ContentLayerClientImpl; + scoped_refptr<cc::Layer> m_rootLayer; OwnPtr<WebLayer> m_webLayer; + Vector<OwnPtr<ContentLayerClientImpl>> m_contentLayerClients; + + // For ~PaintArtifactCompositor on MSVC. + friend struct WTF::OwnedPtrDeleter<ContentLayerClientImpl>; }; } // namespace blink
diff --git a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h index fa05677..e936b3c 100644 --- a/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h +++ b/third_party/WebKit/Source/platform/scroll/ProgrammaticScrollAnimator.h
@@ -39,6 +39,7 @@ void tickAnimation(double monotonicTime) override; void updateCompositorAnimations() override; void notifyCompositorAnimationFinished(int groupId) override; + void notifyCompositorAnimationAborted(int groupId) override { }; void layerForCompositedScrollingDidChange(WebCompositorAnimationTimeline*) override; DECLARE_TRACE();
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp index 6841836..df95d27 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.cpp
@@ -269,6 +269,13 @@ } } +void ScrollAnimator::notifyCompositorAnimationAborted(int groupId) +{ + // An animation aborted by the compositor is treated as a finished + // animation. + ScrollAnimatorCompositorCoordinator::compositorAnimationFinished(groupId); +} + void ScrollAnimator::notifyCompositorAnimationFinished(int groupId) { ScrollAnimatorCompositorCoordinator::compositorAnimationFinished(groupId);
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h index e8ac2ae..88465cad 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimator.h
@@ -60,6 +60,7 @@ void resetAnimationState() override; void updateCompositorAnimations() override; void notifyCompositorAnimationFinished(int groupId) override; + void notifyCompositorAnimationAborted(int groupId) override; void layerForCompositedScrollingDidChange(WebCompositorAnimationTimeline*) override; DECLARE_VIRTUAL_TRACE();
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h index 5926f86..bdbf1bbb 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorBase.h
@@ -83,6 +83,7 @@ void cancelAnimation() override { } void updateCompositorAnimations() override { }; void notifyCompositorAnimationFinished(int groupId) override { }; + void notifyCompositorAnimationAborted(int groupId) override { }; void layerForCompositedScrollingDidChange(WebCompositorAnimationTimeline*) override { }; virtual void contentAreaWillPaint() const { }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp index 4f0528f..142b27e 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.cpp
@@ -182,6 +182,14 @@ notifyCompositorAnimationFinished(group); } +void ScrollAnimatorCompositorCoordinator::notifyAnimationAborted( + double monotonicTime, int group) +{ + // An animation aborted by the compositor is treated as a finished + // animation. + notifyCompositorAnimationFinished(group); +} + WebCompositorAnimationPlayer* ScrollAnimatorCompositorCoordinator::compositorPlayer() const { return m_compositorPlayer.get();
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h index e0d41a8..f5f88233 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollAnimatorCompositorCoordinator.h
@@ -34,6 +34,7 @@ virtual void tickAnimation(double monotonicTime) = 0; virtual void updateCompositorAnimations() = 0; virtual void notifyCompositorAnimationFinished(int groupId) = 0; + virtual void notifyCompositorAnimationAborted(int groupId) = 0; virtual void layerForCompositedScrollingDidChange(WebCompositorAnimationTimeline*) = 0; DEFINE_INLINE_VIRTUAL_TRACE() { } @@ -51,6 +52,7 @@ // WebCompositorAnimationDelegate implementation. void notifyAnimationStarted(double monotonicTime, int group) override; void notifyAnimationFinished(double monotonicTime, int group) override; + void notifyAnimationAborted(double monotonicTime, int group) override; // WebCompositorAnimationPlayerClient implementation. WebCompositorAnimationPlayer* compositorPlayer() const override;
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp index 365aa95..1b86c47 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.cpp
@@ -501,6 +501,15 @@ scrollAnimator->notifyCompositorAnimationFinished(groupId); } +void ScrollableArea::notifyCompositorAnimationAborted(int groupId) +{ + if (ProgrammaticScrollAnimator* programmaticScrollAnimator = existingProgrammaticScrollAnimator()) + programmaticScrollAnimator->notifyCompositorAnimationAborted(groupId); + + if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator()) + scrollAnimator->notifyCompositorAnimationAborted(groupId); +} + void ScrollableArea::cancelScrollAnimation() { if (ScrollAnimatorBase* scrollAnimator = existingScrollAnimator())
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h index 50d99bf..70403aa 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableArea.h +++ b/third_party/WebKit/Source/platform/scroll/ScrollableArea.h
@@ -219,6 +219,7 @@ virtual void deregisterForAnimation() { } void notifyCompositorAnimationFinished(int groupId); + void notifyCompositorAnimationAborted(int groupId); virtual bool usesCompositedScrolling() const { return false; }
diff --git a/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp b/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp index b6ef90e..87f1f604 100644 --- a/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp +++ b/third_party/WebKit/Source/platform/scroll/ScrollableAreaTest.cpp
@@ -113,7 +113,7 @@ EXPECT_CALL(theme, shouldRepaintAllPartsOnInvalidation()).WillRepeatedly(Return(true)); EXPECT_TRUE(scrollbar->trackNeedsRepaint()); EXPECT_TRUE(scrollbar->thumbNeedsRepaint()); - scrollbar->setNeedsPaintInvalidation(); + scrollbar->setNeedsPaintInvalidation(NoPart); EXPECT_TRUE(scrollbar->trackNeedsRepaint()); EXPECT_TRUE(scrollbar->thumbNeedsRepaint()); @@ -121,7 +121,7 @@ scrollbar->clearThumbNeedsRepaint(); EXPECT_FALSE(scrollbar->trackNeedsRepaint()); EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); - scrollbar->setNeedsPaintInvalidation(); + scrollbar->setNeedsPaintInvalidation(NoPart); EXPECT_TRUE(scrollbar->trackNeedsRepaint()); EXPECT_TRUE(scrollbar->thumbNeedsRepaint()); @@ -130,7 +130,7 @@ scrollbar->clearThumbNeedsRepaint(); EXPECT_FALSE(scrollbar->trackNeedsRepaint()); EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); - scrollbar->setNeedsPaintInvalidation(); + scrollbar->setNeedsPaintInvalidation(NoPart); EXPECT_FALSE(scrollbar->trackNeedsRepaint()); EXPECT_FALSE(scrollbar->thumbNeedsRepaint()); @@ -164,7 +164,7 @@ RefPtrWillBeRawPtr<Scrollbar> scrollbar = Scrollbar::create(scrollableArea.get(), HorizontalScrollbar, RegularScrollbar, nullptr); graphicsLayer.resetTrackedPaintInvalidations(); - scrollbar->setNeedsPaintInvalidation(); + scrollbar->setNeedsPaintInvalidation(NoPart); EXPECT_TRUE(graphicsLayer.hasTrackedPaintInvalidations()); }
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp index 32f7306..dd67570f 100644 --- a/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp +++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.cpp
@@ -105,7 +105,7 @@ return; Widget::setFrameRect(frameRect); - setNeedsPaintInvalidation(); + setNeedsPaintInvalidation(AllParts); } ScrollbarOverlayStyle Scrollbar::scrollbarOverlayStyle() const @@ -141,7 +141,10 @@ int oldThumbPosition = theme().thumbPosition(*this); m_currentPos = position; - setNeedsPaintInvalidation(); + // TODO(jbroman): The theme should provide the parts to invalidate. + // At the moment, the only theme that doesn't invalidate everything is Mac, + // which invalidates this as needed in ScrollAnimatorMac. + setNeedsPaintInvalidation(NoPart); if (m_pressedPart == ThumbPart) setPressedPos(m_pressedPos + theme().thumbPosition(*this) - oldThumbPosition); } @@ -159,7 +162,7 @@ m_visibleSize = visibleSize; m_totalSize = totalSize; - setNeedsPaintInvalidation(); + setNeedsPaintInvalidation(AllParts); } void Scrollbar::paint(GraphicsContext& context, const CullRect& cullRect) const @@ -191,7 +194,6 @@ // Handle the track. if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse(*this)) { - setNeedsPaintInvalidation(); setHoveredPart(ThumbPart); return; } @@ -210,7 +212,6 @@ // Handle the track. We halt track scrolling once the thumb is level // with us. if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && thumbUnderMouse(*this)) { - setNeedsPaintInvalidation(); setHoveredPart(ThumbPart); return; } @@ -307,7 +308,7 @@ if (((m_hoveredPart == NoPart || part == NoPart) && theme().invalidateOnMouseEnterExit()) // When there's a pressed part, we don't draw a hovered state, so there's no reason to invalidate. || m_pressedPart == NoPart) - setNeedsPaintInvalidation(); + setNeedsPaintInvalidation(static_cast<ScrollbarPart>(m_hoveredPart | part)); m_hoveredPart = part; } @@ -317,7 +318,7 @@ if (m_pressedPart != NoPart // When we no longer have a pressed part, we can start drawing a hovered state on the hovered part. || m_hoveredPart != NoPart) - setNeedsPaintInvalidation(); + setNeedsPaintInvalidation(static_cast<ScrollbarPart>(m_pressedPart | m_hoveredPart | part)); m_pressedPart = part; } @@ -388,12 +389,10 @@ // The mouse is moving back over the pressed part. We // need to start up the timer action again. startTimerIfNeeded(theme().autoscrollTimerDelay()); - setNeedsPaintInvalidation(); } else if (m_hoveredPart == m_pressedPart) { // The mouse is leaving the pressed part. Kill our timer // if needed. stopTimerIfNeeded(); - setNeedsPaintInvalidation(); } } @@ -473,7 +472,7 @@ return; m_enabled = e; theme().updateEnabledState(*this); - setNeedsPaintInvalidation(); + setNeedsPaintInvalidation(AllParts); } int Scrollbar::scrollbarThickness() const
diff --git a/third_party/WebKit/Source/platform/scroll/Scrollbar.h b/third_party/WebKit/Source/platform/scroll/Scrollbar.h index 0e461ab..295a0e8 100644 --- a/third_party/WebKit/Source/platform/scroll/Scrollbar.h +++ b/third_party/WebKit/Source/platform/scroll/Scrollbar.h
@@ -170,7 +170,7 @@ // Even if no parts are invalidated, the scrollbar may need to be redrawn // if, for instance, the thumb moves without changing the appearance of any // part. - void setNeedsPaintInvalidation(ScrollbarPart invalidParts = NoPart); + void setNeedsPaintInvalidation(ScrollbarPart invalidParts); // Promptly unregister from the theme manager + run finalizers of derived Scrollbars. EAGERLY_FINALIZE(); @@ -217,8 +217,8 @@ private: bool isScrollbar() const override { return true; } - void invalidate() override { setNeedsPaintInvalidation(); } - void invalidateRect(const IntRect&) override { setNeedsPaintInvalidation(); } + void invalidate() override { setNeedsPaintInvalidation(AllParts); } + void invalidateRect(const IntRect&) override { setNeedsPaintInvalidation(AllParts); } float scrollableAreaCurrentPos() const;
diff --git a/third_party/WebKit/Source/web/ChromeClientImpl.cpp b/third_party/WebKit/Source/web/ChromeClientImpl.cpp index ca0bb2e..e728623d 100644 --- a/third_party/WebKit/Source/web/ChromeClientImpl.cpp +++ b/third_party/WebKit/Source/web/ChromeClientImpl.cpp
@@ -754,10 +754,6 @@ { // TODO(jbroman): This doesn't handle OOPIF correctly. We probably need a // branch for WebFrameWidget, like attachRootGraphicsLayer. - - // TODO(jbroman): We shouldn't reattach the root layer every time. - m_webView->attachPaintArtifactCompositor(); - m_webView->paintArtifactCompositor().update(paintArtifact); }
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp index a954edf..ffe5e93 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.cpp
@@ -264,10 +264,10 @@ return true; } -bool FrameLoaderClientImpl::allowDisplayingInsecureContent(bool enabledPerSettings, SecurityOrigin* context, const KURL& url) +bool FrameLoaderClientImpl::allowDisplayingInsecureContent(bool enabledPerSettings, const KURL& url) { if (m_webFrame->contentSettingsClient()) - return m_webFrame->contentSettingsClient()->allowDisplayingInsecureContent(enabledPerSettings, WebSecurityOrigin(context), WebURL(url)); + return m_webFrame->contentSettingsClient()->allowDisplayingInsecureContent(enabledPerSettings, WebURL(url)); return enabledPerSettings; }
diff --git a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h index e65c5b29..aadcb5d3 100644 --- a/third_party/WebKit/Source/web/FrameLoaderClientImpl.h +++ b/third_party/WebKit/Source/web/FrameLoaderClientImpl.h
@@ -139,7 +139,7 @@ bool allowPlugins(bool enabledPerSettings) override; bool allowImage(bool enabledPerSettings, const KURL& imageURL) override; bool allowMedia(const KURL& mediaURL) override; - bool allowDisplayingInsecureContent(bool enabledPerSettings, SecurityOrigin*, const KURL&) override; + bool allowDisplayingInsecureContent(bool enabledPerSettings, const KURL&) override; bool allowRunningInsecureContent(bool enabledPerSettings, SecurityOrigin*, const KURL&) override; void didNotAllowScript() override; void didNotAllowPlugins() override;
diff --git a/third_party/WebKit/Source/web/LinkHighlightImpl.h b/third_party/WebKit/Source/web/LinkHighlightImpl.h index 62fdee2e..d42d8bcf 100644 --- a/third_party/WebKit/Source/web/LinkHighlightImpl.h +++ b/third_party/WebKit/Source/web/LinkHighlightImpl.h
@@ -66,6 +66,7 @@ // WebCompositorAnimationDelegate implementation. void notifyAnimationStarted(double monotonicTime, int group) override; void notifyAnimationFinished(double monotonicTime, int group) override; + void notifyAnimationAborted(double monotonicTime, int group) override { } // LinkHighlight implementation. void invalidate() override;
diff --git a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp index 3b1a964..db5bee54 100644 --- a/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp +++ b/third_party/WebKit/Source/web/WebRuntimeFeatures.cpp
@@ -225,11 +225,6 @@ RuntimeEnabledFeatures::setTouchEnabled(enable); } -void WebRuntimeFeatures::enableTouchIconLoading(bool enable) -{ - RuntimeEnabledFeatures::setTouchIconLoadingEnabled(enable); -} - void WebRuntimeFeatures::enableWebAudio(bool enable) { RuntimeEnabledFeatures::setWebAudioEnabled(enable);
diff --git a/third_party/WebKit/Source/web/WebViewImpl.cpp b/third_party/WebKit/Source/web/WebViewImpl.cpp index 30d37eb1..416f9d82 100644 --- a/third_party/WebKit/Source/web/WebViewImpl.cpp +++ b/third_party/WebKit/Source/web/WebViewImpl.cpp
@@ -2760,8 +2760,11 @@ bool WebViewImpl::isAcceleratedCompositingActive() const { + // For SPv2, accelerated compositing is managed by the + // PaintArtifactCompositor. if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) - return m_paintArtifactCompositor.webLayer(); + return m_paintArtifactCompositor.rootLayer(); + return m_rootLayer; } @@ -4370,6 +4373,9 @@ m_linkHighlightsTimeline = adoptPtr(Platform::current()->compositorSupport()->createAnimationTimeline()); attachCompositorAnimationTimeline(m_linkHighlightsTimeline.get()); } + + if (RuntimeEnabledFeatures::slimmingPaintV2Enabled()) + attachPaintArtifactCompositor(); } void WebViewImpl::applyViewportDeltas(
diff --git a/third_party/WebKit/public/platform/WebCompositorAnimationDelegate.h b/third_party/WebKit/public/platform/WebCompositorAnimationDelegate.h index 5bf043a..456524d 100644 --- a/third_party/WebKit/public/platform/WebCompositorAnimationDelegate.h +++ b/third_party/WebKit/public/platform/WebCompositorAnimationDelegate.h
@@ -18,6 +18,7 @@ virtual void notifyAnimationStarted(double monotonicTime, int group) = 0; virtual void notifyAnimationFinished(double monotonicTime, int group) = 0; + virtual void notifyAnimationAborted(double monotonicTime, int group) = 0; }; } // namespace blink
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h index 8d74751f..6e3af37 100644 --- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h +++ b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetooth.h
@@ -60,7 +60,7 @@ // BluetoothGATTRemoteServer methods: // See https://webbluetoothchrome.github.io/web-bluetooth/#idl-def-bluetoothgattremoteserver - virtual void disconnect() { } + virtual void disconnect(const WebString& deviceId) = 0; virtual void getPrimaryService(const WebString& deviceId, const WebString& serviceUUID, WebBluetoothGetPrimaryServiceCallbacks*) { }
diff --git a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h index db673003..54d4ae62 100644 --- a/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h +++ b/third_party/WebKit/public/platform/modules/bluetooth/WebBluetoothGATTRemoteServer.h
@@ -10,17 +10,17 @@ namespace blink { struct WebBluetoothGATTRemoteServer { - WebBluetoothGATTRemoteServer(const WebString& deviceInstanceID, + WebBluetoothGATTRemoteServer(const WebString& deviceId, bool connected) - : deviceInstanceID(deviceInstanceID) + : deviceId(deviceId) , connected(connected) { } // Members corresponding to BluetoothGATTRemoteServer attributes as // specified in the IDL. - const WebString deviceInstanceID; - const bool connected; + const WebString deviceId; + bool connected; }; } // namespace blink
diff --git a/third_party/WebKit/public/web/WebContentSettingsClient.h b/third_party/WebKit/public/web/WebContentSettingsClient.h index 3d285d2..eaa4368 100644 --- a/third_party/WebKit/public/web/WebContentSettingsClient.h +++ b/third_party/WebKit/public/web/WebContentSettingsClient.h
@@ -43,7 +43,7 @@ virtual bool allowScriptFromSource(bool enabledPerSettings, const WebURL& scriptURL) { return enabledPerSettings; } // Controls whether insecrure content is allowed to display for this frame. - virtual bool allowDisplayingInsecureContent(bool enabledPerSettings, const WebSecurityOrigin&, const WebURL&) { return enabledPerSettings; } + virtual bool allowDisplayingInsecureContent(bool enabledPerSettings, const WebURL&) { return enabledPerSettings; } // Controls whether insecrure scripts are allowed to execute for this frame. virtual bool allowRunningInsecureContent(bool enabledPerSettings, const WebSecurityOrigin&, const WebURL&) { return enabledPerSettings; }
diff --git a/third_party/WebKit/public/web/WebRuntimeFeatures.h b/third_party/WebKit/public/web/WebRuntimeFeatures.h index 85048e8..f16f7b5 100644 --- a/third_party/WebKit/public/web/WebRuntimeFeatures.h +++ b/third_party/WebKit/public/web/WebRuntimeFeatures.h
@@ -120,8 +120,6 @@ BLINK_EXPORT static void enableTouch(bool); - BLINK_EXPORT static void enableTouchIconLoading(bool); - BLINK_EXPORT static void enableWebAudio(bool); BLINK_EXPORT static void enableWebGLDraftExtensions(bool);
diff --git a/third_party/closure_compiler/compiled_resources.gyp b/third_party/closure_compiler/compiled_resources.gyp index 144543f..56a5a0b 100644 --- a/third_party/closure_compiler/compiled_resources.gyp +++ b/third_party/closure_compiler/compiled_resources.gyp
@@ -23,6 +23,7 @@ '../../chrome/browser/resources/help/compiled_resources.gyp:*', '../../chrome/browser/resources/history/compiled_resources.gyp:*', '../../chrome/browser/resources/options/compiled_resources.gyp:*', + '../../chrome/browser/resources/media_router/compiled_resources.gyp:*', '../../chrome/browser/resources/md_downloads/compiled_resources.gyp:*', '../../chrome/browser/resources/md_extensions/compiled_resources.gyp:*', '../../chrome/browser/resources/ntp4/compiled_resources.gyp:*',
diff --git a/third_party/libjingle/BUILD.gn b/third_party/libjingle/BUILD.gn index d78a0a2..9a80a44 100644 --- a/third_party/libjingle/BUILD.gn +++ b/third_party/libjingle/BUILD.gn
@@ -391,6 +391,8 @@ "source/talk/media/base/rtputils.h", "source/talk/media/base/streamparams.cc", "source/talk/media/base/streamparams.h", + "source/talk/media/base/turnutils.cc", + "source/talk/media/base/turnutils.h", "source/talk/media/base/videoadapter.cc", "source/talk/media/base/videoadapter.h", "source/talk/media/base/videocapturer.cc",
diff --git a/third_party/libjingle/libjingle.gyp b/third_party/libjingle/libjingle.gyp index d8417b7a..11ea915 100644 --- a/third_party/libjingle/libjingle.gyp +++ b/third_party/libjingle/libjingle.gyp
@@ -350,6 +350,8 @@ '<(libjingle_source)/talk/media/base/rtputils.h', '<(libjingle_source)/talk/media/base/streamparams.cc', '<(libjingle_source)/talk/media/base/streamparams.h', + '<(libjingle_source)/talk/media/base/turnutils.cc', + '<(libjingle_source)/talk/media/base/turnutils.h', '<(libjingle_source)/talk/media/base/videoadapter.cc', '<(libjingle_source)/talk/media/base/videoadapter.h', '<(libjingle_source)/talk/media/base/videocapturer.cc',
diff --git a/third_party/libxml/README.chromium b/third_party/libxml/README.chromium index b1f644ff..1b611f0 100644 --- a/third_party/libxml/README.chromium +++ b/third_party/libxml/README.chromium
@@ -15,7 +15,7 @@ - Import https://git.gnome.org/browse/libxml2/commit/?id=7580ce0a7f53891de520fed2c0e360266c286da6 from upstream. - Self-assignment removed https://bugzilla.gnome.org/show_bug.cgi?id=751679. -- Include fix for runtime blowups on larger xpath expressions, https://bugzilla.gnome.org/show_bug.cgi?id=760325 + To import a new snapshot: @@ -49,3 +49,4 @@ Update BUILD.gn and libxml.gyp as necessary to add/remove files, etc. +
diff --git a/third_party/libxml/src/xpath.c b/third_party/libxml/src/xpath.c index 1b85872..dc41ce6b 100644 --- a/third_party/libxml/src/xpath.c +++ b/third_party/libxml/src/xpath.c
@@ -14732,12 +14732,8 @@ #endif /* XPATH_STREAMING */ static void -xmlXPathOptimizeExpressionInternal(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) +xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, xmlXPathStepOpPtr op) { - /* Already optimized? */ - if (op->cacheURI != 0) - return; - /* * Try to rewrite "descendant-or-self::node()/foo" to an optimized * internal representation. @@ -14788,27 +14784,11 @@ } } - /* Mark the node. */ - op->cacheURI = (void*)(~0); - /* Recurse */ if (op->ch1 != -1) - xmlXPathOptimizeExpressionInternal(comp, &comp->steps[op->ch1]); + xmlXPathOptimizeExpression(comp, &comp->steps[op->ch1]); if (op->ch2 != -1) - xmlXPathOptimizeExpressionInternal(comp, &comp->steps[op->ch2]); -} - -static void -xmlXPathOptimizeExpression(xmlXPathCompExprPtr comp, int root) -{ - int i; - // The expression tree/graph traversal is linear, visiting - // each node at most once. Mark each xmlXPathStepOp node - // upon visiting, taking care of clearing out the marks - // afterwards - xmlXPathOptimizeExpressionInternal(comp, &comp->steps[root]); - for (i = 0; i <= root; ++i) - comp->steps[i].cacheURI = 0; + xmlXPathOptimizeExpression(comp, &comp->steps[op->ch2]); } /** @@ -14867,7 +14847,7 @@ comp->nb = 0; #endif if ((comp->nbStep > 1) && (comp->last >= 0)) { - xmlXPathOptimizeExpression(comp, comp->last); + xmlXPathOptimizeExpression(comp, &comp->steps[comp->last]); } } return(comp); @@ -15049,7 +15029,8 @@ (ctxt->comp->nbStep > 1) && (ctxt->comp->last >= 0)) { - xmlXPathOptimizeExpression(ctxt->comp, ctxt->comp->last); + xmlXPathOptimizeExpression(ctxt->comp, + &ctxt->comp->steps[ctxt->comp->last]); } } CHECK_ERROR;
diff --git a/tools/battor_agent/battor_agent.h b/tools/battor_agent/battor_agent.h index c13bc4a..7347eb9 100644 --- a/tools/battor_agent/battor_agent.h +++ b/tools/battor_agent/battor_agent.h
@@ -53,7 +53,7 @@ // Returns whether the BattOr is able to record clock sync markers in its own // trace log. - static bool SupportsExplicitClockSync() { return true; } + static bool SupportsExplicitClockSync() { return false; } // BattOrConnection::Listener implementation. void OnConnectionOpened(bool success) override;
diff --git a/tools/checklicenses/checklicenses.py b/tools/checklicenses/checklicenses.py index 4346629..3b0ac89 100755 --- a/tools/checklicenses/checklicenses.py +++ b/tools/checklicenses/checklicenses.py
@@ -57,6 +57,7 @@ 'BSD-like MIT/X11 (BSD like)', 'BSL (v1.0)', + 'BSL (v1) LGPL (v2.1 or later)', 'FreeType (BSD like) with patent clause', 'FreeType (BSD like)', 'GPL (v2 or later) with Bison parser exception',
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 9fd6bbe..24f60ef 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -6391,6 +6391,16 @@ </summary> </histogram> +<histogram name="DataReductionProxy.LoFi.TransformationType" + enum="DataReductionProxyLoFiTransformationType"> + <owner>bengr@chromium.org</owner> + <owner>megjablon@chromium.org</owner> + <summary> + Counts of pageloads that received or requested, but did not receive, various + Lo-Fi transformations. + </summary> +</histogram> + <histogram name="DataReductionProxy.LoFi.UIAction" enum="DataReductionProxyLoFiUIAction"> <owner>bengr@chromium.org</owner> @@ -6575,6 +6585,57 @@ </summary> </histogram> +<histogram name="DataUsage.MatchingRulesCount.Invalid" units="count"> + <owner>bengr@chromium.org</owner> + <owner>rajendrant@chromium.org</owner> + <summary> + The number of invalid matching rules fetched from the platform external data + use observer. A sample is recorded everytime fetch done callback is called. + </summary> +</histogram> + +<histogram name="DataUsage.MatchingRulesCount.Valid" units="count"> + <owner>bengr@chromium.org</owner> + <owner>rajendrant@chromium.org</owner> + <summary> + The number of valid matching rules fetched from the platform external data + use observer. A sample is recorded everytime fetch done callback is called. + </summary> +</histogram> + +<histogram name="DataUsage.Perf.MatchingRuleFirstFetchDuration" units="ms"> + <owner>bengr@chromium.org</owner> + <owner>rajendrant@chromium.org</owner> + <summary> + The time taken in milliseconds to fetch the matching rules for the first + time from the platform external data use observer. This measures the + duration from the start time of Chromium to the time the rules are returned + asynchronously. A sample is recorded when the first fetch done callback is + called. + </summary> +</histogram> + +<histogram name="DataUsage.Perf.ReportSubmissionDuration" units="ms"> + <owner>bengr@chromium.org</owner> + <owner>rajendrant@chromium.org</owner> + <summary> + The time taken in milliseconds to submit the data use reports to the + platform external data use observer. This measures the duration from the + time of report submission to the time report submission done asynchronous + callback is received. A sample is recorded everytime report submission done + callback is received. + </summary> +</histogram> + +<histogram name="DataUsage.Perf.URLRegexMatchDuration" units="ms"> + <owner>bengr@chromium.org</owner> + <owner>rajendrant@chromium.org</owner> + <summary> + The time taken in milliseconds for a regular expression to parse an URL. A + sample is recorded evertime regular expression parsing is done for an URL. + </summary> +</histogram> + <histogram name="DataUsage.ReportSubmission.Bytes" units="bytes"> <owner>bengr@chromium.org</owner> <owner>tbansal@chromium.org</owner> @@ -44503,6 +44564,16 @@ </summary> </histogram> +<histogram name="Settings.SearchSections" enum="SettingsSections"> + <owner>dschuyler@chromium.org</owner> + <summary> + If there is no further activity in the search box for 1 second, this records + one tick each time a settings section is shown as a result of searching + withing the chrome://settings page. If multiple matches are found within + the same section, the section match is only recorded once. + </summary> +</histogram> + <histogram name="Settings.SearchSubpageMatchCount"> <owner>dschuyler@chromium.org</owner> <summary> @@ -57205,6 +57276,8 @@ <int value="102" label="RFMF_RENDERER_FAKED_ITS_OWN_DEATH"/> <int value="103" label="DWNLD_INVALID_SAVABLE_RESOURCE_LINKS_RESPONSE"/> <int value="104" label="DWNLD_INVALID_SERIALIZE_AS_MHTML_RESPONSE"/> + <int value="105" label="BDH_DEVICE_NOT_ALLOWED_FOR_ORIGIN"/> + <int value="106" label="ACI_WRONG_STORAGE_PARTITION"/> </enum> <enum name="BadMessageReasonExtensions" type="int"> @@ -59485,6 +59558,13 @@ out"/> </enum> +<enum name="DataReductionProxyLoFiTransformationType" type="int"> + <int value="0" label="Pageloads that are Lo-Fi previews"/> + <int value="1" + label="Pageloads that requested Lo-Fi previews, but did not have the + transformation"/> +</enum> + <enum name="DataReductionProxyLoFiUIAction" type="int"> <int value="0" label="'Load images' snackbar shown"/> <int value="1" label="'Load images' snackbar clicked"/> @@ -67872,41 +67952,41 @@ <enum name="InsecureContentType" type="int"> <int value="0" label="Displayed"/> - <int value="1" label="Displayed by *.google.com"/> - <int value="2" label="Displayed by www.google.com"/> + <int value="1" label="Displayed by *.google.com (deprecated)"/> + <int value="2" label="Displayed by www.google.com (deprecated)"/> <int value="3" label="Displayed due to an iframe"/> <int value="4" label="Ran"/> - <int value="5" label="Ran by *.google.com"/> - <int value="6" label="Ran by www.google.com"/> - <int value="7" label="Ran from www.youtube.com"/> + <int value="5" label="Ran by *.google.com (deprecated)"/> + <int value="6" label="Ran by www.google.com (deprecated)"/> + <int value="7" label="Ran from www.youtube.com (deprecated)"/> <int value="8" label="Ran due to script"/> <int value="9" label="Ran due to CSS"/> <int value="10" label="Ran due to a plug-in"/> - <int value="11" label="Displayed by www.youtube.com"/> - <int value="12" label="Ran by www.youtube.com"/> - <int value="13" label="Ran by *.googleusercontent.com"/> - <int value="14" label="Displayed by mail.google.com"/> - <int value="15" label="Ran by mail.google.com"/> - <int value="16" label="Displayed by plus.google.com"/> - <int value="17" label="Ran by plus.google.com"/> - <int value="18" label="Displayed by docs.google.com"/> - <int value="19" label="Ran by docs.google.com"/> - <int value="20" label="Displayed by sites.google.com"/> - <int value="21" label="Ran by sites.google.com"/> - <int value="22" label="Displayed by picasaweb.google.com"/> - <int value="23" label="Ran by picasaweb.google.com"/> - <int value="24" label="Displayed by google.com/reader/"/> - <int value="25" label="Ran by google.com/reader/"/> - <int value="26" label="Displayed by code.google.com"/> - <int value="27" label="Ran by code.google.com"/> - <int value="28" label="Displayed by groups.google.com"/> - <int value="29" label="Ran by groups.google.com"/> - <int value="30" label="Displayed by maps.google.com"/> - <int value="31" label="Ran by maps.google.com"/> - <int value="32" label="Displayed by google.com/support/"/> - <int value="33" label="Ran by google.com/support/"/> - <int value="34" label="Displayed by google.com/intl/"/> - <int value="35" label="Ran by google.com/intl/"/> + <int value="11" label="Displayed by www.youtube.com (deprecated)"/> + <int value="12" label="Ran by www.youtube.com (deprecated)"/> + <int value="13" label="Ran by *.googleusercontent.com (deprecated)"/> + <int value="14" label="Displayed by mail.google.com (deprecated)"/> + <int value="15" label="Ran by mail.google.com (deprecated)"/> + <int value="16" label="Displayed by plus.google.com (deprecated)"/> + <int value="17" label="Ran by plus.google.com (deprecated)"/> + <int value="18" label="Displayed by docs.google.com (deprecated)"/> + <int value="19" label="Ran by docs.google.com (deprecated)"/> + <int value="20" label="Displayed by sites.google.com (deprecated)"/> + <int value="21" label="Ran by sites.google.com (deprecated)"/> + <int value="22" label="Displayed by picasaweb.google.com (deprecated)"/> + <int value="23" label="Ran by picasaweb.google.com (deprecated)"/> + <int value="24" label="Displayed by google.com/reader/ (deprecated)"/> + <int value="25" label="Ran by google.com/reader/ (deprecated)"/> + <int value="26" label="Displayed by code.google.com (deprecated)"/> + <int value="27" label="Ran by code.google.com (deprecated)"/> + <int value="28" label="Displayed by groups.google.com (deprecated)"/> + <int value="29" label="Ran by groups.google.com (deprecated)"/> + <int value="30" label="Displayed by maps.google.com (deprecated)"/> + <int value="31" label="Ran by maps.google.com (deprecated)"/> + <int value="32" label="Displayed by google.com/support/ (deprecated)"/> + <int value="33" label="Ran by google.com/support/ (deprecated)"/> + <int value="34" label="Displayed by google.com/intl/ (deprecated)"/> + <int value="35" label="Ran by google.com/intl/ (deprecated)"/> </enum> <enum name="InstallStatus" type="int"> @@ -73609,6 +73689,7 @@ <int value="1" label="DENIED"/> <int value="2" label="DISMISSED"/> <int value="3" label="IGNORED"/> + <int value="4" label="REVOKED"/> </enum> <enum name="PermissionStatus" type="int"> @@ -76774,6 +76855,54 @@ </int> </enum> +<enum name="SettingsSections" type="int"> + <summary> + A collection of sections from chrome://settings. Used for metrics about + searching within the settings options. + </summary> + <int value="0" label="No Match Found"/> + <int value="1" label="Unknown Section"/> + <int value="2" label="Network CROS"/> + <int value="3" label="Proxy"/> + <int value="4" label="Appearance"/> + <int value="5" label="Device"/> + <int value="6" label="Search"/> + <int value="7" label="Sync Users"/> + <int value="8" label="Set Default Browser"/> + <int value="9" label="Date Time"/> + <int value="10" label="Device Control"/> + <int value="11" label="Privacy"/> + <int value="12" label="Bluetooth Devices"/> + <int value="13" label="Passwords and Autofill"/> + <int value="14" label="Easy Unlock"/> + <int value="15" label="Web Content"/> + <int value="16" label="Network"/> + <int value="17" label="Languages"/> + <int value="18" label="Downloads"/> + <int value="19" label="Certificates"/> + <int value="20" label="Cloudprint Options"/> + <int value="21" label="A11y"/> + <int value="22" label="Factory Reset"/> + <int value="23" label="System"/> + <int value="24" label="Reset Profile"/> + <int value="25" label="Sync"/> + <int value="26" label="Startup"/> + <int value="27" label="Mouselock"/> + <int value="28" label="Page Zoom Levels"/> + <int value="29" label="Status"/> + <int value="30" label="Main"/> + <int value="31" label="Pointer Touchpad"/> + <int value="32" label="Pointer Mouse"/> + <int value="33" label="Prefs Blocked Languages"/> + <int value="34" label="Prefs Language Blacklist"/> + <int value="35" label="Prefs Site Blacklist"/> + <int value="36" label="Prefs Whitelists"/> + <int value="37" label="Prefs Supported Languages"/> + <int value="38" label="Prefs Cld Version"/> + <int value="39" label="Prefs Cld Data Source"/> + <int value="40" label="Prefs Dump"/> +</enum> + <enum name="SHA1Status" type="int"> <summary> Whether or not SHA-1 was present in a certificate chain and, if it was, when @@ -80205,12 +80334,13 @@ <enum name="WebBluetoothFunction" type="int"> <int value="0" label="requestDevice()"/> <int value="1" label="connectGATT()"/> - <int value="2" label="getPrimaryService()"/> + <int value="2" label="RemoteGATTServer.getPrimaryService()"/> <int value="3" label="getCharacteristic()"/> <int value="4" label="Characteristic.readValue()"/> <int value="5" label="Characteristic.writeValue()"/> <int value="6" label="Characteristic.startNotifications()"/> <int value="7" label="Characteristic.stopNotifications()"/> + <int value="8" label="RemoteGATTServer.disconnect()"/> </enum> <enum name="WebBluetoothGATTOperationOutcome" type="int">
diff --git a/tools/metrics/rappor/rappor.xml b/tools/metrics/rappor/rappor.xml index 068d12a..c8b9f1f 100644 --- a/tools/metrics/rappor/rappor.xml +++ b/tools/metrics/rappor/rappor.xml
@@ -217,11 +217,23 @@ </summary> </rappor-metric> +<rappor-metric + name="ContentSettings.PermissionActions_AudioCapture.Revoked.Url" + type="ETLD_PLUS_ONE"> + <owner>tsergeant@chromium.org</owner> + <summary> + The domain for which an AudioCapture permission was revoked. Also recorded + as a multi-dimensional metric in Permissions.Action.AudioCapture. + </summary> +</rappor-metric> + <rappor-metric name="ContentSettings.PermissionActions_Camera.Revoked.Url" type="ETLD_PLUS_ONE"> <owner>jialiul@chromium.org</owner> <summary> - The domain for which a camera permission was revoked. + **DEPRECATED. Renamed to + ContentSettings.PermissionActions_VideoCapture.Revoked.Url on + 2016-01-07.** The domain for which a camera permission was revoked. </summary> </rappor-metric> @@ -278,7 +290,9 @@ type="ETLD_PLUS_ONE"> <owner>jialiul@chromium.org</owner> <summary> - The domain for which a microphone permission was revoked. + **DEPRECATED. Renamed to + ContentSettings.PermissionActions_AudioCapture.Revoked.Url on + 2016-01-07.** The domain for which a microphone permission was revoked. </summary> </rappor-metric> @@ -382,6 +396,16 @@ </summary> </rappor-metric> +<rappor-metric + name="ContentSettings.PermissionActions_VideoCapture.Revoked.Url" + type="ETLD_PLUS_ONE"> + <owner>tsergeant@chromium.org</owner> + <summary> + The domain for which an VideoCapture permission was revoked. Also recorded + as a multi-dimensional metric in Permissions.Action.VideoCapture. + </summary> +</rappor-metric> + <rappor-metric name="ContentSettings.PermissionRequested.Geolocation.Url" type="ETLD_PLUS_ONE"> <owner>miguelg@chromium.org</owner>
diff --git a/tools/perf/measurements/draw_properties.py b/tools/perf/measurements/draw_properties.py index e1f8e87..6f28444 100644 --- a/tools/perf/measurements/draw_properties.py +++ b/tools/perf/measurements/draw_properties.py
@@ -22,7 +22,7 @@ config.tracing_category_filter.AddDisabledByDefault( 'disabled-by-default-cc.debug.cdp-perf') config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(config) + tab.browser.platform.tracing_controller.StartTracing(config) def ComputeAverageOfDurations(self, timeline_model, name): events = timeline_model.GetAllEventsOfName(name) @@ -35,7 +35,7 @@ return duration_avg def ValidateAndMeasurePage(self, page, tab, results): - timeline_data = tab.browser.platform.tracing_controller.Stop() + timeline_data = tab.browser.platform.tracing_controller.StopTracing() timeline_model = model.TimelineModel(timeline_data) pt_avg = self.ComputeAverageOfDurations( @@ -49,4 +49,4 @@ def DidRunPage(self, platform): tracing_controller = platform.tracing_controller if tracing_controller.is_tracing_running: - tracing_controller.Stop() + tracing_controller.StopTracing()
diff --git a/tools/perf/measurements/image_decoding.py b/tools/perf/measurements/image_decoding.py index 361762a..4b0910e 100644 --- a/tools/perf/measurements/image_decoding.py +++ b/tools/perf/measurements/image_decoding.py
@@ -44,7 +44,7 @@ for c in [ 'blink', 'devtools.timeline', 'webkit.console', 'blink.console']: config.tracing_category_filter.AddIncludedCategory(c) config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(config) + tab.browser.platform.tracing_controller.StartTracing(config) def StopBrowserAfterPage(self, browser, page): return not browser.tabs[0].ExecuteJavaScript(""" @@ -54,7 +54,7 @@ """) def ValidateAndMeasurePage(self, page, tab, results): - timeline_data = tab.browser.platform.tracing_controller.Stop() + timeline_data = tab.browser.platform.tracing_controller.StopTracing() timeline_model = model.TimelineModel(timeline_data) self._power_metric.Stop(page, tab) self._power_metric.AddResults(tab, results) @@ -93,4 +93,4 @@ def DidRunPage(self, platform): self._power_metric.Close() if platform.tracing_controller.is_tracing_running: - platform.tracing_controller.Stop() + platform.tracing_controller.StopTracing()
diff --git a/tools/perf/measurements/oilpan_gc_times.py b/tools/perf/measurements/oilpan_gc_times.py index 0eb4ef61..3e74d66 100644 --- a/tools/perf/measurements/oilpan_gc_times.py +++ b/tools/perf/measurements/oilpan_gc_times.py
@@ -141,10 +141,10 @@ for c in ['webkit.console', 'blink.console', 'blink_gc']: config.tracing_category_filter.AddIncludedCategory(c) config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(config, timeout=1000) + tab.browser.platform.tracing_controller.StartTracing(config, timeout=1000) def ValidateAndMeasurePage(self, page, tab, results): - timeline_data = tab.browser.platform.tracing_controller.Stop() + timeline_data = tab.browser.platform.tracing_controller.StopTracing() timeline_model = TimelineModel(timeline_data) threads = timeline_model.GetAllThreads() for thread in threads: @@ -153,7 +153,7 @@ def DidRunPage(self, platform): if platform.tracing_controller.is_tracing_running: - platform.tracing_controller.Stop() + platform.tracing_controller.StopTracing() class OilpanGCTimesForSmoothness(_OilpanGCTimesBase):
diff --git a/tools/perf/measurements/smoothness_unittest.py b/tools/perf/measurements/smoothness_unittest.py index 0bf1a91..d79b4346 100644 --- a/tools/perf/measurements/smoothness_unittest.py +++ b/tools/perf/measurements/smoothness_unittest.py
@@ -19,7 +19,7 @@ class FakeTracingController(object): def __init__(self): self.config = None - def Start(self, config): + def StartTracing(self, config): self.config = config def IsChromeTracingSupported(self):
diff --git a/tools/perf/measurements/task_execution_time.py b/tools/perf/measurements/task_execution_time.py index 12c6031b..1ff77c1 100644 --- a/tools/perf/measurements/task_execution_time.py +++ b/tools/perf/measurements/task_execution_time.py
@@ -46,11 +46,11 @@ config.tracing_category_filter.AddIncludedCategory(category) config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start( + tab.browser.platform.tracing_controller.StartTracing( config, self._TIME_OUT_IN_SECONDS) def ValidateAndMeasurePage(self, page, tab, results): - trace_data = tab.browser.platform.tracing_controller.Stop() + trace_data = tab.browser.platform.tracing_controller.StopTracing() timeline_model = TimelineModel(trace_data) self._renderer_process = timeline_model.GetRendererProcessFromTabId(tab.id)
diff --git a/tools/perf/measurements/timeline_controller.py b/tools/perf/measurements/timeline_controller.py index 2f96559..482d680 100644 --- a/tools/perf/measurements/timeline_controller.py +++ b/tools/perf/measurements/timeline_controller.py
@@ -38,7 +38,7 @@ for delay in page.GetSyntheticDelayCategories(): config.tracing_category_filter.AddSyntheticDelay(delay) config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(config) + tab.browser.platform.tracing_controller.StartTracing(config) def Start(self, tab): # Start the smooth marker for all actions. @@ -53,7 +53,7 @@ if self._enable_auto_issuing_record: self._interaction.End() # Stop tracing. - timeline_data = tab.browser.platform.tracing_controller.Stop() + timeline_data = tab.browser.platform.tracing_controller.StopTracing() results.AddValue(trace.TraceValue( results.current_page, timeline_data)) self._model = TimelineModel(timeline_data) @@ -89,7 +89,7 @@ def CleanUp(self, platform): if platform.tracing_controller.is_tracing_running: - platform.tracing_controller.Stop() + platform.tracing_controller.StopTracing() @property def model(self):
diff --git a/tools/perf/measurements/v8_gc_times.py b/tools/perf/measurements/v8_gc_times.py index 75ed3a7..90543f2 100644 --- a/tools/perf/measurements/v8_gc_times.py +++ b/tools/perf/measurements/v8_gc_times.py
@@ -27,18 +27,18 @@ for category in self._CATEGORIES: config.tracing_category_filter.AddIncludedCategory(category) config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start( + tab.browser.platform.tracing_controller.StartTracing( config, self._TIME_OUT_IN_SECONDS) def ValidateAndMeasurePage(self, page, tab, results): - trace_data = tab.browser.platform.tracing_controller.Stop() + trace_data = tab.browser.platform.tracing_controller.StopTracing() timeline_model = TimelineModel(trace_data) renderer_process = timeline_model.GetRendererProcessFromTabId(tab.id) self._AddV8MetricsToResults(renderer_process, results) def DidRunPage(self, platform): if platform.tracing_controller.is_tracing_running: - platform.tracing_controller.Stop() + platform.tracing_controller.StopTracing() def _AddV8MetricsToResults(self, process, results): if process is None:
diff --git a/tools/telemetry/telemetry/core/tracing_controller.py b/tools/telemetry/telemetry/core/tracing_controller.py index 8b35c10..15492fd 100644 --- a/tools/telemetry/telemetry/core/tracing_controller.py +++ b/tools/telemetry/telemetry/core/tracing_controller.py
@@ -2,17 +2,21 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +from telemetry.internal.platform import tracing_agent -class TracingController(object): + +class TracingController(tracing_agent.TracingAgent): def __init__(self, tracing_controller_backend): """Provides control of the tracing systems supported by telemetry.""" + super(TracingController, self).__init__( + tracing_controller_backend._platform_backend) self._tracing_controller_backend = tracing_controller_backend - def Start(self, tracing_config, timeout=10): + def StartTracing(self, tracing_config, timeout=10): """Starts tracing. - tracing config contains both tracing optoins and category filters. + tracing config contains both tracing options and category filters. trace_options specifies which tracing systems to activate. Category filter allows fine-tuning of the data that are collected by the selected tracing @@ -28,11 +32,11 @@ your code fail gracefully when the data you require is not present in the resulting trace. """ - self._tracing_controller_backend.Start(tracing_config, timeout) + self._tracing_controller_backend.StartTracing(tracing_config, timeout) - def Stop(self): + def StopTracing(self): """Stops tracing and returns a TraceValue.""" - return self._tracing_controller_backend.Stop() + return self._tracing_controller_backend.StopTracing() @property def is_tracing_running(self): @@ -41,3 +45,17 @@ def IsChromeTracingSupported(self): """Returns whether chrome tracing is supported.""" return self._tracing_controller_backend.IsChromeTracingSupported() + + def StartAgentTracing(self, config, timeout=10): + """ Starts agent tracing for tracing controller""" + return self._tracing_controller_backend.StartAgentTracing(config, timeout) + + def StopAgentTracing(self, trace_data_builder): + """ Stops agent tracing for tracing controller. """ + return self._tracing_controller_backend.StopAgentTracing(trace_data_builder) + + def SupportsExplicitClockSync(self): + return self._tracing_controller_backend.SupportsExplicitClockSync() + + def RecordClockSyncMarker(self, sync_id): + return self._tracing_controller_backend.RecordClockSyncMarker(sync_id)
diff --git a/tools/telemetry/telemetry/core/tracing_controller_unittest.py b/tools/telemetry/telemetry/core/tracing_controller_unittest.py index ccab5fe..316fd5f 100644 --- a/tools/telemetry/telemetry/core/tracing_controller_unittest.py +++ b/tools/telemetry/telemetry/core/tracing_controller_unittest.py
@@ -16,7 +16,7 @@ tracing_controller = self._tab.browser.platform.tracing_controller config = tracing_config.TracingConfig() config.enable_chrome_trace = True - tracing_controller.Start(config) + tracing_controller.StartTracing(config) self.Navigate('blank.html') self.assertEquals( self._tab.EvaluateJavaScript('document.location.pathname;'), @@ -27,7 +27,7 @@ console.time = function() { }; """) with self.assertRaisesRegexp(Exception, 'Page stomped on console.time'): - tracing_controller.Stop() + tracing_controller.StopTracing() # Restore console.time self._tab.EvaluateJavaScript(""" @@ -37,16 +37,16 @@ # Check that subsequent tests will be able to use tracing normally. self.assertFalse(tracing_controller.is_tracing_running) - tracing_controller.Start(config) + tracing_controller.StartTracing(config) self.assertTrue(tracing_controller.is_tracing_running) - tracing_controller.Stop() + tracing_controller.StopTracing() self.assertFalse(tracing_controller.is_tracing_running) def testExceptionRaisedInStopTracing(self): tracing_controller = self._tab.browser.platform.tracing_controller config = tracing_config.TracingConfig() config.enable_chrome_trace = True - tracing_controller.Start(config) + tracing_controller.StartTracing(config) self.Navigate('blank.html') self._tab.EvaluateJavaScript(""" @@ -54,7 +54,7 @@ console.time = function() { }; """) with self.assertRaisesRegexp(Exception, 'Page stomped on console.time'): - tracing_controller.Stop() + tracing_controller.StopTracing() # Tracing is stopped even if there is exception. self.assertFalse(tracing_controller.is_tracing_running) @@ -63,9 +63,9 @@ tracing_controller = self._browser.platform.tracing_controller config = tracing_config.TracingConfig() config.enable_chrome_trace = True - tracing_controller.Start(config) + tracing_controller.StartTracing(config) - trace_data = tracing_controller.Stop() + trace_data = tracing_controller.StopTracing() # Test that trace data is parsable model = model_module.TimelineModel(trace_data) assert len(model.processes) > 0 @@ -74,15 +74,15 @@ tracing_controller = self._browser.platform.tracing_controller config = tracing_config.TracingConfig() config.enable_chrome_trace = True - tracing_controller.Start(config) - self.assertFalse(tracing_controller.Start(config)) + tracing_controller.StartTracing(config) + self.assertFalse(tracing_controller.StartTracing(config)) - trace_data = tracing_controller.Stop() + trace_data = tracing_controller.StopTracing() # Test that trace data is parsable model_module.TimelineModel(trace_data) self.assertFalse(tracing_controller.is_tracing_running) # Calling stop again will raise exception - self.assertRaises(Exception, tracing_controller.Stop) + self.assertRaises(Exception, tracing_controller.StopTracing) def _StartupTracing(self, platform): # Stop browser @@ -92,7 +92,7 @@ self.assertFalse(platform.tracing_controller.is_tracing_running) config = tracing_config.TracingConfig() config.enable_chrome_trace = True - platform.tracing_controller.Start(config) + platform.tracing_controller.StartTracing(config) self.assertTrue(platform.tracing_controller.is_tracing_running) try: @@ -102,16 +102,17 @@ self._browser.tabs[0].WaitForDocumentReadyStateToBeInteractiveOrBetter() self.assertEquals(platform, self._browser.platform) # Calling start tracing again will return False - self.assertFalse(self._browser.platform.tracing_controller.Start(config)) + self.assertFalse( + self._browser.platform.tracing_controller.StartTracing(config)) - trace_data = self._browser.platform.tracing_controller.Stop() + trace_data = self._browser.platform.tracing_controller.StopTracing() # Test that trace data is parsable model_module.TimelineModel(trace_data) self.assertFalse( self._browser.platform.tracing_controller.is_tracing_running) # Calling stop tracing again will raise exception self.assertRaises(Exception, - self._browser.platform.tracing_controller.Stop) + self._browser.platform.tracing_controller.StopTracing) finally: if self._browser: self._browser.Close()
diff --git a/tools/telemetry/telemetry/internal/actions/action_runner_unittest.py b/tools/telemetry/telemetry/internal/actions/action_runner_unittest.py index 3967a8b..d17c4a7 100644 --- a/tools/telemetry/telemetry/internal/actions/action_runner_unittest.py +++ b/tools/telemetry/telemetry/internal/actions/action_runner_unittest.py
@@ -33,11 +33,11 @@ config = tracing_config.TracingConfig() config.SetNoOverheadFilter() config.enable_chrome_trace = True - self._browser.platform.tracing_controller.Start(config) + self._browser.platform.tracing_controller.StartTracing(config) with action_runner.CreateInteraction('InteractionName', **interaction_kwargs): pass - trace_data = self._browser.platform.tracing_controller.Stop() + trace_data = self._browser.platform.tracing_controller.StopTracing() records = self.GetInteractionRecords(trace_data) self.assertEqual(
diff --git a/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py b/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py index 6491df21..dacef13 100644 --- a/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py +++ b/tools/telemetry/telemetry/internal/backends/chrome_inspector/tracing_backend_unittest.py
@@ -49,7 +49,7 @@ config.tracing_category_filter.AddDisabledByDefault( 'disabled-by-default-memory-infra') config.enable_chrome_trace = True - self._tracing_controller.Start(config) + self._tracing_controller.StartTracing(config) # Request several memory dumps in a row and test that they were all # successfully created with unique IDs. @@ -60,7 +60,7 @@ self.assertNotIn(dump_id, expected_dump_ids) expected_dump_ids.append(dump_id) - trace_data = self._tracing_controller.Stop() + trace_data = self._tracing_controller.StopTracing() # Check that dumping memory after tracing stopped raises an exception. self.assertRaises(Exception, self._browser.DumpMemory) @@ -82,12 +82,12 @@ # Start tracing with memory dumps disabled. config = tracing_config.TracingConfig() config.enable_chrome_trace = True - self._tracing_controller.Start(config) + self._tracing_controller.StartTracing(config) # Check that the method returns None if the dump was not successful. self.assertIsNone(self._browser.DumpMemory()) - trace_data = self._tracing_controller.Stop() + trace_data = self._tracing_controller.StopTracing() # Check that dumping memory after tracing stopped raises an exception. self.assertRaises(Exception, self._browser.DumpMemory)
diff --git a/tools/telemetry/telemetry/internal/browser/browser_unittest.py b/tools/telemetry/telemetry/internal/browser/browser_unittest.py index 2ff6992..2f744f0e 100644 --- a/tools/telemetry/telemetry/internal/browser/browser_unittest.py +++ b/tools/telemetry/telemetry/internal/browser/browser_unittest.py
@@ -122,9 +122,9 @@ self.assertFalse(tracing_controller.is_tracing_running) config = tracing_config.TracingConfig() config.enable_chrome_trace = True - tracing_controller.Start(config) + tracing_controller.StartTracing(config) self.assertTrue(tracing_controller.is_tracing_running) - tracing_controller.Stop() + tracing_controller.StopTracing() self.assertFalse(tracing_controller.is_tracing_running)
diff --git a/tools/telemetry/telemetry/internal/browser/tab_unittest.py b/tools/telemetry/telemetry/internal/browser/tab_unittest.py index 2863c75..119e42e8 100644 --- a/tools/telemetry/telemetry/internal/browser/tab_unittest.py +++ b/tools/telemetry/telemetry/internal/browser/tab_unittest.py
@@ -104,10 +104,10 @@ config = tracing_config.TracingConfig() config.SetNoOverheadFilter() config.enable_chrome_trace = True - self._browser.platform.tracing_controller.Start(config) + self._browser.platform.tracing_controller.StartTracing(config) self._tab.Highlight(rgba_color.WEB_PAGE_TEST_ORANGE) self._tab.ClearHighlight(rgba_color.WEB_PAGE_TEST_ORANGE) - trace_data = self._browser.platform.tracing_controller.Stop() + trace_data = self._browser.platform.tracing_controller.StopTracing() timeline_model = model.TimelineModel(trace_data) renderer_thread = timeline_model.GetRendererThreadFromTabId( self._tab.id) @@ -124,7 +124,7 @@ def testGetRendererThreadFromTabId(self): self.assertEquals(self._tab.url, 'about:blank') # Create 3 tabs. The third tab is closed before we call - # tracing_controller.Start. + # tracing_controller.StartTracing. first_tab = self._tab second_tab = self._browser.tabs.New() second_tab.Navigate('about:blank') @@ -136,12 +136,12 @@ config = tracing_config.TracingConfig() config.SetNoOverheadFilter() config.enable_chrome_trace = True - self._browser.platform.tracing_controller.Start(config) + self._browser.platform.tracing_controller.StartTracing(config) first_tab.ExecuteJavaScript('console.time("first-tab-marker");') first_tab.ExecuteJavaScript('console.timeEnd("first-tab-marker");') second_tab.ExecuteJavaScript('console.time("second-tab-marker");') second_tab.ExecuteJavaScript('console.timeEnd("second-tab-marker");') - trace_data = self._browser.platform.tracing_controller.Stop() + trace_data = self._browser.platform.tracing_controller.StopTracing() timeline_model = model.TimelineModel(trace_data) # Assert that the renderer_thread of the first tab contains
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/__init__.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/__init__.py index 85d82d6..85e35fdf 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/__init__.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/__init__.py
@@ -24,7 +24,7 @@ del platform_backend # unused return False - def Start(self, config, timeout): + def StartAgentTracing(self, config, timeout): """ Override to add tracing agent's custom logic to start tracing. Depending on trace_options and category_filter, the tracing agent may choose @@ -45,9 +45,24 @@ """ raise NotImplementedError - def Stop(self, trace_data_builder): + def StopAgentTracing(self, trace_data_builder): """ Override to add tracing agent's custom logic to stop tracing. - Stop() should guarantee tracing is stopped, even if there may be exception. + StopAgentTracing() should guarantee tracing is stopped, even if there may + be exception. """ raise NotImplementedError + + def SupportsExplicitClockSync(self): + """ Override to indicate support of explicit clock syncing. """ + return False + + def RecordClockSyncMarker(self, sync_id): + """ Override to record clock sync marker. + + Only override if supports explicit clock syncing. + Args: + sync_id: Unqiue id for sync event. + """ + del sync_id # unused + raise NotImplementedError
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent.py index 5ee2d2a..a932b74 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent.py
@@ -82,7 +82,7 @@ config, config.tracing_category_filter.filter_string, timeout) return True - def Start(self, config, timeout): + def StartAgentTracing(self, config, timeout): if not config.enable_chrome_trace: return False @@ -108,7 +108,7 @@ return True return False - def Stop(self, trace_data_builder): + def StopAgentTracing(self, trace_data_builder): if not self._trace_config: raise ChromeTracingStoppedError( 'Tracing is not running on platform backend %s.'
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent_unittest.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent_unittest.py index ee4f85f2..a90a66e 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent_unittest.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/chrome_tracing_agent_unittest.py
@@ -84,13 +84,13 @@ config.tracing_category_filter.AddIncludedCategory('foo') config.enable_chrome_trace = enable_chrome_trace agent._platform_backend.tracing_controller_backend.is_tracing_running = True - agent.Start(config, 10) + agent.StartAgentTracing(config, 10) return agent def StopTracing(self, agent): agent._platform_backend.tracing_controller_backend.is_tracing_running = ( False) - agent.Stop(None) + agent.StopAgentTracing(None) def testRegisterDevtoolsClient(self): chrome_tracing_devtools_manager.RegisterDevToolsClient(
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent.py index d82817b..074026f 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent.py
@@ -14,13 +14,13 @@ def IsSupported(cls, platform_backend): return platform_backend.IsDisplayTracingSupported() - def Start(self, config, timeout): + def StartAgentTracing(self, config, timeout): del timeout # unused if config.enable_platform_display_trace: self._platform_backend.StartDisplayTracing() return True - def Stop(self, trace_data_builder): + def StopAgentTracing(self, trace_data_builder): surface_flinger_trace_data = self._platform_backend.StopDisplayTracing() trace_data_builder.AddEventsTo( trace_data.SURFACE_FLINGER_PART, surface_flinger_trace_data)
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent_unittest.py b/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent_unittest.py index 0956946..eb8720e9 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent_unittest.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_agent/display_tracing_agent_unittest.py
@@ -35,30 +35,30 @@ @mock.patch( 'devil.android.perf.surface_stats_collector.SurfaceStatsCollector') def testStartAndStopTracing(self, MockSurfaceStatsCollector): - self._agent.Start(self._config, 10) + self._agent.StartAgentTracing(self._config, 10) # Second start tracing will raise error. with self.assertRaises(AssertionError): - self._agent.Start(self._config, 10) + self._agent.StartAgentTracing(self._config, 10) self._platform_backend.surface_stats_collector.Stop.return_value = (0, []) - self._agent.Stop(mock.MagicMock()) + self._agent.StopAgentTracing(mock.MagicMock()) # Can start and stop tracing multiple times. - self._agent.Start(self._config, 10) + self._agent.StartAgentTracing(self._config, 10) self._platform_backend.surface_stats_collector.Stop.return_value = (0, []) - self._agent.Stop(mock.MagicMock()) + self._agent.StopAgentTracing(mock.MagicMock()) @mock.patch( 'devil.android.perf.surface_stats_collector.SurfaceStatsCollector') def testExceptionRaisedInStopTracing(self, MockSurfaceStatsCollector): - self._agent.Start(self._config, 10) + self._agent.StartAgentTracing(self._config, 10) self._platform_backend.surface_stats_collector.Stop.side_effect = Exception( 'Raise error when stopping tracing.') with self.assertRaises(Exception): - self._agent.Stop(mock.MagicMock()) + self._agent.StopAgentTracing(mock.MagicMock()) # Tracing is stopped even if there is exception. And the agent can start # tracing again. - self._agent.Start(self._config, 10) + self._agent.StartAgentTracing(self._config, 10) self._platform_backend.surface_stats_collector.Stop.side_effect = None self._platform_backend.surface_stats_collector.Stop.return_value = (0, []) - self._agent.Stop(mock.MagicMock()) + self._agent.StopAgentTracing(mock.MagicMock())
diff --git a/tools/telemetry/telemetry/internal/platform/tracing_controller_backend.py b/tools/telemetry/telemetry/internal/platform/tracing_controller_backend.py index 75e3624..b7cea403 100644 --- a/tools/telemetry/telemetry/internal/platform/tracing_controller_backend.py +++ b/tools/telemetry/telemetry/internal/platform/tracing_controller_backend.py
@@ -36,7 +36,7 @@ agent_classes.IsSupported(platform_backend)] self._active_agents_instances = [] - def Start(self, config, timeout): + def StartTracing(self, config, timeout): if self.is_tracing_running: return False @@ -57,17 +57,17 @@ for agent_class in self._supported_agents_classes: agent = agent_class(self._platform_backend) - if agent.Start(config, timeout): + if agent.StartAgentTracing(config, timeout): self._active_agents_instances.append(agent) - def Stop(self): + def StopTracing(self): assert self.is_tracing_running, 'Can only stop tracing when tracing is on.' trace_data_builder = trace_data_module.TraceDataBuilder() raised_execption_messages = [] for agent in self._active_agents_instances: try: - agent.Stop(trace_data_builder) + agent.StopAgentTracing(trace_data_builder) except Exception: raised_execption_messages.append( ''.join(traceback.format_exception(*sys.exc_info()))) @@ -82,6 +82,26 @@ return trace_data_builder.AsData() + def StartAgentTracing(self, config, timeout): + # TODO(rnephew): Used when implementing clock sync. + pass + + def StopAgentTracing(self, trace_data_builder): + # TODO(rnephew) Used when implementing clock sync. + pass + + def SupportsExplicitClockSync(self): + return False + + def RecordClockSyncMarker(self, sync_id): + """ Record clock sync event. + + Args: + sync_id: Unqiue id for sync event. + """ + # TODO(rnephew): Implement clock sync for trace controller. + del sync_id # unused + def IsChromeTracingSupported(self): return chrome_tracing_agent.ChromeTracingAgent.IsSupported( self._platform_backend)
diff --git a/tools/telemetry/telemetry/testing/page_test_test_case.py b/tools/telemetry/telemetry/testing/page_test_test_case.py index 233d6d3..ef8c372e 100644 --- a/tools/telemetry/telemetry/testing/page_test_test_case.py +++ b/tools/telemetry/telemetry/testing/page_test_test_case.py
@@ -81,19 +81,19 @@ # Inject fake tracing methods to tracing_controller def TabForPage(self, page, browser): - ActualStartTracing = browser.platform.tracing_controller.Start + ActualStartTracing = browser.platform.tracing_controller.StartTracing def FakeStartTracing(*args, **kwargs): ActualStartTracing(*args, **kwargs) start_tracing_called[0] = True raise exceptions.IntentionalException browser.StartTracing = FakeStartTracing - ActualStopTracing = browser.platform.tracing_controller.Stop + ActualStopTracing = browser.platform.tracing_controller.StopTracing def FakeStopTracing(*args, **kwargs): result = ActualStopTracing(*args, **kwargs) stop_tracing_called[0] = True return result - browser.platform.tracing_controller.Stop = FakeStopTracing + browser.platform.tracing_controller.StopTracing = FakeStopTracing return measurement_class.TabForPage(self, page, browser)
diff --git a/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py b/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py index 4118d3f..5796b9dc 100644 --- a/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py +++ b/tools/telemetry/telemetry/web_perf/smooth_gesture_util_unittest.py
@@ -128,12 +128,12 @@ del page # unused config = tracing_config.TracingConfig() config.enable_chrome_trace = True - tab.browser.platform.tracing_controller.Start(config) + tab.browser.platform.tracing_controller.StartTracing(config) def ValidateAndMeasurePage(self, page, tab, results): del page, results # unused models.append(model_module.TimelineModel( - tab.browser.platform.tracing_controller.Stop())) + tab.browser.platform.tracing_controller.StopTracing())) tab_ids.append(tab.id) self.RunMeasurement(ScrollingGestureTestMeasurement(), ps)
diff --git a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py index da7dba41..f208d3f 100644 --- a/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py +++ b/tools/telemetry/telemetry/web_perf/timeline_based_measurement.py
@@ -250,11 +250,11 @@ """Configure and start tracing.""" if not platform.tracing_controller.IsChromeTracingSupported(): raise Exception('Not supported') - platform.tracing_controller.Start(self._tbm_options.config) + platform.tracing_controller.StartTracing(self._tbm_options.config) def Measure(self, platform, results): """Collect all possible metrics and added them to results.""" - trace_result = platform.tracing_controller.Stop() + trace_result = platform.tracing_controller.StopTracing() results.AddValue(trace.TraceValue(results.current_page, trace_result)) model = model_module.TimelineModel(trace_result) threads_to_records_map = _GetRendererThreadsToInteractionRecordsMap(model) @@ -281,4 +281,4 @@ def DidRunStory(self, platform): """Clean up after running the story.""" if platform.tracing_controller.is_tracing_running: - platform.tracing_controller.Stop() + platform.tracing_controller.StopTracing()
diff --git a/ui/events/BUILD.gn b/ui/events/BUILD.gn index a1a65aee..5c557289 100644 --- a/ui/events/BUILD.gn +++ b/ui/events/BUILD.gn
@@ -142,7 +142,11 @@ ] if (use_x11) { - sources += [ "x/events_x.cc" ] + sources += [ + "x/events_x.cc", + "x/events_x_utils.cc", + "x/events_x_utils.h", + ] configs += [ "//build/config/linux:glib", "//build/config/linux:x11",
diff --git a/ui/events/events.gyp b/ui/events/events.gyp index 757324b..dd83a60e 100644 --- a/ui/events/events.gyp +++ b/ui/events/events.gyp
@@ -153,6 +153,8 @@ 'win/system_event_state_lookup.cc', 'win/system_event_state_lookup.h', 'x/events_x.cc', + 'x/events_x_utils.cc', + 'x/events_x_utils.h', ], 'conditions': [ ['use_x11==1', {
diff --git a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc index 7b31771..ed59617 100644 --- a/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc +++ b/ui/events/ozone/layout/xkb/xkb_keyboard_layout_engine_unittest.cc
@@ -245,7 +245,7 @@ // plus sign, question mark, unmapped /* 37 */ {{0x002B, 0x003F, 0x2461, DomCode::MINUS}, VKEY_OEM_PLUS}, // plus sign, question mark, reverse solidus - /* 38 */ {{0x002B, 0x003F, 0x005C, DomCode::MINUS}, VKEY_OEM_MINUS}, + /* 38 */ {{0x002B, 0x003F, 0x005C, DomCode::MINUS}, VKEY_OEM_PLUS}, // plus sign, question mark, o double acute /* 39 */ {{0x002B, 0x003F, 0x0151, DomCode::MINUS}, VKEY_OEM_PLUS}, // plus sign, *, *
diff --git a/ui/events/x/events_x.cc b/ui/events/x/events_x.cc index 2674d5a..647b55b 100644 --- a/ui/events/x/events_x.cc +++ b/ui/events/x/events_x.cc
@@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "ui/events/event_constants.h" +#include "ui/events/event_utils.h" #include <stddef.h> #include <string.h> @@ -13,7 +13,6 @@ #include <X11/Xutil.h> #include <cmath> -#include "base/logging.h" #include "base/macros.h" #include "base/memory/singleton.h" #include "build/build_config.h" @@ -21,295 +20,33 @@ #include "ui/events/devices/x11/device_list_cache_x11.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/event.h" -#include "ui/events/event_utils.h" +#include "ui/events/event_constants.h" #include "ui/events/keycodes/keyboard_code_conversion_x.h" +#include "ui/events/x/events_x_utils.h" #include "ui/gfx/display.h" #include "ui/gfx/geometry/point.h" -#include "ui/gfx/geometry/rect.h" #include "ui/gfx/screen.h" #include "ui/gfx/x/x11_atom_cache.h" #include "ui/gfx/x/x11_types.h" namespace { -// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. -const int kWheelScrollAmount = 53; - -const int kMinWheelButton = 4; -const int kMaxWheelButton = 7; - -// A class to track current modifier state on master device. Only track ctrl, -// alt, shift and caps lock keys currently. The tracked state can then be used -// by floating device. -class XModifierStateWatcher{ - public: - static XModifierStateWatcher* GetInstance() { - return base::Singleton<XModifierStateWatcher>::get(); - } - - int StateFromKeyboardCode(ui::KeyboardCode keyboard_code) { - switch (keyboard_code) { - case ui::VKEY_CONTROL: - return ControlMask; - case ui::VKEY_SHIFT: - return ShiftMask; - case ui::VKEY_MENU: - return Mod1Mask; - case ui::VKEY_CAPITAL: - return LockMask; - default: - return 0; - } - } - - void UpdateStateFromXEvent(const base::NativeEvent& native_event) { - ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event); - unsigned int mask = StateFromKeyboardCode(keyboard_code); - // Floating device can't access the modifer state from master device. - // We need to track the states of modifier keys in a singleton for - // floating devices such as touch screen. Issue 106426 is one example - // of why we need the modifier states for floating device. - switch (native_event->type) { - case KeyPress: - state_ = native_event->xkey.state | mask; - break; - case KeyRelease: - state_ = native_event->xkey.state & ~mask; - break; - case GenericEvent: { - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - switch (xievent->evtype) { - case XI_KeyPress: - state_ = xievent->mods.effective |= mask; - break; - case XI_KeyRelease: - state_ = xievent->mods.effective &= ~mask; - break; - default: - NOTREACHED(); - break; - } - break; - } - default: - NOTREACHED(); - break; - } - } - - // Returns the current modifer state in master device. It only contains the - // state of ctrl, shift, alt and caps lock keys. - unsigned int state() { return state_; } - - private: - friend struct base::DefaultSingletonTraits<XModifierStateWatcher>; - - XModifierStateWatcher() : state_(0) { } - - unsigned int state_; - - DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher); -}; - -// Detects if a touch event is a driver-generated 'special event'. -// A 'special event' is a touch event with maximum radius and pressure at -// location (0, 0). -// This needs to be done in a cleaner way: http://crbug.com/169256 -bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) { - XIDeviceEvent* event = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - CHECK(event->evtype == XI_TouchBegin || - event->evtype == XI_TouchUpdate || - event->evtype == XI_TouchEnd); - - // Force is normalized to [0, 1]. - if (ui::GetTouchForce(native_event) < 1.0f) - return false; - - if (ui::EventLocationFromNative(native_event) != gfx::Point()) - return false; - - // Radius is in pixels, and the valuator is the diameter in pixels. - double radius = ui::GetTouchRadiusX(native_event), min, max; - unsigned int deviceid = - static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; - if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange( - deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) { - return false; - } - - return radius * 2 == max; -} - -int GetEventFlagsFromXState(unsigned int state) { - int flags = 0; - if (state & ShiftMask) - flags |= ui::EF_SHIFT_DOWN; - if (state & LockMask) - flags |= ui::EF_CAPS_LOCK_ON; - if (state & ControlMask) - flags |= ui::EF_CONTROL_DOWN; - if (state & Mod1Mask) - flags |= ui::EF_ALT_DOWN; - if (state & Mod2Mask) - flags |= ui::EF_NUM_LOCK_ON; - if (state & Mod3Mask) - flags |= ui::EF_MOD3_DOWN; - if (state & Mod4Mask) - flags |= ui::EF_COMMAND_DOWN; - if (state & Mod5Mask) - flags |= ui::EF_ALTGR_DOWN; - if (state & Button1Mask) - flags |= ui::EF_LEFT_MOUSE_BUTTON; - if (state & Button2Mask) - flags |= ui::EF_MIDDLE_MOUSE_BUTTON; - if (state & Button3Mask) - flags |= ui::EF_RIGHT_MOUSE_BUTTON; - // There are no masks for EF_BACK_MOUSE_BUTTON and - // EF_FORWARD_MOUSE_BUTTON. - return flags; -} - -int GetEventFlagsFromXKeyEvent(XEvent* xevent) { - DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease); - -#if defined(OS_CHROMEOS) - const int ime_fabricated_flag = 0; -#else - // XIM fabricates key events for the character compositions by XK_Multi_key. - // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in - // order to input "é", then XIM generates a key event with keycode=0 and - // state=0 for the composition, and the sequence of X11 key events will be - // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used - // shift key and/or caps lock key, state can be ShiftMask, LockMask or both. - // - // We have to send these fabricated key events to XIM so it can correctly - // handle the character compositions. - const unsigned int shift_lock_mask = ShiftMask | LockMask; - const bool fabricated_by_xim = - xevent->xkey.keycode == 0 && - (xevent->xkey.state & ~shift_lock_mask) == 0; - const int ime_fabricated_flag = - fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0; -#endif - - return GetEventFlagsFromXState(xevent->xkey.state) | - (xevent->xkey.send_event ? ui::EF_FINAL : 0) | - ime_fabricated_flag; -} - -int GetEventFlagsFromXGenericEvent(XEvent* xevent) { - DCHECK(xevent->type == GenericEvent); - XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data); - DCHECK((xievent->evtype == XI_KeyPress) || - (xievent->evtype == XI_KeyRelease)); - return GetEventFlagsFromXState(xievent->mods.effective) | - (xevent->xkey.send_event ? ui::EF_FINAL : 0); -} - -// Get the event flag for the button in XButtonEvent. During a ButtonPress -// event, |state| in XButtonEvent does not include the button that has just been -// pressed. Instead |state| contains flags for the buttons (if any) that had -// already been pressed before the current button, and |button| stores the most -// current pressed button. So, if you press down left mouse button, and while -// pressing it down, press down the right mouse button, then for the latter -// event, |state| would have Button1Mask set but not Button3Mask, and |button| -// would be 3. -int GetEventFlagsForButton(int button) { - switch (button) { - case 1: - return ui::EF_LEFT_MOUSE_BUTTON; - case 2: - return ui::EF_MIDDLE_MOUSE_BUTTON; - case 3: - return ui::EF_RIGHT_MOUSE_BUTTON; - case 8: - return ui::EF_BACK_MOUSE_BUTTON; - case 9: - return ui::EF_FORWARD_MOUSE_BUTTON; - default: - return 0; - } -} - -int GetButtonMaskForX2Event(XIDeviceEvent* xievent) { - int buttonflags = 0; - for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) { - if (XIMaskIsSet(xievent->buttons.mask, i)) { - int button = (xievent->sourceid == xievent->deviceid) ? - ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) : i; - buttonflags |= GetEventFlagsForButton(button); - } - } - return buttonflags; -} - -ui::EventType GetTouchEventType(const base::NativeEvent& native_event) { - XIDeviceEvent* event = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - switch(event->evtype) { - case XI_TouchBegin: - return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN : - ui::ET_TOUCH_PRESSED; - case XI_TouchUpdate: - return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN : - ui::ET_TOUCH_MOVED; - case XI_TouchEnd: - return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED : - ui::ET_TOUCH_RELEASED; - } - - DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid)); - switch (event->evtype) { - case XI_ButtonPress: - return ui::ET_TOUCH_PRESSED; - case XI_ButtonRelease: - return ui::ET_TOUCH_RELEASED; - case XI_Motion: - // Should not convert any emulated Motion event from touch device to - // touch event. - if (!(event->flags & XIPointerEmulated) && - GetButtonMaskForX2Event(event)) - return ui::ET_TOUCH_MOVED; - return ui::ET_UNKNOWN; - default: - NOTREACHED(); - } - return ui::ET_UNKNOWN; -} - -double GetTouchParamFromXEvent(XEvent* xev, - ui::DeviceDataManagerX11::DataType val, - double default_value) { - ui::DeviceDataManagerX11::GetInstance()->GetEventData( - *xev, val, &default_value); - return default_value; -} - -void ScaleTouchRadius(XEvent* xev, double* radius) { - DCHECK_EQ(GenericEvent, xev->type); - XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data); - ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale( - xiev->sourceid, radius); -} - unsigned int UpdateX11EventFlags(int ui_flags, unsigned int old_x_flags) { static struct { int ui; int x; } flags[] = { - {ui::EF_SHIFT_DOWN, ShiftMask}, - {ui::EF_CAPS_LOCK_ON, LockMask}, - {ui::EF_CONTROL_DOWN, ControlMask}, - {ui::EF_ALT_DOWN, Mod1Mask}, - {ui::EF_NUM_LOCK_ON, Mod2Mask}, - {ui::EF_MOD3_DOWN, Mod3Mask}, - {ui::EF_COMMAND_DOWN, Mod4Mask}, - {ui::EF_ALTGR_DOWN, Mod5Mask}, - {ui::EF_LEFT_MOUSE_BUTTON, Button1Mask}, - {ui::EF_MIDDLE_MOUSE_BUTTON, Button2Mask}, - {ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask}, + {ui::EF_SHIFT_DOWN, ShiftMask}, + {ui::EF_CAPS_LOCK_ON, LockMask}, + {ui::EF_CONTROL_DOWN, ControlMask}, + {ui::EF_ALT_DOWN, Mod1Mask}, + {ui::EF_NUM_LOCK_ON, Mod2Mask}, + {ui::EF_MOD3_DOWN, Mod3Mask}, + {ui::EF_COMMAND_DOWN, Mod4Mask}, + {ui::EF_ALTGR_DOWN, Mod5Mask}, + {ui::EF_LEFT_MOUSE_BUTTON, Button1Mask}, + {ui::EF_MIDDLE_MOUSE_BUTTON, Button2Mask}, + {ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask}, }; unsigned int new_x_flags = old_x_flags; for (size_t i = 0; i < arraysize(flags); ++i) { @@ -335,23 +72,6 @@ NOTREACHED(); } -bool GetGestureTimes(const base::NativeEvent& native_event, - double* start_time, - double* end_time) { - if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(*native_event)) - return false; - - double start_time_, end_time_; - if (!start_time) - start_time = &start_time_; - if (!end_time) - end_time = &end_time_; - - ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes( - *native_event, start_time, end_time); - return true; -} - } // namespace namespace ui { @@ -364,288 +84,28 @@ } EventType EventTypeFromNative(const base::NativeEvent& native_event) { - // Allow the DeviceDataManager to block the event. If blocked return - // ET_UNKNOWN as the type so this event will not be further processed. - // NOTE: During some events unittests there is no device data manager. - if (DeviceDataManager::HasInstance() && - static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance()) - ->IsEventBlocked(*native_event)) { - return ET_UNKNOWN; - } - - switch (native_event->type) { - case KeyPress: - return ET_KEY_PRESSED; - case KeyRelease: - return ET_KEY_RELEASED; - case ButtonPress: - if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && - static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) - return ET_MOUSEWHEEL; - return ET_MOUSE_PRESSED; - case ButtonRelease: - // Drop wheel events; we should've already scrolled on the press. - if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && - static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) - return ET_UNKNOWN; - return ET_MOUSE_RELEASED; - case MotionNotify: - if (native_event->xmotion.state & - (Button1Mask | Button2Mask | Button3Mask)) - return ET_MOUSE_DRAGGED; - return ET_MOUSE_MOVED; - case EnterNotify: - // The standard on Windows is to send a MouseMove event when the mouse - // first enters a window instead of sending a special mouse enter event. - // To be consistent we follow the same style. - return ET_MOUSE_MOVED; - case LeaveNotify: - return ET_MOUSE_EXITED; - case GenericEvent: { - TouchFactory* factory = TouchFactory::GetInstance(); - if (!factory->ShouldProcessXI2Event(native_event)) - return ET_UNKNOWN; - - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - - // This check works only for master and floating slave devices. That is - // why it is necessary to check for the XI_Touch* events in the following - // switch statement to account for attached-slave touchscreens. - if (factory->IsTouchDevice(xievent->sourceid)) - return GetTouchEventType(native_event); - - switch (xievent->evtype) { - case XI_TouchBegin: - return ui::ET_TOUCH_PRESSED; - case XI_TouchUpdate: - return ui::ET_TOUCH_MOVED; - case XI_TouchEnd: - return ui::ET_TOUCH_RELEASED; - case XI_ButtonPress: { - int button = EventButtonFromNative(native_event); - if (button >= kMinWheelButton && button <= kMaxWheelButton) - return ET_MOUSEWHEEL; - return ET_MOUSE_PRESSED; - } - case XI_ButtonRelease: { - int button = EventButtonFromNative(native_event); - // Drop wheel events; we should've already scrolled on the press. - if (button >= kMinWheelButton && button <= kMaxWheelButton) - return ET_UNKNOWN; - return ET_MOUSE_RELEASED; - } - case XI_Motion: { - bool is_cancel; - DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance(); - if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel)) - return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START; - if (devices->IsScrollEvent(*native_event)) { - return devices->IsTouchpadXInputEvent(*native_event) - ? ET_SCROLL - : ET_MOUSEWHEEL; - } - if (devices->GetScrollClassEventDetail(*native_event) != - SCROLL_TYPE_NO_SCROLL) - return ET_MOUSEWHEEL; - if (devices->IsCMTMetricsEvent(*native_event)) - return ET_UMA_DATA; - if (GetButtonMaskForX2Event(xievent)) - return ET_MOUSE_DRAGGED; - if (DeviceDataManagerX11::GetInstance()->HasEventData( - xievent, DeviceDataManagerX11::DT_CMT_SCROLL_X) || - DeviceDataManagerX11::GetInstance()->HasEventData( - xievent, DeviceDataManagerX11::DT_CMT_SCROLL_Y)) { - // Don't produce mouse move events for mousewheel scrolls. - return ET_UNKNOWN; - } - - return ET_MOUSE_MOVED; - } - case XI_KeyPress: - return ET_KEY_PRESSED; - case XI_KeyRelease: - return ET_KEY_RELEASED; - } - } - default: - break; - } - return ET_UNKNOWN; + return EventTypeFromXEvent(*native_event); } int EventFlagsFromNative(const base::NativeEvent& native_event) { - switch (native_event->type) { - case KeyPress: - case KeyRelease: { - XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event); - return GetEventFlagsFromXKeyEvent(native_event); - } - case ButtonPress: - case ButtonRelease: { - int flags = GetEventFlagsFromXState(native_event->xbutton.state); - const EventType type = EventTypeFromNative(native_event); - if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) - flags |= GetEventFlagsForButton(native_event->xbutton.button); - return flags; - } - case EnterNotify: - case LeaveNotify: - return GetEventFlagsFromXState(native_event->xcrossing.state); - case MotionNotify: - return GetEventFlagsFromXState(native_event->xmotion.state); - case GenericEvent: { - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - - switch (xievent->evtype) { - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - return GetButtonMaskForX2Event(xievent) | - GetEventFlagsFromXState(xievent->mods.effective) | - GetEventFlagsFromXState( - XModifierStateWatcher::GetInstance()->state()); - break; - case XI_ButtonPress: - case XI_ButtonRelease: { - const bool touch = - TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid); - int flags = GetButtonMaskForX2Event(xievent) | - GetEventFlagsFromXState(xievent->mods.effective); - if (touch) { - flags |= GetEventFlagsFromXState( - XModifierStateWatcher::GetInstance()->state()); - } - - const EventType type = EventTypeFromNative(native_event); - int button = EventButtonFromNative(native_event); - if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch) - flags |= GetEventFlagsForButton(button); - return flags; - } - case XI_Motion: - return GetButtonMaskForX2Event(xievent) | - GetEventFlagsFromXState(xievent->mods.effective); - case XI_KeyPress: - case XI_KeyRelease: { - XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent( - native_event); - return GetEventFlagsFromXGenericEvent(native_event); - } - } - } - } - return 0; + return EventFlagsFromXEvent(*native_event); } base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { - switch(native_event->type) { - case KeyPress: - case KeyRelease: - return base::TimeDelta::FromMilliseconds(native_event->xkey.time); - case ButtonPress: - case ButtonRelease: - return base::TimeDelta::FromMilliseconds(native_event->xbutton.time); - break; - case MotionNotify: - return base::TimeDelta::FromMilliseconds(native_event->xmotion.time); - break; - case EnterNotify: - case LeaveNotify: - return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time); - break; - case GenericEvent: { - double start, end; - double touch_timestamp; - if (GetGestureTimes(native_event, &start, &end)) { - // If the driver supports gesture times, use them. - return base::TimeDelta::FromMicroseconds(end * 1000000); - } else if (DeviceDataManagerX11::GetInstance()->GetEventData( - *native_event, - DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP, - &touch_timestamp)) { - return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000); - } else { - XIDeviceEvent* xide = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - return base::TimeDelta::FromMilliseconds(xide->time); - } - break; - } - } - NOTREACHED(); - return base::TimeDelta(); + return EventTimeFromXEvent(*native_event); } gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) { - switch (native_event->type) { - case EnterNotify: - case LeaveNotify: - return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y); - case ButtonPress: - case ButtonRelease: - return gfx::Point(native_event->xbutton.x, native_event->xbutton.y); - case MotionNotify: - return gfx::Point(native_event->xmotion.x, native_event->xmotion.y); - case GenericEvent: { - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - float x = xievent->event_x; - float y = xievent->event_y; -#if defined(OS_CHROMEOS) - switch (xievent->evtype) { - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: - ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer( - xievent->deviceid, &x, &y); - break; - default: - break; - } -#endif // defined(OS_CHROMEOS) - return gfx::Point(static_cast<int>(x), static_cast<int>(y)); - } - } - return gfx::Point(); + return EventLocationFromXEvent(*native_event); } gfx::Point EventSystemLocationFromNative( const base::NativeEvent& native_event) { - switch (native_event->type) { - case EnterNotify: - case LeaveNotify: { - return gfx::Point(native_event->xcrossing.x_root, - native_event->xcrossing.y_root); - } - case ButtonPress: - case ButtonRelease: { - return gfx::Point(native_event->xbutton.x_root, - native_event->xbutton.y_root); - } - case MotionNotify: { - return gfx::Point(native_event->xmotion.x_root, - native_event->xmotion.y_root); - } - case GenericEvent: { - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - return gfx::Point(xievent->root_x, xievent->root_y); - } - } - - return gfx::Point(); + return EventSystemLocationFromXEvent(*native_event); } int EventButtonFromNative(const base::NativeEvent& native_event) { - CHECK_EQ(GenericEvent, native_event->type); - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - int button = xievent->detail; - - return (xievent->sourceid == xievent->deviceid) ? - DeviceDataManagerX11::GetInstance()->GetMappedButton(button) : button; + return EventButtonFromXEvent(*native_event); } KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { @@ -662,127 +122,52 @@ int GetChangedMouseButtonFlagsFromNative( const base::NativeEvent& native_event) { - switch (native_event->type) { - case ButtonPress: - case ButtonRelease: - return GetEventFlagsForButton(native_event->xbutton.button); - case GenericEvent: { - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - switch (xievent->evtype) { - case XI_ButtonPress: - case XI_ButtonRelease: - return GetEventFlagsForButton(EventButtonFromNative(native_event)); - default: - break; - } - } - default: - break; - } - return 0; + return GetChangedMouseButtonFlagsFromXEvent(*native_event); } PointerDetails GetMousePointerDetailsFromNative( const base::NativeEvent& native_event) { - return PointerDetails(EventPointerType::POINTER_TYPE_MOUSE); + return GetMousePointerDetailsFromXEvent(*native_event); } gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) { - float x_offset, y_offset; - if (GetScrollOffsets( - native_event, &x_offset, &y_offset, NULL, NULL, NULL)) { - return gfx::Vector2d(static_cast<int>(x_offset), - static_cast<int>(y_offset)); - } - - int button = native_event->type == GenericEvent ? - EventButtonFromNative(native_event) : native_event->xbutton.button; - - switch (button) { - case 4: - return gfx::Vector2d(0, kWheelScrollAmount); - case 5: - return gfx::Vector2d(0, -kWheelScrollAmount); - case 6: - return gfx::Vector2d(kWheelScrollAmount, 0); - case 7: - return gfx::Vector2d(-kWheelScrollAmount, 0); - default: - return gfx::Vector2d(); - } + return GetMouseWheelOffsetFromXEvent(*native_event); } -base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) { - if (!event || event->type == GenericEvent) +base::NativeEvent CopyNativeEvent(const base::NativeEvent& native_event) { + if (!native_event || native_event->type == GenericEvent) return NULL; XEvent* copy = new XEvent; - *copy = *event; + *copy = *native_event; return copy; } -void ReleaseCopiedNativeEvent(const base::NativeEvent& event) { - delete event; +void ReleaseCopiedNativeEvent(const base::NativeEvent& native_event) { + delete native_event; } -void ClearTouchIdIfReleased(const base::NativeEvent& xev) { - ui::EventType type = ui::EventTypeFromNative(xev); - if (type == ui::ET_TOUCH_CANCELLED || - type == ui::ET_TOUCH_RELEASED) { - ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); - ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); - double tracking_id; - if (manager->GetEventData( - *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) { - factory->ReleaseSlotForTrackingID(tracking_id); - } - } +void ClearTouchIdIfReleased(const base::NativeEvent& native_event) { + ClearTouchIdIfReleasedFromXEvent(*native_event); } -int GetTouchId(const base::NativeEvent& xev) { - double slot = 0; - ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); - double tracking_id; - if (!manager->GetEventData( - *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) { - LOG(ERROR) << "Could not get the tracking ID for the event. Using 0."; - } else { - ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); - slot = factory->GetSlotForTrackingID(tracking_id); - } - return slot; +int GetTouchId(const base::NativeEvent& native_event) { + return GetTouchIdFromXEvent(*native_event); } float GetTouchRadiusX(const base::NativeEvent& native_event) { - double radius = GetTouchParamFromXEvent(native_event, - ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0; - ScaleTouchRadius(native_event, &radius); - return radius; + return GetTouchRadiusXFromXEvent(*native_event); } float GetTouchRadiusY(const base::NativeEvent& native_event) { - double radius = GetTouchParamFromXEvent(native_event, - ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0; - ScaleTouchRadius(native_event, &radius); - return radius; + return GetTouchRadiusYFromXEvent(*native_event); } float GetTouchAngle(const base::NativeEvent& native_event) { - return GetTouchParamFromXEvent(native_event, - ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / 2.0; + return GetTouchAngleFromXEvent(*native_event); } float GetTouchForce(const base::NativeEvent& native_event) { - double force = 0.0; - force = GetTouchParamFromXEvent(native_event, - ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0); - unsigned int deviceid = - static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; - // Force is normalized to fall into [0, 1] - if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData( - deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force)) - force = 0.0; - return force; + return GetTouchForceFromXEvent(*native_event); } bool GetScrollOffsets(const base::NativeEvent& native_event, @@ -791,38 +176,9 @@ float* x_offset_ordinal, float* y_offset_ordinal, int* finger_count) { - if (DeviceDataManagerX11::GetInstance()->IsScrollEvent(*native_event)) { - // Temp values to prevent passing NULLs to DeviceDataManager. - float x_offset_, y_offset_; - float x_offset_ordinal_, y_offset_ordinal_; - int finger_count_; - if (!x_offset) - x_offset = &x_offset_; - if (!y_offset) - y_offset = &y_offset_; - if (!x_offset_ordinal) - x_offset_ordinal = &x_offset_ordinal_; - if (!y_offset_ordinal) - y_offset_ordinal = &y_offset_ordinal_; - if (!finger_count) - finger_count = &finger_count_; - - DeviceDataManagerX11::GetInstance()->GetScrollOffsets( - *native_event, x_offset, y_offset, x_offset_ordinal, y_offset_ordinal, - finger_count); - return true; - } - - if (DeviceDataManagerX11::GetInstance()->GetScrollClassDeviceDetail( - *native_event) != SCROLL_TYPE_NO_SCROLL) { - double x_scroll_offset, y_scroll_offset; - DeviceDataManagerX11::GetInstance()->GetScrollClassOffsets( - *native_event, &x_scroll_offset, &y_scroll_offset); - *x_offset = x_scroll_offset * kWheelScrollAmount; - *y_offset = y_scroll_offset * kWheelScrollAmount; - return true; - } - return false; + return GetScrollOffsetsFromXEvent(*native_event, x_offset, y_offset, + x_offset_ordinal, y_offset_ordinal, + finger_count); } bool GetFlingData(const base::NativeEvent& native_event, @@ -831,26 +187,8 @@ float* vx_ordinal, float* vy_ordinal, bool* is_cancel) { - if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(*native_event)) - return false; - - float vx_, vy_; - float vx_ordinal_, vy_ordinal_; - bool is_cancel_; - if (!vx) - vx = &vx_; - if (!vy) - vy = &vy_; - if (!vx_ordinal) - vx_ordinal = &vx_ordinal_; - if (!vy_ordinal) - vy_ordinal = &vy_ordinal_; - if (!is_cancel) - is_cancel = &is_cancel_; - - DeviceDataManagerX11::GetInstance()->GetFlingData( - *native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel); - return true; + return GetFlingDataFromXEvent(*native_event, vx, vy, vx_ordinal, vy_ordinal, + is_cancel); } void UpdateX11EventForFlags(Event* event) {
diff --git a/ui/events/x/events_x_utils.cc b/ui/events/x/events_x_utils.cc new file mode 100644 index 0000000..c79266ee --- /dev/null +++ b/ui/events/x/events_x_utils.cc
@@ -0,0 +1,760 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ui/events/x/events_x_utils.h" + +#include <stddef.h> +#include <string.h> +#include <X11/extensions/XInput.h> +#include <X11/extensions/XInput2.h> +#include <X11/XKBlib.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <cmath> + +#include "base/logging.h" +#include "base/macros.h" +#include "base/memory/singleton.h" +#include "build/build_config.h" +#include "ui/events/devices/x11/device_data_manager_x11.h" +#include "ui/events/devices/x11/device_list_cache_x11.h" +#include "ui/events/devices/x11/touch_factory_x11.h" +#include "ui/events/keycodes/keyboard_code_conversion_x.h" +#include "ui/gfx/display.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/screen.h" +#include "ui/gfx/x/x11_atom_cache.h" +#include "ui/gfx/x/x11_types.h" + +namespace { + +// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. +const int kWheelScrollAmount = 53; + +const int kMinWheelButton = 4; +const int kMaxWheelButton = 7; + +// A class to track current modifier state on master device. Only track ctrl, +// alt, shift and caps lock keys currently. The tracked state can then be used +// by floating device. +class XModifierStateWatcher { + public: + static XModifierStateWatcher* GetInstance() { + return base::Singleton<XModifierStateWatcher>::get(); + } + + int StateFromKeyboardCode(ui::KeyboardCode keyboard_code) { + switch (keyboard_code) { + case ui::VKEY_CONTROL: + return ControlMask; + case ui::VKEY_SHIFT: + return ShiftMask; + case ui::VKEY_MENU: + return Mod1Mask; + case ui::VKEY_CAPITAL: + return LockMask; + default: + return 0; + } + } + + void UpdateStateFromXEvent(const XEvent& xev) { + ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromXKeyEvent(&xev); + unsigned int mask = StateFromKeyboardCode(keyboard_code); + // Floating device can't access the modifer state from master device. + // We need to track the states of modifier keys in a singleton for + // floating devices such as touch screen. Issue 106426 is one example + // of why we need the modifier states for floating device. + switch (xev.type) { + case KeyPress: + state_ = xev.xkey.state | mask; + break; + case KeyRelease: + state_ = xev.xkey.state & ~mask; + break; + case GenericEvent: { + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); + switch (xievent->evtype) { + case XI_KeyPress: + state_ = xievent->mods.effective |= mask; + break; + case XI_KeyRelease: + state_ = xievent->mods.effective &= ~mask; + break; + default: + NOTREACHED(); + break; + } + break; + } + default: + NOTREACHED(); + break; + } + } + + // Returns the current modifer state in master device. It only contains the + // state of ctrl, shift, alt and caps lock keys. + unsigned int state() { return state_; } + + private: + friend struct base::DefaultSingletonTraits<XModifierStateWatcher>; + + XModifierStateWatcher() : state_(0) {} + + unsigned int state_; + + DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher); +}; + +// Detects if a touch event is a driver-generated 'special event'. +// A 'special event' is a touch event with maximum radius and pressure at +// location (0, 0). +// This needs to be done in a cleaner way: http://crbug.com/169256 +bool TouchEventIsGeneratedHack(const XEvent& xev) { + XIDeviceEvent* event = static_cast<XIDeviceEvent*>(xev.xcookie.data); + CHECK(event->evtype == XI_TouchBegin || event->evtype == XI_TouchUpdate || + event->evtype == XI_TouchEnd); + + // Force is normalized to [0, 1]. + if (ui::GetTouchForceFromXEvent(xev) < 1.0f) + return false; + + if (ui::EventLocationFromXEvent(xev) != gfx::Point()) + return false; + + // Radius is in pixels, and the valuator is the diameter in pixels. + double radius = ui::GetTouchRadiusXFromXEvent(xev), min, max; + unsigned int deviceid = + static_cast<XIDeviceEvent*>(xev.xcookie.data)->sourceid; + if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange( + deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) { + return false; + } + + return radius * 2 == max; +} + +int GetEventFlagsFromXState(unsigned int state) { + int flags = 0; + if (state & ShiftMask) + flags |= ui::EF_SHIFT_DOWN; + if (state & LockMask) + flags |= ui::EF_CAPS_LOCK_ON; + if (state & ControlMask) + flags |= ui::EF_CONTROL_DOWN; + if (state & Mod1Mask) + flags |= ui::EF_ALT_DOWN; + if (state & Mod2Mask) + flags |= ui::EF_NUM_LOCK_ON; + if (state & Mod3Mask) + flags |= ui::EF_MOD3_DOWN; + if (state & Mod4Mask) + flags |= ui::EF_COMMAND_DOWN; + if (state & Mod5Mask) + flags |= ui::EF_ALTGR_DOWN; + if (state & Button1Mask) + flags |= ui::EF_LEFT_MOUSE_BUTTON; + if (state & Button2Mask) + flags |= ui::EF_MIDDLE_MOUSE_BUTTON; + if (state & Button3Mask) + flags |= ui::EF_RIGHT_MOUSE_BUTTON; + // There are no masks for EF_BACK_MOUSE_BUTTON and + // EF_FORWARD_MOUSE_BUTTON. + return flags; +} + +int GetEventFlagsFromXKeyEvent(const XEvent& xev) { + DCHECK(xev.type == KeyPress || xev.type == KeyRelease); + +#if defined(OS_CHROMEOS) + const int ime_fabricated_flag = 0; +#else + // XIM fabricates key events for the character compositions by XK_Multi_key. + // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in + // order to input "é", then XIM generates a key event with keycode=0 and + // state=0 for the composition, and the sequence of X11 key events will be + // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used + // shift key and/or caps lock key, state can be ShiftMask, LockMask or both. + // + // We have to send these fabricated key events to XIM so it can correctly + // handle the character compositions. + const unsigned int shift_lock_mask = ShiftMask | LockMask; + const bool fabricated_by_xim = + xev.xkey.keycode == 0 && (xev.xkey.state & ~shift_lock_mask) == 0; + const int ime_fabricated_flag = + fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0; +#endif + + return GetEventFlagsFromXState(xev.xkey.state) | + (xev.xkey.send_event ? ui::EF_FINAL : 0) | ime_fabricated_flag; +} + +int GetEventFlagsFromXGenericEvent(const XEvent& xev) { + DCHECK(xev.type == GenericEvent); + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); + DCHECK((xievent->evtype == XI_KeyPress) || + (xievent->evtype == XI_KeyRelease)); + return GetEventFlagsFromXState(xievent->mods.effective) | + (xev.xkey.send_event ? ui::EF_FINAL : 0); +} + +// Get the event flag for the button in XButtonEvent. During a ButtonPress +// event, |state| in XButtonEvent does not include the button that has just been +// pressed. Instead |state| contains flags for the buttons (if any) that had +// already been pressed before the current button, and |button| stores the most +// current pressed button. So, if you press down left mouse button, and while +// pressing it down, press down the right mouse button, then for the latter +// event, |state| would have Button1Mask set but not Button3Mask, and |button| +// would be 3. +int GetEventFlagsForButton(int button) { + switch (button) { + case 1: + return ui::EF_LEFT_MOUSE_BUTTON; + case 2: + return ui::EF_MIDDLE_MOUSE_BUTTON; + case 3: + return ui::EF_RIGHT_MOUSE_BUTTON; + case 8: + return ui::EF_BACK_MOUSE_BUTTON; + case 9: + return ui::EF_FORWARD_MOUSE_BUTTON; + default: + return 0; + } +} + +int GetButtonMaskForX2Event(XIDeviceEvent* xievent) { + int buttonflags = 0; + for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) { + if (XIMaskIsSet(xievent->buttons.mask, i)) { + int button = + (xievent->sourceid == xievent->deviceid) + ? ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) + : i; + buttonflags |= GetEventFlagsForButton(button); + } + } + return buttonflags; +} + +ui::EventType GetTouchEventType(const XEvent& xev) { + XIDeviceEvent* event = static_cast<XIDeviceEvent*>(xev.xcookie.data); + switch (event->evtype) { + case XI_TouchBegin: + return TouchEventIsGeneratedHack(xev) ? ui::ET_UNKNOWN + : ui::ET_TOUCH_PRESSED; + case XI_TouchUpdate: + return TouchEventIsGeneratedHack(xev) ? ui::ET_UNKNOWN + : ui::ET_TOUCH_MOVED; + case XI_TouchEnd: + return TouchEventIsGeneratedHack(xev) ? ui::ET_TOUCH_CANCELLED + : ui::ET_TOUCH_RELEASED; + } + + DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid)); + switch (event->evtype) { + case XI_ButtonPress: + return ui::ET_TOUCH_PRESSED; + case XI_ButtonRelease: + return ui::ET_TOUCH_RELEASED; + case XI_Motion: + // Should not convert any emulated Motion event from touch device to + // touch event. + if (!(event->flags & XIPointerEmulated) && GetButtonMaskForX2Event(event)) + return ui::ET_TOUCH_MOVED; + return ui::ET_UNKNOWN; + default: + NOTREACHED(); + } + return ui::ET_UNKNOWN; +} + +double GetTouchParamFromXEvent(const XEvent& xev, + ui::DeviceDataManagerX11::DataType val, + double default_value) { + ui::DeviceDataManagerX11::GetInstance()->GetEventData(xev, val, + &default_value); + return default_value; +} + +void ScaleTouchRadius(const XEvent& xev, double* radius) { + DCHECK_EQ(GenericEvent, xev.type); + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); + ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(xiev->sourceid, + radius); +} + +bool GetGestureTimes(const XEvent& xev, double* start_time, double* end_time) { + if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(xev)) + return false; + + double start_time_, end_time_; + if (!start_time) + start_time = &start_time_; + if (!end_time) + end_time = &end_time_; + + ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes(xev, start_time, + end_time); + return true; +} + +} // namespace + +namespace ui { + +EventType EventTypeFromXEvent(const XEvent& xev) { + // Allow the DeviceDataManager to block the event. If blocked return + // ET_UNKNOWN as the type so this event will not be further processed. + // NOTE: During some events unittests there is no device data manager. + if (DeviceDataManager::HasInstance() && + static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance()) + ->IsEventBlocked(xev)) { + return ET_UNKNOWN; + } + + switch (xev.type) { + case KeyPress: + return ET_KEY_PRESSED; + case KeyRelease: + return ET_KEY_RELEASED; + case ButtonPress: + if (static_cast<int>(xev.xbutton.button) >= kMinWheelButton && + static_cast<int>(xev.xbutton.button) <= kMaxWheelButton) + return ET_MOUSEWHEEL; + return ET_MOUSE_PRESSED; + case ButtonRelease: + // Drop wheel events; we should've already scrolled on the press. + if (static_cast<int>(xev.xbutton.button) >= kMinWheelButton && + static_cast<int>(xev.xbutton.button) <= kMaxWheelButton) + return ET_UNKNOWN; + return ET_MOUSE_RELEASED; + case MotionNotify: + if (xev.xmotion.state & (Button1Mask | Button2Mask | Button3Mask)) + return ET_MOUSE_DRAGGED; + return ET_MOUSE_MOVED; + case EnterNotify: + // The standard on Windows is to send a MouseMove event when the mouse + // first enters a window instead of sending a special mouse enter event. + // To be consistent we follow the same style. + return ET_MOUSE_MOVED; + case LeaveNotify: + return ET_MOUSE_EXITED; + case GenericEvent: { + TouchFactory* factory = TouchFactory::GetInstance(); + if (!factory->ShouldProcessXI2Event(const_cast<XEvent*>(&xev))) + return ET_UNKNOWN; + + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); + + // This check works only for master and floating slave devices. That is + // why it is necessary to check for the XI_Touch* events in the following + // switch statement to account for attached-slave touchscreens. + if (factory->IsTouchDevice(xievent->sourceid)) + return GetTouchEventType(xev); + + switch (xievent->evtype) { + case XI_TouchBegin: + return ui::ET_TOUCH_PRESSED; + case XI_TouchUpdate: + return ui::ET_TOUCH_MOVED; + case XI_TouchEnd: + return ui::ET_TOUCH_RELEASED; + case XI_ButtonPress: { + int button = EventButtonFromXEvent(xev); + if (button >= kMinWheelButton && button <= kMaxWheelButton) + return ET_MOUSEWHEEL; + return ET_MOUSE_PRESSED; + } + case XI_ButtonRelease: { + int button = EventButtonFromXEvent(xev); + // Drop wheel events; we should've already scrolled on the press. + if (button >= kMinWheelButton && button <= kMaxWheelButton) + return ET_UNKNOWN; + return ET_MOUSE_RELEASED; + } + case XI_Motion: { + bool is_cancel; + DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance(); + if (GetFlingDataFromXEvent(xev, NULL, NULL, NULL, NULL, &is_cancel)) + return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START; + if (devices->IsScrollEvent(xev)) { + return devices->IsTouchpadXInputEvent(xev) ? ET_SCROLL + : ET_MOUSEWHEEL; + } + if (devices->GetScrollClassEventDetail(xev) != SCROLL_TYPE_NO_SCROLL) + return ET_MOUSEWHEEL; + if (devices->IsCMTMetricsEvent(xev)) + return ET_UMA_DATA; + if (GetButtonMaskForX2Event(xievent)) + return ET_MOUSE_DRAGGED; + if (DeviceDataManagerX11::GetInstance()->HasEventData( + xievent, DeviceDataManagerX11::DT_CMT_SCROLL_X) || + DeviceDataManagerX11::GetInstance()->HasEventData( + xievent, DeviceDataManagerX11::DT_CMT_SCROLL_Y)) { + // Don't produce mouse move events for mousewheel scrolls. + return ET_UNKNOWN; + } + + return ET_MOUSE_MOVED; + } + case XI_KeyPress: + return ET_KEY_PRESSED; + case XI_KeyRelease: + return ET_KEY_RELEASED; + } + } + default: + break; + } + return ET_UNKNOWN; +} + +int EventFlagsFromXEvent(const XEvent& xev) { + switch (xev.type) { + case KeyPress: + case KeyRelease: { + XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(xev); + return GetEventFlagsFromXKeyEvent(xev); + } + case ButtonPress: + case ButtonRelease: { + int flags = GetEventFlagsFromXState(xev.xbutton.state); + const EventType type = EventTypeFromXEvent(xev); + if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) + flags |= GetEventFlagsForButton(xev.xbutton.button); + return flags; + } + case EnterNotify: + case LeaveNotify: + return GetEventFlagsFromXState(xev.xcrossing.state); + case MotionNotify: + return GetEventFlagsFromXState(xev.xmotion.state); + case GenericEvent: { + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); + + switch (xievent->evtype) { + case XI_TouchBegin: + case XI_TouchUpdate: + case XI_TouchEnd: + return GetButtonMaskForX2Event(xievent) | + GetEventFlagsFromXState(xievent->mods.effective) | + GetEventFlagsFromXState( + XModifierStateWatcher::GetInstance()->state()); + break; + case XI_ButtonPress: + case XI_ButtonRelease: { + const bool touch = + TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid); + int flags = GetButtonMaskForX2Event(xievent) | + GetEventFlagsFromXState(xievent->mods.effective); + if (touch) { + flags |= GetEventFlagsFromXState( + XModifierStateWatcher::GetInstance()->state()); + } + + const EventType type = EventTypeFromXEvent(xev); + int button = EventButtonFromXEvent(xev); + if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch) + flags |= GetEventFlagsForButton(button); + return flags; + } + case XI_Motion: + return GetButtonMaskForX2Event(xievent) | + GetEventFlagsFromXState(xievent->mods.effective); + case XI_KeyPress: + case XI_KeyRelease: { + XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(xev); + return GetEventFlagsFromXGenericEvent(xev); + } + } + } + } + return 0; +} + +base::TimeDelta EventTimeFromXEvent(const XEvent& xev) { + switch (xev.type) { + case KeyPress: + case KeyRelease: + return base::TimeDelta::FromMilliseconds(xev.xkey.time); + case ButtonPress: + case ButtonRelease: + return base::TimeDelta::FromMilliseconds(xev.xbutton.time); + break; + case MotionNotify: + return base::TimeDelta::FromMilliseconds(xev.xmotion.time); + break; + case EnterNotify: + case LeaveNotify: + return base::TimeDelta::FromMilliseconds(xev.xcrossing.time); + break; + case GenericEvent: { + double start, end; + double touch_timestamp; + if (GetGestureTimes(xev, &start, &end)) { + // If the driver supports gesture times, use them. + return base::TimeDelta::FromMicroseconds(end * 1000000); + } else if (DeviceDataManagerX11::GetInstance()->GetEventData( + xev, DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP, + &touch_timestamp)) { + return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000); + } else { + XIDeviceEvent* xide = static_cast<XIDeviceEvent*>(xev.xcookie.data); + return base::TimeDelta::FromMilliseconds(xide->time); + } + break; + } + } + NOTREACHED(); + return base::TimeDelta(); +} + +gfx::Point EventLocationFromXEvent(const XEvent& xev) { + switch (xev.type) { + case EnterNotify: + case LeaveNotify: + return gfx::Point(xev.xcrossing.x, xev.xcrossing.y); + case ButtonPress: + case ButtonRelease: + return gfx::Point(xev.xbutton.x, xev.xbutton.y); + case MotionNotify: + return gfx::Point(xev.xmotion.x, xev.xmotion.y); + case GenericEvent: { + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); + float x = xievent->event_x; + float y = xievent->event_y; +#if defined(OS_CHROMEOS) + switch (xievent->evtype) { + case XI_TouchBegin: + case XI_TouchUpdate: + case XI_TouchEnd: + ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer( + xievent->deviceid, &x, &y); + break; + default: + break; + } +#endif // defined(OS_CHROMEOS) + return gfx::Point(static_cast<int>(x), static_cast<int>(y)); + } + } + return gfx::Point(); +} + +gfx::Point EventSystemLocationFromXEvent(const XEvent& xev) { + switch (xev.type) { + case EnterNotify: + case LeaveNotify: { + return gfx::Point(xev.xcrossing.x_root, xev.xcrossing.y_root); + } + case ButtonPress: + case ButtonRelease: { + return gfx::Point(xev.xbutton.x_root, xev.xbutton.y_root); + } + case MotionNotify: { + return gfx::Point(xev.xmotion.x_root, xev.xmotion.y_root); + } + case GenericEvent: { + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); + return gfx::Point(xievent->root_x, xievent->root_y); + } + } + + return gfx::Point(); +} + +int EventButtonFromXEvent(const XEvent& xev) { + CHECK_EQ(GenericEvent, xev.type); + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); + int button = xievent->detail; + + return (xievent->sourceid == xievent->deviceid) + ? DeviceDataManagerX11::GetInstance()->GetMappedButton(button) + : button; +} + +int GetChangedMouseButtonFlagsFromXEvent(const XEvent& xev) { + switch (xev.type) { + case ButtonPress: + case ButtonRelease: + return GetEventFlagsForButton(xev.xbutton.button); + case GenericEvent: { + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev.xcookie.data); + switch (xievent->evtype) { + case XI_ButtonPress: + case XI_ButtonRelease: + return GetEventFlagsForButton(EventButtonFromXEvent(xev)); + default: + break; + } + } + default: + break; + } + return 0; +} + +PointerDetails GetMousePointerDetailsFromXEvent(const XEvent& xev) { + return PointerDetails(EventPointerType::POINTER_TYPE_MOUSE); +} + +gfx::Vector2d GetMouseWheelOffsetFromXEvent(const XEvent& xev) { + float x_offset, y_offset; + if (GetScrollOffsetsFromXEvent(xev, &x_offset, &y_offset, NULL, NULL, NULL)) { + return gfx::Vector2d(static_cast<int>(x_offset), + static_cast<int>(y_offset)); + } + + int button = xev.type == GenericEvent ? EventButtonFromXEvent(xev) + : xev.xbutton.button; + + switch (button) { + case 4: + return gfx::Vector2d(0, kWheelScrollAmount); + case 5: + return gfx::Vector2d(0, -kWheelScrollAmount); + case 6: + return gfx::Vector2d(kWheelScrollAmount, 0); + case 7: + return gfx::Vector2d(-kWheelScrollAmount, 0); + default: + return gfx::Vector2d(); + } +} + +void ClearTouchIdIfReleasedFromXEvent(const XEvent& xev) { + ui::EventType type = ui::EventTypeFromXEvent(xev); + if (type == ui::ET_TOUCH_CANCELLED || type == ui::ET_TOUCH_RELEASED) { + ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); + ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); + double tracking_id; + if (manager->GetEventData(xev, + ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, + &tracking_id)) { + factory->ReleaseSlotForTrackingID(tracking_id); + } + } +} + +int GetTouchIdFromXEvent(const XEvent& xev) { + double slot = 0; + ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); + double tracking_id; + if (!manager->GetEventData( + xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) { + LOG(ERROR) << "Could not get the tracking ID for the event. Using 0."; + } else { + ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); + slot = factory->GetSlotForTrackingID(tracking_id); + } + return slot; +} + +float GetTouchRadiusXFromXEvent(const XEvent& xev) { + double radius = GetTouchParamFromXEvent( + xev, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / + 2.0; + ScaleTouchRadius(xev, &radius); + return radius; +} + +float GetTouchRadiusYFromXEvent(const XEvent& xev) { + double radius = GetTouchParamFromXEvent( + xev, ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / + 2.0; + ScaleTouchRadius(xev, &radius); + return radius; +} + +float GetTouchAngleFromXEvent(const XEvent& xev) { + return GetTouchParamFromXEvent( + xev, ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) / + 2.0; +} + +float GetTouchForceFromXEvent(const XEvent& xev) { + double force = 0.0; + force = GetTouchParamFromXEvent( + xev, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0); + unsigned int deviceid = + static_cast<XIDeviceEvent*>(xev.xcookie.data)->sourceid; + // Force is normalized to fall into [0, 1] + if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData( + deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force)) + force = 0.0; + return force; +} + +bool GetScrollOffsetsFromXEvent(const XEvent& xev, + float* x_offset, + float* y_offset, + float* x_offset_ordinal, + float* y_offset_ordinal, + int* finger_count) { + if (DeviceDataManagerX11::GetInstance()->IsScrollEvent(xev)) { + // Temp values to prevent passing NULLs to DeviceDataManager. + float x_offset_, y_offset_; + float x_offset_ordinal_, y_offset_ordinal_; + int finger_count_; + if (!x_offset) + x_offset = &x_offset_; + if (!y_offset) + y_offset = &y_offset_; + if (!x_offset_ordinal) + x_offset_ordinal = &x_offset_ordinal_; + if (!y_offset_ordinal) + y_offset_ordinal = &y_offset_ordinal_; + if (!finger_count) + finger_count = &finger_count_; + + DeviceDataManagerX11::GetInstance()->GetScrollOffsets( + xev, x_offset, y_offset, x_offset_ordinal, y_offset_ordinal, + finger_count); + return true; + } + + if (DeviceDataManagerX11::GetInstance()->GetScrollClassDeviceDetail(xev) != + SCROLL_TYPE_NO_SCROLL) { + double x_scroll_offset, y_scroll_offset; + DeviceDataManagerX11::GetInstance()->GetScrollClassOffsets( + xev, &x_scroll_offset, &y_scroll_offset); + *x_offset = x_scroll_offset * kWheelScrollAmount; + *y_offset = y_scroll_offset * kWheelScrollAmount; + return true; + } + return false; +} + +bool GetFlingDataFromXEvent(const XEvent& xev, + float* vx, + float* vy, + float* vx_ordinal, + float* vy_ordinal, + bool* is_cancel) { + if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(xev)) + return false; + + float vx_, vy_; + float vx_ordinal_, vy_ordinal_; + bool is_cancel_; + if (!vx) + vx = &vx_; + if (!vy) + vy = &vy_; + if (!vx_ordinal) + vx_ordinal = &vx_ordinal_; + if (!vy_ordinal) + vy_ordinal = &vy_ordinal_; + if (!is_cancel) + is_cancel = &is_cancel_; + + DeviceDataManagerX11::GetInstance()->GetFlingData(xev, vx, vy, vx_ordinal, + vy_ordinal, is_cancel); + return true; +} + +} // namespace ui
diff --git a/ui/events/x/events_x_utils.h b/ui/events/x/events_x_utils.h new file mode 100644 index 0000000..671c3bb --- /dev/null +++ b/ui/events/x/events_x_utils.h
@@ -0,0 +1,87 @@ +// Copyright (c) 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef UI_EVENTS_X_EVENTS_X_UTILS_H_ +#define UI_EVENTS_X_EVENTS_X_UTILS_H_ + +#include <stdint.h> + +#include "base/time/time.h" +#include "ui/events/event.h" +#include "ui/events/event_constants.h" + +typedef union _XEvent XEvent; + +namespace ui { + +// Get the EventType from a XEvent. +EventType EventTypeFromXEvent(const XEvent& xev); + +// Get the EventFlags from a XEvent. +int EventFlagsFromXEvent(const XEvent& xev); + +// Get the timestamp from a XEvent. +base::TimeDelta EventTimeFromXEvent(const XEvent& xev); + +// Get the location from a XEvent. The coordinate system of the resultant +// |Point| has the origin at top-left of the "root window". The nature of +// this "root window" and how it maps to platform-specific drawing surfaces is +// defined in ui/aura/root_window.* and ui/aura/window_tree_host*. +gfx::Point EventLocationFromXEvent(const XEvent& xev); + +// Gets the location in native system coordinate space. +gfx::Point EventSystemLocationFromXEvent(const XEvent& xev); + +// Returns the 'real' button for an event. The button reported in slave events +// does not take into account any remapping (e.g. using xmodmap), while the +// button reported in master events do. This is a utility function to always +// return the mapped button. +int EventButtonFromXEvent(const XEvent& xev); + +// Returns the flags of the button that changed during a press/release. +int GetChangedMouseButtonFlagsFromXEvent(const XEvent& xev); + +// Returns the detailed pointer information for mouse events. +PointerDetails GetMousePointerDetailsFromXEvent(const XEvent& xev); + +// Gets the mouse wheel offsets from a XEvent. +gfx::Vector2d GetMouseWheelOffsetFromXEvent(const XEvent& xev); + +// Clear the touch id from bookkeeping if it is a release/cancel event. +void ClearTouchIdIfReleasedFromXEvent(const XEvent& xev); + +// Gets the touch id from a XEvent. +int GetTouchIdFromXEvent(const XEvent& xev); + +// Gets the radius along the X/Y axis from a XEvent. Default is 1.0. +float GetTouchRadiusXFromXEvent(const XEvent& xev); +float GetTouchRadiusYFromXEvent(const XEvent& xev); + +// Gets the angle of the major axis away from the X axis. Default is 0.0. +float GetTouchAngleFromXEvent(const XEvent& xev); + +// Gets the force from a native_event. Normalized to be [0, 1]. Default is 0.0. +float GetTouchForceFromXEvent(const XEvent& xev); + +// Returns whether this is a scroll event and optionally gets the amount to be +// scrolled. |x_offset|, |y_offset| and |finger_count| can be NULL. +bool GetScrollOffsetsFromXEvent(const XEvent& xev, + float* x_offset, + float* y_offset, + float* x_offset_ordinal, + float* y_offset_ordinal, + int* finger_count); + +// Gets the fling velocity from a XEvent. is_cancel is set to true if +// this was a tap down, intended to stop an ongoing fling. +bool GetFlingDataFromXEvent(const XEvent& xev, + float* vx, + float* vy, + float* vx_ordinal, + float* vy_ordinal, + bool* is_cancel); + +} // namespace ui + +#endif // UI_EVENTS_X_EVENTS_X_UTILS_H_
diff --git a/ui/gl/gl_surface.cc b/ui/gl/gl_surface.cc index 768bfa9..77153a59 100644 --- a/ui/gl/gl_surface.cc +++ b/ui/gl/gl_surface.cc
@@ -225,6 +225,10 @@ return false; } +bool GLSurface::BuffersFlipped() const { + return false; +} + GLSurface* GLSurface::GetCurrent() { return current_surface_.Pointer()->Get(); } @@ -389,6 +393,10 @@ return surface_->FlipsVertically(); } +bool GLSurfaceAdapter::BuffersFlipped() const { + return surface_->BuffersFlipped(); +} + GLSurfaceAdapter::~GLSurfaceAdapter() {} } // namespace gfx
diff --git a/ui/gl/gl_surface.h b/ui/gl/gl_surface.h index 066435a..56b6bcf 100644 --- a/ui/gl/gl_surface.h +++ b/ui/gl/gl_surface.h
@@ -183,6 +183,10 @@ virtual bool FlipsVertically() const; + // Returns true if SwapBuffers or PostSubBuffers causes a flip, such that + // the next buffer may be 2 frames old. + virtual bool BuffersFlipped() const; + // Create a GL surface that renders directly to a view. static scoped_refptr<GLSurface> CreateViewGLSurface( gfx::AcceleratedWidget window); @@ -270,6 +274,7 @@ const RectF& crop_rect) override; bool IsSurfaceless() const override; bool FlipsVertically() const override; + bool BuffersFlipped() const override; GLSurface* surface() const { return surface_.get(); }
diff --git a/ui/gl/gl_surface_egl.cc b/ui/gl/gl_surface_egl.cc index 20f6298..79b8c16 100644 --- a/ui/gl/gl_surface_egl.cc +++ b/ui/gl/gl_surface_egl.cc
@@ -769,6 +769,10 @@ return flips_vertically_; } +bool NativeViewGLSurfaceEGL::BuffersFlipped() const { + return g_use_direct_composition; +} + gfx::SwapResult NativeViewGLSurfaceEGL::PostSubBuffer(int x, int y, int width,
diff --git a/ui/gl/gl_surface_egl.h b/ui/gl/gl_surface_egl.h index 45396d47..f14f4e6 100644 --- a/ui/gl/gl_surface_egl.h +++ b/ui/gl/gl_surface_egl.h
@@ -102,6 +102,7 @@ const Rect& bounds_rect, const RectF& crop_rect) override; bool FlipsVertically() const override; + bool BuffersFlipped() const override; // Create a NativeViewGLSurfaceEGL with an externally provided VSyncProvider. // Takes ownership of the VSyncProvider.
diff --git a/ui/gl/gl_surface_stub.cc b/ui/gl/gl_surface_stub.cc index c49165fe..ad5b0b3 100644 --- a/ui/gl/gl_surface_stub.cc +++ b/ui/gl/gl_surface_stub.cc
@@ -9,6 +9,12 @@ void GLSurfaceStub::Destroy() { } +bool GLSurfaceStub::Resize(const gfx::Size& size, + float scale_factor, + bool has_alpha) { + return true; +} + bool GLSurfaceStub::IsOffscreen() { return false; } @@ -25,6 +31,10 @@ return NULL; } +bool GLSurfaceStub::BuffersFlipped() const { + return buffers_flipped_; +} + GLSurfaceStub::~GLSurfaceStub() {} } // namespace gfx
diff --git a/ui/gl/gl_surface_stub.h b/ui/gl/gl_surface_stub.h index bf21573e..9115b7c1 100644 --- a/ui/gl/gl_surface_stub.h +++ b/ui/gl/gl_surface_stub.h
@@ -13,19 +13,25 @@ class GL_EXPORT GLSurfaceStub : public GLSurface { public: void SetSize(const gfx::Size& size) { size_ = size; } + void set_buffers_flipped(bool flipped) { buffers_flipped_ = flipped; } // Implement GLSurface. void Destroy() override; + bool Resize(const gfx::Size& size, + float scale_factor, + bool has_alpha) override; bool IsOffscreen() override; gfx::SwapResult SwapBuffers() override; gfx::Size GetSize() override; void* GetHandle() override; + bool BuffersFlipped() const override; protected: ~GLSurfaceStub() override; private: gfx::Size size_; + bool buffers_flipped_ = false; }; } // namespace gfx