diff --git a/DEPS b/DEPS index b8ab6cf..212fcab 100644 --- a/DEPS +++ b/DEPS
@@ -133,7 +133,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling Skia # and whatever else without interference from each other. - 'skia_revision': '3061d27351076a36fce47fb82ce45d39cbdde3c0', + 'skia_revision': 'f5ca01a69ab6f427c515bb3b4a9748047f04cb13', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling V8 # and whatever else without interference from each other. @@ -145,15 +145,15 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling ANGLE # and whatever else without interference from each other. - 'angle_revision': 'a10b2d078ceb55cc1ba1bf6d7558095154f24163', + 'angle_revision': 'ebab670cb32dccde42bdf48a02816c44ee6246c7', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling SwiftShader # and whatever else without interference from each other. - 'swiftshader_revision': '529eda3e56aa186ee17efe28319d30f33ba33372', + 'swiftshader_revision': '0264d8e12603cb3ef63436237013b666abe31c2b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling PDFium # and whatever else without interference from each other. - 'pdfium_revision': '17dedfae9feb1fd108aca77fd80bc641e64309ca', + 'pdfium_revision': '94908c491899a1baf566826cc4faa253844b4e6a', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling openmax_dl # and whatever else without interference from each other. @@ -200,7 +200,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling catapult # and whatever else without interference from each other. - 'catapult_revision': 'f8847c1a94bb0c8ec61669bdcc1a34098aa94664', + 'catapult_revision': '09e818b4de419d2aa15c6f1ef36e49fdf6176a9f', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling libFuzzer # and whatever else without interference from each other. @@ -256,7 +256,7 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'spv_tools_revision': 'cc3e93c4e6fb776b67863decfd69eb307df74ae1', + 'spv_tools_revision': 'f2803c4a7f58237aa0dd9d39ccc6dea362527b96', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -268,11 +268,11 @@ # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'shaderc_revision': '3ac606a7738e2e07ec534ccec973c32973939375', + 'shaderc_revision': '1defed750e1fe3b7f1947306ee4ea86c1562403b', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. - 'dawn_revision': 'f112ceca341d06a00089f3a71bfa18ab64d15287', + 'dawn_revision': '974a1503273543719df2a3a18a967a4a785d49f1', # Three lines of non-changing comments so that # the commit queue can handle CLs rolling feed # and whatever else without interference from each other. @@ -831,7 +831,7 @@ }, 'src/third_party/depot_tools': - Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '8c66565649b7cae3bc80bba872b730902be7aa03', + Var('chromium_git') + '/chromium/tools/depot_tools.git' + '@' + '370d193c8e46d8ff67d9581afb639c095cc7ded4', 'src/third_party/devtools-node-modules': Var('chromium_git') + '/external/github.com/ChromeDevTools/devtools-node-modules' + '@' + Var('devtools_node_modules_revision'), @@ -1184,7 +1184,7 @@ }, 'src/third_party/perfetto': - Var('android_git') + '/platform/external/perfetto.git' + '@' + '826c8d4342d321fb921cf6e0704fe482c7a58348', + Var('android_git') + '/platform/external/perfetto.git' + '@' + 'dc65ac0b74e9da50bb09b74f09e75fc45205adc7', 'src/third_party/perl': { 'url': Var('chromium_git') + '/chromium/deps/perl.git' + '@' + 'ac0d98b5cee6c024b0cffeb4f8f45b6fc5ccdb78',
diff --git a/android_webview/browser/aw_content_browser_client.cc b/android_webview/browser/aw_content_browser_client.cc index c773860..b734e80f 100644 --- a/android_webview/browser/aw_content_browser_client.cc +++ b/android_webview/browser/aw_content_browser_client.cc
@@ -71,6 +71,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/client_certificate_delegate.h" +#include "content/public/browser/cors_exempt_headers.h" #include "content/public/browser/file_url_loader.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/navigation_throttle.h" @@ -379,6 +380,8 @@ #endif context_params->check_clear_text_permitted = g_check_cleartext_permitted; + content::UpdateCorsExemptHeader(context_params.get()); + // Add proxy settings AwProxyConfigMonitor::GetInstance()->AddProxyToNetworkContextParams( context_params);
diff --git a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc index 57d927d..2ea57ce 100644 --- a/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc +++ b/android_webview/browser/network_service/aw_proxying_url_loader_factory.cc
@@ -27,6 +27,7 @@ #include "content/public/browser/global_request_id.h" #include "content/public/browser/resource_request_info.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/content_constants.h" #include "content/public/common/url_utils.h" #include "net/base/load_flags.h" #include "net/http/http_util.h" @@ -36,7 +37,6 @@ namespace { const char kAutoLoginHeaderName[] = "X-Auto-Login"; -const char kRequestedWithHeaderName[] = "X-Requested-With"; // Handles intercepted, in-progress requests/responses, so that they can be // controlled and modified accordingly. @@ -332,18 +332,18 @@ android_webview::IsAndroidSpecialFileUrl(request_.url)); } -void SetRequestedWithHeader(net::HttpRequestHeaders& headers) { - // We send the application's package name in the X-Requested-With header for - // compatibility with previous WebView versions. This should not be visible to - // shouldInterceptRequest. - headers.SetHeaderIfMissing( - kRequestedWithHeaderName, - base::android::BuildInfo::GetInstance()->host_package_name()); -} - void InterceptedRequest::InterceptResponseReceived( std::unique_ptr<AwWebResourceResponse> response) { - SetRequestedWithHeader(request_.headers); + // We send the application's package name in the X-Requested-With header for + // compatibility with previous WebView versions. This should not be visible to + // shouldInterceptRequest. It should also not trigger CORS prefetch if + // OOR-CORS is enabled. + if (!request_.headers.HasHeader( + content::kCorsExemptRequestedWithHeaderName)) { + request_.cors_exempt_headers.SetHeader( + content::kCorsExemptRequestedWithHeaderName, + base::android::BuildInfo::GetInstance()->host_package_name()); + } if (response) { // non-null response: make sure to use it as an override for the
diff --git a/ash/BUILD.gn b/ash/BUILD.gn index 77005de1..d84c702e 100644 --- a/ash/BUILD.gn +++ b/ash/BUILD.gn
@@ -1608,6 +1608,7 @@ "accessibility/touch_exploration_controller_unittest.cc", "accessibility/touch_exploration_manager_unittest.cc", "app_list/app_list_controller_impl_unittest.cc", + "app_list/app_list_metrics_unittest.cc", "app_list/app_list_presenter_delegate_unittest.cc", "app_list/app_list_unittest.cc", "app_list/model/app_list_item_list_unittest.cc",
diff --git a/ash/app_list/app_list_controller_impl.cc b/ash/app_list/app_list_controller_impl.cc index 24853dde..e6b1bc9 100644 --- a/ash/app_list/app_list_controller_impl.cc +++ b/ash/app_list/app_list_controller_impl.cc
@@ -37,6 +37,7 @@ #include "ash/wallpaper/wallpaper_controller.h" #include "ash/wm/mru_window_tracker.h" #include "ash/wm/overview/overview_controller.h" +#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" #include "base/logging.h" @@ -1114,7 +1115,7 @@ // will be ended after the app is opened. OverviewController* overview_controller = Shell::Get()->overview_controller(); auto* split_view_controller = Shell::Get()->split_view_controller(); - if ((overview_controller->IsSelecting() && + if ((overview_controller->InOverviewSession() && !split_view_controller->InClamshellSplitViewMode()) || overview_controller->IsCompletingShutdownAnimations()) { return false;
diff --git a/ash/app_list/app_list_metrics_unittest.cc b/ash/app_list/app_list_metrics_unittest.cc new file mode 100644 index 0000000..bd0cb73 --- /dev/null +++ b/ash/app_list/app_list_metrics_unittest.cc
@@ -0,0 +1,504 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <vector> + +#include "ash/app_list/app_list_controller_impl.h" +#include "ash/app_list/model/search/search_model.h" +#include "ash/app_list/test/app_list_test_helper.h" +#include "ash/app_list/test/app_list_test_model.h" +#include "ash/app_list/views/app_list_item_view.h" +#include "ash/app_list/views/app_list_main_view.h" +#include "ash/app_list/views/app_list_view.h" +#include "ash/app_list/views/apps_container_view.h" +#include "ash/app_list/views/apps_grid_view.h" +#include "ash/app_list/views/contents_view.h" +#include "ash/app_list/views/search_result_container_view.h" +#include "ash/app_list/views/search_result_page_view.h" +#include "ash/app_list/views/search_result_tile_item_view.h" +#include "ash/app_list/views/suggestion_chip_container_view.h" +#include "ash/public/cpp/shelf_item_delegate.h" +#include "ash/public/cpp/shelf_model.h" +#include "ash/public/interfaces/app_list.mojom.h" +#include "ash/public/interfaces/app_list_view.mojom.h" +#include "ash/shelf/shelf.h" +#include "ash/shelf/shelf_view.h" +#include "ash/shelf/shelf_view_test_api.h" +#include "ash/shell.h" +#include "ash/test/ash_test_base.h" +#include "ash/wm/tablet_mode/tablet_mode_controller.h" +#include "base/test/metrics/histogram_tester.h" +#include "ui/display/screen.h" +#include "ui/events/test/event_generator.h" + +namespace ash { + +namespace { + +// A test shelf item delegate that simulates an activated window when a shelf +// item is selected. +class TestShelfItemDelegate : public ShelfItemDelegate { + public: + explicit TestShelfItemDelegate(const ShelfID& shelf_id) + : ShelfItemDelegate(shelf_id) {} + + void ItemSelected(std::unique_ptr<ui::Event> event, + int64_t display_id, + ash::ShelfLaunchSource source, + ItemSelectedCallback callback) override { + std::move(callback).Run(SHELF_ACTION_WINDOW_ACTIVATED, base::nullopt); + } + void ExecuteCommand(bool from_context_menu, + int64_t command_id, + int32_t event_flags, + int64_t display_id) override {} + void Close() override {} +}; + +} // namespace + +int64_t GetPrimaryDisplayId() { + return display::Screen::GetScreen()->GetPrimaryDisplay().id(); +} + +// Used to test that app launched metrics are properly recorded. +class AppListAppLaunchedMetricTest : public AshTestBase { + public: + AppListAppLaunchedMetricTest() = default; + ~AppListAppLaunchedMetricTest() override = default; + + void SetUp() override { + app_list::AppListView::SetShortAnimationForTesting(true); + AshTestBase::SetUp(); + + search_model_ = Shell::Get()->app_list_controller()->GetSearchModel(); + + app_list_test_model_ = static_cast<app_list::test::AppListTestModel*>( + Shell::Get()->app_list_controller()->GetModel()); + } + + void TearDown() override { + AshTestBase::TearDown(); + app_list::AppListView::SetShortAnimationForTesting(false); + } + + protected: + void CreateAndClickShelfItem() { + // Add shelf item to be launched. + ShelfItem shelf_item; + shelf_item.id = ash::ShelfID("app_id"); + shelf_item.type = TYPE_BROWSER_SHORTCUT; + Shell::Get()->shelf_model()->Add(shelf_item); + + // The TestShelfItemDelegate will simulate a window activation after the + // shelf item is clicked. + Shell::Get()->shelf_model()->SetShelfItemDelegate( + shelf_item.id, std::make_unique<TestShelfItemDelegate>(shelf_item.id)); + + ClickShelfItem(); + } + + void ClickShelfItem() { + // Get location of the shelf item. + ShelfViewTestAPI shelf_test_api( + GetPrimaryShelf()->GetShelfViewForTesting()); + ShelfView* shelf_view = shelf_test_api.shelf_view(); + const views::ViewModel* view_model = shelf_view->view_model_for_test(); + gfx::Point center = + view_model->view_at(2)->GetBoundsInScreen().CenterPoint(); + + // Click on the shelf item. + ui::test::EventGenerator* generator = GetEventGenerator(); + generator->MoveMouseTo(center); + generator->ClickLeftButton(); + generator->ReleaseLeftButton(); + } + + void PopulateAndLaunchSearchBoxTileItem() { + // Populate 4 tile items. + for (size_t i = 0; i < 4; i++) { + auto search_result = std::make_unique<app_list::SearchResult>(); + search_result->set_display_type(ash::SearchResultDisplayType::kTile); + search_model_->results()->Add(std::move(search_result)); + } + GetAppListTestHelper()->WaitUntilIdle(); + + app_list::SearchResultContainerView* search_result_container_view = + Shell::Get() + ->app_list_controller() + ->presenter() + ->GetView() + ->app_list_main_view() + ->contents_view() + ->search_results_page_view() + ->result_container_views()[1]; + + // Request focus on the first tile item view. + search_result_container_view->GetFirstResultView()->RequestFocus(); + + // Press return to simulate an app launch from the tile item. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + } + + void PopulateAndLaunchSuggestionChip() { + // Populate 4 suggestion chips. + for (size_t i = 0; i < 4; i++) { + auto search_result_chip = std::make_unique<app_list::SearchResult>(); + search_result_chip->set_display_type( + ash::SearchResultDisplayType::kRecommendation); + search_model_->results()->Add(std::move(search_result_chip)); + } + GetAppListTestHelper()->WaitUntilIdle(); + + app_list::SearchResultContainerView* suggestions_container_ = + Shell::Get() + ->app_list_controller() + ->presenter() + ->GetView() + ->app_list_main_view() + ->contents_view() + ->GetAppsContainerView() + ->suggestion_chip_container_view_for_test(); + + // Get focus on the first chip. + suggestions_container_->children().front()->RequestFocus(); + GetAppListTestHelper()->WaitUntilIdle(); + + // Press return to simulate an app launch from the suggestion chip. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + } + + void PopulateAndLaunchAppInGrid() { + // Populate apps in the root app grid. + app_list_test_model_->PopulateApps(4); + + app_list::AppListView::TestApi test_api( + Shell::Get()->app_list_controller()->presenter()->GetView()); + + // Focus the first item in the root app grid. + test_api.GetRootAppsGridView()->GetItemViewAt(0)->RequestFocus(); + + // Press return to simulate an app launch from a grid item. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_RETURN, 0); + } + + private: + app_list::SearchModel* search_model_ = nullptr; + app_list::test::AppListTestModel* app_list_test_model_ = nullptr; + + DISALLOW_COPY_AND_ASSIGN(AppListAppLaunchedMetricTest); +}; + +// Test that the histogram records an app launch from the shelf while the half +// launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, HalfLaunchFromShelf) { + base::HistogramTester histogram_tester; + + GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId()); + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kPeeking); + + // Press a letter key, the AppListView should transition to kHalf. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_H, 0); + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kHalf); + + CreateAndClickShelfItem(); + GetAppListTestHelper()->WaitUntilIdle(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.Half", + mojom::AppListLaunchedFrom::kLaunchedFromShelf, + 1 /* Number of times launched from shelf */); +} + +// Test that the histogram records an app launch from the search box while the +// half launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, HalfLaunchFromSearchBox) { + base::HistogramTester histogram_tester; + + GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId()); + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kPeeking); + + // Press a letter key, the AppListView should transition to kHalf. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_H, 0); + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kHalf); + + PopulateAndLaunchSearchBoxTileItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.Half", + mojom::AppListLaunchedFrom::kLaunchedFromSearchBox, + 1 /* Number of times launched from search box */); +} + +// Test that the histogram records an app launch from the search box while the +// fullscreen search launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, FullscreenSearchLaunchFromSearchBox) { + base::HistogramTester histogram_tester; + ui::test::EventGenerator* generator = GetEventGenerator(); + + // Press search + shift to transition to kFullscreenAllApps. + generator->PressKey(ui::KeyboardCode::VKEY_BROWSER_SEARCH, ui::EF_SHIFT_DOWN); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenAllApps); + + // Press a letter key, the AppListView should transition to kFullscreenSearch. + generator->PressKey(ui::KeyboardCode::VKEY_H, 0); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenSearch); + + PopulateAndLaunchSearchBoxTileItem(); + + GetAppListTestHelper()->WaitUntilIdle(); + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.FullscreenSearch", + mojom::AppListLaunchedFrom::kLaunchedFromSearchBox, + 1 /* Number of times launched from search box */); +} + +// Test that the histogram records an app launch from the shelf while the +// fullscreen search launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, FullscreenSearchLaunchFromShelf) { + base::HistogramTester histogram_tester; + ui::test::EventGenerator* generator = GetEventGenerator(); + + // Press search + shift to transition to kFullscreenAllApps. + generator->PressKey(ui::KeyboardCode::VKEY_BROWSER_SEARCH, ui::EF_SHIFT_DOWN); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenAllApps); + + // Press a letter key, the AppListView should transition to kFullscreenSearch. + generator->PressKey(ui::KeyboardCode::VKEY_H, 0); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenSearch); + + CreateAndClickShelfItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.FullscreenSearch", + mojom::AppListLaunchedFrom::kLaunchedFromShelf, + 1 /* Number of times launched from shelf */); +} + +// Test that the histogram records an app launch from a suggestion chip while +// the fullscreen all apps launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, FullscreenAllAppsLaunchFromChip) { + base::HistogramTester histogram_tester; + + // Press search + shift to transition to kFullscreenAllApps. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_BROWSER_SEARCH, + ui::EF_SHIFT_DOWN); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenAllApps); + + PopulateAndLaunchSuggestionChip(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.FullscreenAllApps", + mojom::AppListLaunchedFrom::kLaunchedFromSuggestionChip, + 1 /* Number of times launched from chip */); +} + +// Test that the histogram records an app launch from the app grid while the +// fullscreen all apps launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, FullscreenAllAppsLaunchFromGrid) { + base::HistogramTester histogram_tester; + + // Press search + shift to transition to kFullscreenAllApps. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_BROWSER_SEARCH, + ui::EF_SHIFT_DOWN); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenAllApps); + + PopulateAndLaunchAppInGrid(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.FullscreenAllApps", + mojom::AppListLaunchedFrom::kLaunchedFromGrid, + 1 /* Number of times launched from grid */); +} + +// Test that the histogram records an app launch from the shelf while the +// fullscreen all apps launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, FullscreenAllAppsLaunchFromShelf) { + base::HistogramTester histogram_tester; + + // Press search + shift to transition to kFullscreenAllApps. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_BROWSER_SEARCH, + ui::EF_SHIFT_DOWN); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenAllApps); + + CreateAndClickShelfItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.FullscreenAllApps", + mojom::AppListLaunchedFrom::kLaunchedFromShelf, + 1 /* Number of times launched from shelf */); +} + +// Test that the histogram records an app launch from the shelf while the +// peeking launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, PeekingLaunchFromShelf) { + base::HistogramTester histogram_tester; + + GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId()); + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kPeeking); + + CreateAndClickShelfItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.Peeking", + mojom::AppListLaunchedFrom::kLaunchedFromShelf, + 1 /* Number of times launched from shelf */); +} + +// Test that the histogram records an app launch from a suggestion chip while +// the peeking launcher is showing. +TEST_F(AppListAppLaunchedMetricTest, PeekingLaunchFromChip) { + base::HistogramTester histogram_tester; + + GetAppListTestHelper()->ShowAndRunLoop(GetPrimaryDisplayId()); + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kPeeking); + + PopulateAndLaunchSuggestionChip(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.Peeking", + mojom::AppListLaunchedFrom::kLaunchedFromSuggestionChip, + 1 /* Number of times launched from chip */); +} + +// Test that the histogram records an app launch from the shelf while the +// launcher is closed. +TEST_F(AppListAppLaunchedMetricTest, ClosedLaunchFromShelf) { + base::HistogramTester histogram_tester; + + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kClosed); + + CreateAndClickShelfItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.Closed", + mojom::AppListLaunchedFrom::kLaunchedFromShelf, + 1 /* Number of times launched from shelf */); + + // Open the launcher to peeking. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_BROWSER_SEARCH, 0); + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kPeeking); + + // Close launcher back to closed. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_BROWSER_SEARCH, 0); + GetAppListTestHelper()->CheckState(ash::mojom::AppListViewState::kClosed); + + ClickShelfItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.Closed", + mojom::AppListLaunchedFrom::kLaunchedFromShelf, + 2 /* Number of times launched from shelf */); +} + +// Test that the histogram records an app launch from the shelf while the +// homecher all apps state is showing. +TEST_F(AppListAppLaunchedMetricTest, HomecherAllAppsLaunchFromShelf) { + Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true); + base::HistogramTester histogram_tester; + + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenAllApps); + + CreateAndClickShelfItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.HomecherAllApps", + mojom::AppListLaunchedFrom::kLaunchedFromShelf, + 1 /* Number of times launched from shelf */); +} + +// Test that the histogram records an app launch from the app grid while the +// homecher all apps state is showing. +TEST_F(AppListAppLaunchedMetricTest, HomecherAllAppsLaunchFromGrid) { + base::HistogramTester histogram_tester; + + // Enable tablet mode. + Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenAllApps); + + PopulateAndLaunchAppInGrid(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.HomecherAllApps", + mojom::AppListLaunchedFrom::kLaunchedFromGrid, + 1 /* Number of times launched from grid */); +} + +// Test that the histogram records an app launch from a suggestion chip while +// the homecher all apps state is showing. +TEST_F(AppListAppLaunchedMetricTest, HomecherAllAppsLaunchFromChip) { + base::HistogramTester histogram_tester; + + GetAppListTestHelper()->WaitUntilIdle(); + // Enable tablet mode. + Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenAllApps); + + PopulateAndLaunchSuggestionChip(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.HomecherAllApps", + mojom::AppListLaunchedFrom::kLaunchedFromSuggestionChip, + 1 /* Number of times launched from chip */); +} + +// Test that the histogram records an app launch from the shelf while the +// homecher search state is showing. +TEST_F(AppListAppLaunchedMetricTest, HomecherSearchLaunchFromShelf) { + base::HistogramTester histogram_tester; + + // Enable tablet mode. + GetAppListTestHelper()->WaitUntilIdle(); + Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true); + + // Press a letter key, the AppListView should transition to kFullscreenSearch. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_H, 0); + GetAppListTestHelper()->WaitUntilIdle(); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenSearch); + + CreateAndClickShelfItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.HomecherSearch", + mojom::AppListLaunchedFrom::kLaunchedFromShelf, + 1 /* Number of times launched from shelf */); +} + +// Test that the histogram records an app launch from the search box while the +// homercher search state is showing. +TEST_F(AppListAppLaunchedMetricTest, HomecherSearchLaunchFromSearchBox) { + base::HistogramTester histogram_tester; + + // Enable tablet mode. + GetAppListTestHelper()->WaitUntilIdle(); + Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(true); + + // Press a letter key, the AppListView should transition to kFullscreenSearch. + GetEventGenerator()->PressKey(ui::KeyboardCode::VKEY_H, 0); + GetAppListTestHelper()->WaitUntilIdle(); + GetAppListTestHelper()->CheckState( + ash::mojom::AppListViewState::kFullscreenSearch); + + // Populate search box with tile items and launch a tile item. + PopulateAndLaunchSearchBoxTileItem(); + + histogram_tester.ExpectBucketCount( + "Apps.AppListAppLaunchedV2.HomecherSearch", + mojom::AppListLaunchedFrom::kLaunchedFromSearchBox, + 1 /* Number of times launched from search box */); +} + +} // namespace ash
diff --git a/ash/app_list/app_list_presenter_delegate_unittest.cc b/ash/app_list/app_list_presenter_delegate_unittest.cc index 56cd088..748eac0 100644 --- a/ash/app_list/app_list_presenter_delegate_unittest.cc +++ b/ash/app_list/app_list_presenter_delegate_unittest.cc
@@ -1517,13 +1517,13 @@ // Enable overview mode. OverviewController* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); ui::Layer* layer = GetAppListView()->GetWidget()->GetNativeWindow()->layer(); EXPECT_EQ(0.0f, layer->opacity()); // Disable overview mode. overview_controller->ToggleOverview(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); EXPECT_EQ(1.0f, layer->opacity()); } @@ -1563,12 +1563,12 @@ EXPECT_FALSE(GetAppListView()->GetWidget()->IsVisible()); OverviewController* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_FALSE(GetAppListView()->GetWidget()->IsVisible()); // Disable overview mode. Verify the app list is still hidden because // wallpaper preview is still active. overview_controller->ToggleOverview(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); EXPECT_FALSE(GetAppListView()->GetWidget()->IsVisible()); // End preview by confirming the wallpaper. Verify the app list is shown. wallpaper_test_api.EndWallpaperPreview(true /*confirm_preview_wallpaper=*/); @@ -1639,11 +1639,11 @@ std::unique_ptr<aura::Window> window(CreateTestWindowInShellWithId(0)); OverviewController* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); // Press app list button. PressAppListButton(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); GetAppListTestHelper()->CheckVisibility(true); }
diff --git a/ash/assistant/assistant_screen_context_controller.cc b/ash/assistant/assistant_screen_context_controller.cc index 057fdbc..9422ef4 100644 --- a/ash/assistant/assistant_screen_context_controller.cc +++ b/ash/assistant/assistant_screen_context_controller.cc
@@ -172,7 +172,7 @@ callback) { // http://crbug.com/941276 // We need to avoid requesting screenshot in known situations that will break. - if (Shell::Get()->overview_controller()->IsSelecting() || + if (Shell::Get()->overview_controller()->InOverviewSession() || Shell::Get()->overview_controller()->IsCompletingShutdownAnimations()) { std::move(callback).Run(std::vector<uint8_t>()); return;
diff --git a/ash/frame/non_client_frame_view_ash.cc b/ash/frame/non_client_frame_view_ash.cc index c12cb91..c31a73d 100644 --- a/ash/frame/non_client_frame_view_ash.cc +++ b/ash/frame/non_client_frame_view_ash.cc
@@ -18,6 +18,7 @@ #include "ash/public/cpp/window_properties.h" #include "ash/shell.h" #include "ash/wm/overview/overview_controller.h" +#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/tablet_mode/tablet_mode_observer.h" #include "ash/wm/window_state.h" @@ -466,8 +467,8 @@ } void NonClientFrameViewAsh::OnSplitViewStateChanged( - SplitViewController::State /* previous_state */, - SplitViewController::State /* current_state */) { + SplitViewState /* previous_state */, + SplitViewState /* current_state */) { UpdateHeaderView(); }
diff --git a/ash/frame/non_client_frame_view_ash.h b/ash/frame/non_client_frame_view_ash.h index 079abc60..77b5a40 100644 --- a/ash/frame/non_client_frame_view_ash.h +++ b/ash/frame/non_client_frame_view_ash.h
@@ -9,8 +9,8 @@ #include "ash/ash_export.h" #include "ash/frame/header_view.h" +#include "ash/public/cpp/split_view.h" #include "ash/wm/overview/overview_observer.h" -#include "ash/wm/splitview/split_view_controller.h" #include "base/macros.h" #include "base/optional.h" #include "third_party/skia/include/core/SkColor.h" @@ -36,7 +36,7 @@ // BrowserNonClientFrameViewAsh. class ASH_EXPORT NonClientFrameViewAsh : public views::NonClientFrameView, public OverviewObserver, - public SplitViewController::Observer { + public SplitViewObserver { public: // Internal class name. static const char kViewClassName[]; @@ -107,9 +107,9 @@ void OnOverviewModeStarting() override; void OnOverviewModeEnded() override; - // SplitViewController::Observer: - void OnSplitViewStateChanged(SplitViewController::State previous_state, - SplitViewController::State state) override; + // SplitViewObserver: + void OnSplitViewStateChanged(SplitViewState previous_state, + SplitViewState state) override; const views::View* GetAvatarIconViewForTest() const; @@ -156,7 +156,7 @@ // Track whether the device is in overview mode. Set this to true when // overview mode started and false when overview mode finished. Use this to // check whether we should paint when splitview state changes instead of - // Shell::Get()->overview_controller()->IsSelecting() because the + // Shell::Get()->overview_controller()->InOverviewSession() because the // later actually may be still be false after overview mode has started. bool in_overview_ = false;
diff --git a/ash/frame/non_client_frame_view_ash_unittest.cc b/ash/frame/non_client_frame_view_ash_unittest.cc index 7d5abe1..cbc0a18 100644 --- a/ash/frame/non_client_frame_view_ash_unittest.cc +++ b/ash/frame/non_client_frame_view_ash_unittest.cc
@@ -21,6 +21,7 @@ #include "ash/test/ash_test_base.h" #include "ash/wm/desks/desks_util.h" #include "ash/wm/overview/overview_controller.h" +#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_state_delegate.h" @@ -457,7 +458,7 @@ // the header is again drawn for the snapped window, but not for the unsnapped // window. Shell::Get()->overview_controller()->ToggleOverview(); - ASSERT_EQ(SplitViewController::LEFT_SNAPPED, + ASSERT_EQ(SplitViewState::kLeftSnapped, Shell::Get()->split_view_controller()->state()); EXPECT_TRUE(delegate1->header_view()->should_paint()); EXPECT_EQ(0, delegate1->GetNonClientFrameViewTopBorderHeight());
diff --git a/ash/home_screen/home_launcher_gesture_handler.cc b/ash/home_screen/home_launcher_gesture_handler.cc index ed0c1f79..32e681f 100644 --- a/ash/home_screen/home_launcher_gesture_handler.cc +++ b/ash/home_screen/home_launcher_gesture_handler.cc
@@ -499,7 +499,7 @@ const bool is_final_state_show = IsFinalStateShow(); NotifyHomeLauncherAnimationComplete(is_final_state_show /*shown*/, display_.id()); - if (Shell::Get()->overview_controller()->IsSelecting()) { + if (Shell::Get()->overview_controller()->InOverviewSession()) { if (overview_active_on_gesture_start_ && is_final_state_show) { // Exit overview if event is released on the top half. This will also // end splitview if it is active as SplitViewController observes @@ -527,7 +527,7 @@ // Explicitly exit split view if two windows are snapped. if (is_final_state_show && Shell::Get()->split_view_controller()->state() == - SplitViewController::BOTH_SNAPPED) { + SplitViewState::kBothSnapped) { Shell::Get()->split_view_controller()->EndSplitView(); } @@ -624,7 +624,7 @@ // observe the animation of a window in overview. OverviewController* controller = Shell::Get()->overview_controller(); std::unique_ptr<ui::ScopedLayerAnimationSettings> overview_settings; - if (overview_active_on_gesture_start_ && controller->IsSelecting()) { + if (overview_active_on_gesture_start_ && controller->InOverviewSession()) { DCHECK_EQ(mode_, Mode::kSlideUpToShow); const int inverted_y_position = gfx::Tween::IntValueBetween( progress, work_area.y(), work_area.bottom()); @@ -735,7 +735,7 @@ return true; if (overview_active_on_gesture_start_ && - Shell::Get()->overview_controller()->IsSelecting() && + Shell::Get()->overview_controller()->InOverviewSession() && (Shell::Get()->overview_controller()->IsInStartAnimation() || animating_to_close_overview_)) { return true; @@ -770,7 +770,7 @@ SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); overview_active_on_gesture_start_ = - Shell::Get()->overview_controller()->IsSelecting(); + Shell::Get()->overview_controller()->InOverviewSession(); const bool split_view_active = split_view_controller->InSplitViewMode(); auto windows = Shell::Get()->mru_window_tracker()->BuildWindowForCycleList(); if (window && (mode != Mode::kSlideDownToHide || @@ -824,7 +824,7 @@ // Alter a second window if we are in split view mode with two windows // snapped. if (mode == Mode::kSlideUpToShow && - split_view_controller->state() == SplitViewController::BOTH_SNAPPED) { + split_view_controller->state() == SplitViewState::kBothSnapped) { DCHECK_GT(windows.size(), 0u); aura::Window* second_window = split_view_controller->default_snap_position() ==
diff --git a/ash/home_screen/home_launcher_gesture_handler_unittest.cc b/ash/home_screen/home_launcher_gesture_handler_unittest.cc index 3923ec7..f449e06 100644 --- a/ash/home_screen/home_launcher_gesture_handler_unittest.cc +++ b/ash/home_screen/home_launcher_gesture_handler_unittest.cc
@@ -224,7 +224,7 @@ // Tests that after releasing at below the halfway point, we remain in // overview mode. GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 300)); - EXPECT_TRUE(controller->IsSelecting()); + EXPECT_TRUE(controller->InOverviewSession()); EXPECT_EQ(window1_initial_translation, window1->transform().To2dTranslation().y()); EXPECT_EQ(window2_initial_translation, @@ -234,7 +234,7 @@ // exited, and the two windows have been minimized to show the home launcher. DoPress(Mode::kSlideUpToShow); GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100)); - EXPECT_FALSE(controller->IsSelecting()); + EXPECT_FALSE(controller->InOverviewSession()); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMinimized()); EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMinimized()); } @@ -260,13 +260,13 @@ // Tests that after releasing at below the halfway point, we remain in // overview mode. GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 300)); - EXPECT_TRUE(controller->IsSelecting()); + EXPECT_TRUE(controller->InOverviewSession()); // Tests that after releasing on the top half, overview mode has been // exited. DoPress(Mode::kSlideUpToShow); GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100)); - EXPECT_FALSE(controller->IsSelecting()); + EXPECT_FALSE(controller->InOverviewSession()); } // Tests that there is no crash if entering overview mode while home launcher is @@ -296,7 +296,7 @@ SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); - ASSERT_TRUE(overview_controller->IsSelecting()); + ASSERT_TRUE(overview_controller->InOverviewSession()); ASSERT_TRUE(split_view_controller->InSplitViewMode()); const int window2_initial_translation = @@ -316,14 +316,14 @@ EXPECT_EQ(window1->transform(), gfx::Transform()); EXPECT_EQ(window2_initial_translation, window2->transform().To2dTranslation().y()); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_TRUE(split_view_controller->InSplitViewMode()); // Tests that after releasing on the top half, overivew and splitview have // both been exited, and both windows are minimized to show the home launcher. DoPress(Mode::kSlideUpToShow); GetGestureHandler()->OnReleaseEvent(gfx::Point(0, 100)); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); EXPECT_FALSE(split_view_controller->InSplitViewMode()); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMinimized()); EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMinimized());
diff --git a/ash/home_screen/home_screen_controller.cc b/ash/home_screen/home_screen_controller.cc index ffab9931..e436114 100644 --- a/ash/home_screen/home_screen_controller.cc +++ b/ash/home_screen/home_screen_controller.cc
@@ -84,7 +84,7 @@ return true; } - if (Shell::Get()->overview_controller()->IsSelecting()) { + if (Shell::Get()->overview_controller()->InOverviewSession()) { // End overview mode. Shell::Get()->overview_controller()->ToggleOverview( OverviewSession::EnterExitOverviewType::kWindowsMinimized); @@ -167,7 +167,8 @@ if (!window) return; - const bool in_overview = Shell::Get()->overview_controller()->IsSelecting(); + const bool in_overview = + Shell::Get()->overview_controller()->InOverviewSession(); if (in_overview || in_wallpaper_preview_ || in_window_dragging_) window->Hide(); else
diff --git a/ash/magnifier/docked_magnifier_controller.cc b/ash/magnifier/docked_magnifier_controller.cc index 710cf50..bf1a064 100644 --- a/ash/magnifier/docked_magnifier_controller.cc +++ b/ash/magnifier/docked_magnifier_controller.cc
@@ -572,7 +572,7 @@ // below. https://crbug.com/894256. Shell* shell = Shell::Get(); auto* overview_controller = shell->overview_controller(); - if (overview_controller->IsSelecting()) { + if (overview_controller->InOverviewSession()) { auto* split_view_controller = shell->split_view_controller(); if (split_view_controller->InSplitViewMode()) { // In this case, we're in a single-split-view mode, i.e. a window is
diff --git a/ash/magnifier/docked_magnifier_controller_unittest.cc b/ash/magnifier/docked_magnifier_controller_unittest.cc index 95fd05a..3aa9a2e 100644 --- a/ash/magnifier/docked_magnifier_controller_unittest.cc +++ b/ash/magnifier/docked_magnifier_controller_unittest.cc
@@ -329,14 +329,14 @@ // Enable overview mode followed by the magnifier. auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); controller()->SetEnabled(true); EXPECT_TRUE(controller()->GetEnabled()); // Expect that overview mode is exited, the display's work area is updated, // and the window's bounds are updated to be equal to the new display's work // area bounds. - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); const display::Display& display = display_manager()->GetDisplayAt(0); gfx::Rect workarea = display.bounds(); const int magnifier_height = GetMagnifierHeight(display.bounds().height()); @@ -360,26 +360,26 @@ wm::GetWindowState(window.get())->Maximize(); auto* split_view_controller = Shell::Get()->split_view_controller(); - EXPECT_EQ(split_view_controller->state(), SplitViewController::NO_SNAP); + EXPECT_EQ(split_view_controller->state(), SplitViewState::kNoSnap); EXPECT_EQ(split_view_controller->InSplitViewMode(), false); // Simulate going into split view, by enabling overview mode, and snapping // a window to the left. auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); split_view_controller->SnapWindow(window.get(), SplitViewController::LEFT); - EXPECT_EQ(split_view_controller->state(), SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller->left_window(), window.get()); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); // Enable the docked magnifier and expect that both overview and split view // modes are exited, and the window remains maximized, and its bounds are // updated to match the new display's work area. controller()->SetEnabled(true); EXPECT_TRUE(controller()->GetEnabled()); - EXPECT_FALSE(overview_controller->IsSelecting()); - EXPECT_EQ(split_view_controller->state(), SplitViewController::NO_SNAP); + EXPECT_FALSE(overview_controller->InOverviewSession()); + EXPECT_EQ(split_view_controller->state(), SplitViewState::kNoSnap); EXPECT_EQ(split_view_controller->InSplitViewMode(), false); const display::Display& display = display_manager()->GetDisplayAt(0); const int magnifier_height = GetMagnifierHeight(display.bounds().height()); @@ -406,17 +406,17 @@ auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); auto* split_view_controller = Shell::Get()->split_view_controller(); EXPECT_EQ(split_view_controller->InSplitViewMode(), false); split_view_controller->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller->SnapWindow(window2.get(), SplitViewController::RIGHT); EXPECT_EQ(split_view_controller->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller->state(), SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller->state(), SplitViewState::kBothSnapped); // Snapping both windows should exit overview mode. - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); // Enable the docked magnifier, and expect that split view does not exit, and // the two windows heights are updated to be equal to the height of the @@ -424,7 +424,7 @@ controller()->SetEnabled(true); EXPECT_TRUE(controller()->GetEnabled()); EXPECT_EQ(split_view_controller->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller->state(), SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller->state(), SplitViewState::kBothSnapped); const display::Display& display = display_manager()->GetDisplayAt(0); const int magnifier_height = GetMagnifierHeight(display.bounds().height()); gfx::Rect work_area = display.bounds();
diff --git a/ash/mojo_interface_factory.cc b/ash/mojo_interface_factory.cc index 9c3cf66..fb10ab6 100644 --- a/ash/mojo_interface_factory.cc +++ b/ash/mojo_interface_factory.cc
@@ -46,7 +46,6 @@ #include "ash/tray_action/tray_action.h" #include "ash/voice_interaction/voice_interaction_controller.h" #include "ash/wallpaper/wallpaper_controller.h" -#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "base/bind.h" #include "base/command_line.h" @@ -257,11 +256,6 @@ Shell::Get()->wallpaper_controller()->BindRequest(std::move(request)); } -void BindSplitViewRequestOnMainThread( - mojom::SplitViewControllerRequest request) { - Shell::Get()->split_view_controller()->BindRequest(std::move(request)); -} - } // namespace void RegisterInterfaces( @@ -382,8 +376,6 @@ main_thread_task_runner); registry->AddInterface(base::BindRepeating(&BindWallpaperRequestOnMainThread), main_thread_task_runner); - registry->AddInterface(base::BindRepeating(&BindSplitViewRequestOnMainThread), - main_thread_task_runner); if (base::CommandLine::ForCurrentProcess()->HasSwitch( ws::switches::kUseTestConfig)) {
diff --git a/ash/public/cpp/BUILD.gn b/ash/public/cpp/BUILD.gn index 410277e41..0ed13a1 100644 --- a/ash/public/cpp/BUILD.gn +++ b/ash/public/cpp/BUILD.gn
@@ -124,6 +124,8 @@ "shelf_types.h", "shell_window_ids.cc", "shell_window_ids.h", + "split_view.cc", + "split_view.h", "stylus_utils.cc", "stylus_utils.h", "system_tray_focus_observer.h",
diff --git a/ash/public/cpp/manifest.cc b/ash/public/cpp/manifest.cc index 75692780..196a363c 100644 --- a/ash/public/cpp/manifest.cc +++ b/ash/public/cpp/manifest.cc
@@ -33,7 +33,6 @@ #include "ash/public/interfaces/shelf.mojom.h" #include "ash/public/interfaces/shelf_integration_test_api.mojom.h" #include "ash/public/interfaces/shutdown.mojom.h" -#include "ash/public/interfaces/split_view.mojom.h" #include "ash/public/interfaces/system_tray.mojom.h" #include "ash/public/interfaces/tablet_mode.mojom.h" #include "ash/public/interfaces/tray_action.mojom.h" @@ -94,10 +93,10 @@ mojom::NewWindowController, mojom::NightLightController, mojom::NoteTakingController, mojom::ProcessCreationTimeRecorder, mojom::ShelfController, - mojom::ShutdownController, mojom::SplitViewController, - mojom::SystemTray, mojom::TabletModeController, - mojom::TrayAction, mojom::VoiceInteractionController, - mojom::VpnList, mojom::WallpaperController>()) + mojom::ShutdownController, mojom::SystemTray, + mojom::TabletModeController, mojom::TrayAction, + mojom::VoiceInteractionController, mojom::VpnList, + mojom::WallpaperController>()) .ExposeCapability("display", service_manager::Manifest::InterfaceList< mojom::AshDisplayController, mojom::DisplayOutputProtection>())
diff --git a/ash/public/cpp/split_view.cc b/ash/public/cpp/split_view.cc new file mode 100644 index 0000000..5aafe89c --- /dev/null +++ b/ash/public/cpp/split_view.cc
@@ -0,0 +1,36 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "ash/public/cpp/split_view.h" + +#include "base/logging.h" + +namespace ash { + +namespace { + +SplitViewNotifier* g_instance = nullptr; + +} // namespace + +SplitViewObserver::SplitViewObserver() = default; + +SplitViewObserver::~SplitViewObserver() = default; + +// static +SplitViewNotifier* SplitViewNotifier::Get() { + return g_instance; +} + +SplitViewNotifier::SplitViewNotifier() { + DCHECK_EQ(nullptr, g_instance); + g_instance = this; +} + +SplitViewNotifier::~SplitViewNotifier() { + DCHECK_EQ(this, g_instance); + g_instance = nullptr; +} + +} // namespace ash
diff --git a/ash/public/cpp/split_view.h b/ash/public/cpp/split_view.h new file mode 100644 index 0000000..f4d7a51 --- /dev/null +++ b/ash/public/cpp/split_view.h
@@ -0,0 +1,50 @@ +// Copyright 2019 The Chromium 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 ASH_PUBLIC_CPP_SPLIT_VIEW_H_ +#define ASH_PUBLIC_CPP_SPLIT_VIEW_H_ + +#include "ash/public/cpp/ash_public_export.h" + +namespace ash { + +enum class SplitViewState { + kNoSnap, + kLeftSnapped, + kRightSnapped, + kBothSnapped, +}; + +class ASH_PUBLIC_EXPORT SplitViewObserver { + public: + // Called when split view state changed from |previous_state| to |state|. + virtual void OnSplitViewStateChanged(SplitViewState previous_state, + SplitViewState state) {} + + // Called when split view divider's position has changed. + virtual void OnSplitViewDividerPositionChanged() {} + + protected: + SplitViewObserver(); + virtual ~SplitViewObserver(); +}; + +// This object handles notifying observers of changes to split view state. It's +// implemented in Ash via SplitViewController. +class ASH_PUBLIC_EXPORT SplitViewNotifier { + public: + static SplitViewNotifier* Get(); + + virtual SplitViewState GetCurrentState() const = 0; + virtual void AddObserver(SplitViewObserver* observer) = 0; + virtual void RemoveObserver(SplitViewObserver* observer) = 0; + + protected: + SplitViewNotifier(); + virtual ~SplitViewNotifier(); +}; + +} // namespace ash + +#endif // ASH_PUBLIC_CPP_SPLIT_VIEW_H_
diff --git a/ash/public/interfaces/BUILD.gn b/ash/public/interfaces/BUILD.gn index 2842cbc2..9a812ba 100644 --- a/ash/public/interfaces/BUILD.gn +++ b/ash/public/interfaces/BUILD.gn
@@ -54,7 +54,6 @@ "shelf.mojom", "shelf_integration_test_api.mojom", "shutdown.mojom", - "split_view.mojom", "system_tray.mojom", "tablet_mode.mojom", "tray_action.mojom",
diff --git a/ash/public/interfaces/shell_test_api.test-mojom b/ash/public/interfaces/shell_test_api.test-mojom index 073e7acb..08fd6a2 100644 --- a/ash/public/interfaces/shell_test_api.test-mojom +++ b/ash/public/interfaces/shell_test_api.test-mojom
@@ -23,10 +23,6 @@ // controller. In tablet mode, enables the virtual keyboard. EnableVirtualKeyboard() => (); - // Tells the SplitViewController to snap the given window to the left or - // right. The client name is used to find the client's WindowTree. - SnapWindowInSplitView(string client_name, uint64 window_id, bool left) => (); - // Fullscreens the active window, as if the user had pressed the hardware // fullscreen button. ToggleFullscreen() => ();
diff --git a/ash/public/interfaces/split_view.mojom b/ash/public/interfaces/split_view.mojom deleted file mode 100644 index ee5581e..0000000 --- a/ash/public/interfaces/split_view.mojom +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -module ash.mojom; - -enum SplitViewState { - NO_SNAP, - LEFT_SNAPPED, - RIGHT_SNAPPED, - BOTH_SNAPPED, -}; - -// Used to listen for split view state changes. -interface SplitViewObserver { - OnSplitViewStateChanged(SplitViewState current_state); -}; - -// The split view controller that allows clients (Chrome) to observe the split -// view state changes. -interface SplitViewController { - // Adds an observer. - AddObserver(SplitViewObserver observer); -};
diff --git a/ash/session/session_controller_impl.cc b/ash/session/session_controller_impl.cc index 8f5b02f..9e0b73e 100644 --- a/ash/session/session_controller_impl.cc +++ b/ash/session/session_controller_impl.cc
@@ -460,7 +460,7 @@ CanSwitchActiveUserCallback callback) { // Cancel overview mode when switching user profiles. OverviewController* controller = Shell::Get()->overview_controller(); - if (controller->IsSelecting()) + if (controller->InOverviewSession()) controller->ToggleOverview(); ash::Shell::Get()
diff --git a/ash/session/session_controller_impl_unittest.cc b/ash/session/session_controller_impl_unittest.cc index 97a9273..6225b5a 100644 --- a/ash/session/session_controller_impl_unittest.cc +++ b/ash/session/session_controller_impl_unittest.cc
@@ -638,8 +638,8 @@ bool ToggleOverview() { return Shell::Get()->overview_controller()->ToggleOverview(); } - bool IsSelecting() const { - return Shell::Get()->overview_controller()->IsSelecting(); + bool InOverviewSession() const { + return Shell::Get()->overview_controller()->InOverviewSession(); } // Various counter accessors. @@ -794,9 +794,9 @@ gfx::Rect bounds(0, 0, 100, 100); std::unique_ptr<aura::Window> w(CreateTestWindowInShellWithBounds(bounds)); ASSERT_TRUE(ToggleOverview()); - ASSERT_TRUE(IsSelecting()); + ASSERT_TRUE(InOverviewSession()); SwitchUser(CanSwitchUserTest::NO_DIALOG); - ASSERT_FALSE(IsSelecting()); + ASSERT_FALSE(InOverviewSession()); EXPECT_EQ(1, switch_callback_hit_count()); }
diff --git a/ash/shelf/app_list_button_unittest.cc b/ash/shelf/app_list_button_unittest.cc index 8c5a2506..e70bcfac 100644 --- a/ash/shelf/app_list_button_unittest.cc +++ b/ash/shelf/app_list_button_unittest.cc
@@ -305,7 +305,7 @@ // Enter Overview mode. OverviewController* overview_controller = Shell::Get()->overview_controller(); ASSERT_TRUE(overview_controller->ToggleOverview()); - ASSERT_TRUE(overview_controller->IsSelecting()); + ASSERT_TRUE(overview_controller->InOverviewSession()); test_api.RunMessageLoopUntilAnimationsDone(); // Tapping the home button should exit Overview mode. @@ -313,7 +313,7 @@ views::View::ConvertPointToScreen(app_list_button(), ¢er); GetEventGenerator()->GestureTapDownAndUp(center); test_api.RunMessageLoopUntilAnimationsDone(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); // TODO(michaelpg): Create a Home Screen aura::Window* and verify its state. }
diff --git a/ash/shelf/back_button_unittest.cc b/ash/shelf/back_button_unittest.cc index 61a7381..adbb525 100644 --- a/ash/shelf/back_button_unittest.cc +++ b/ash/shelf/back_button_unittest.cc
@@ -158,7 +158,7 @@ // home screen. OverviewController* overview_controller = Shell::Get()->overview_controller(); ASSERT_TRUE(overview_controller->ToggleOverview()); - ASSERT_TRUE(overview_controller->IsSelecting()); + ASSERT_TRUE(overview_controller->InOverviewSession()); test_api()->RunMessageLoopUntilAnimationsDone(); // Register an accelerator that looks for back releases. @@ -174,13 +174,13 @@ generator->MoveMouseTo(back_button()->GetBoundsInScreen().CenterPoint()); generator->PressLeftButton(); EXPECT_EQ(0, target_back_release.accelerator_count()); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); // Verify that by releasing the back button, the accelerator is triggered, // exiting Overview mode and sending a release event. generator->ReleaseLeftButton(); EXPECT_EQ(1, target_back_release.accelerator_count()); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); } } // namespace ash
diff --git a/ash/shelf/shelf_layout_manager.cc b/ash/shelf/shelf_layout_manager.cc index 1de47e81..a932f19 100644 --- a/ash/shelf/shelf_layout_manager.cc +++ b/ash/shelf/shelf_layout_manager.cc
@@ -36,6 +36,7 @@ #include "ash/wm/mru_window_tracker.h" #include "ash/wm/overview/overview_controller.h" #include "ash/wm/screen_pinning_controller.h" +#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" @@ -535,7 +536,7 @@ } if (Shell::Get()->overview_controller() && - Shell::Get()->overview_controller()->IsSelecting()) { + Shell::Get()->overview_controller()->InOverviewSession()) { return SHELF_BACKGROUND_OVERVIEW; } @@ -979,7 +980,7 @@ // movement on async preference initialization in tests: crbug.com/834369 display_ = display::Screen::GetScreen()->GetDisplayNearestWindow( shelf_widget_->GetNativeWindow()); - bool in_overview = Shell::Get()->overview_controller()->IsSelecting(); + bool in_overview = Shell::Get()->overview_controller()->InOverviewSession(); if (!in_overview && !state_.IsScreenLocked() && (shelf_->alignment() != SHELF_ALIGNMENT_BOTTOM_LOCKED || display_.work_area() == display_.bounds())) { @@ -1273,7 +1274,7 @@ // Do not hide the shelf if overview mode is active. if (Shell::Get()->overview_controller() && - Shell::Get()->overview_controller()->IsSelecting()) { + Shell::Get()->overview_controller()->InOverviewSession()) { return SHELF_AUTO_HIDE_SHOWN; } @@ -1421,7 +1422,7 @@ if (!IsHomeScreenAvailable()) return false; - return !Shell::Get()->overview_controller()->IsSelecting() && + return !Shell::Get()->overview_controller()->InOverviewSession() && !HasVisibleWindow(); }
diff --git a/ash/shell_test_api.cc b/ash/shell_test_api.cc index bab2bfc9..d3cbc40 100644 --- a/ash/shell_test_api.cc +++ b/ash/shell_test_api.cc
@@ -205,26 +205,6 @@ std::move(cb).Run(); } -void ShellTestApi::SnapWindowInSplitView(const std::string& client_name, - ws::Id window_id, - bool left, - SnapWindowInSplitViewCallback cb) { - auto* window_service = shell_->window_service_owner()->window_service(); - aura::Window* window = nullptr; - for (ws::WindowTree* window_tree : window_service->window_trees()) { - if (client_name == window_tree->client_name()) { - window = window_tree->GetWindowByTransportId(window_id); - break; - } - } - DCHECK(window); - shell_->split_view_controller()->SnapWindow( - window, - left ? ash::SplitViewController::LEFT : ash::SplitViewController::RIGHT); - shell_->split_view_controller()->FlushForTesting(); - std::move(cb).Run(); -} - void ShellTestApi::ToggleFullscreen(ToggleFullscreenCallback cb) { ash::accelerators::ToggleFullscreen(); std::move(cb).Run(); @@ -236,7 +216,7 @@ } void ShellTestApi::IsOverviewSelecting(IsOverviewSelectingCallback callback) { - std::move(callback).Run(shell_->overview_controller()->IsSelecting()); + std::move(callback).Run(shell_->overview_controller()->InOverviewSession()); } void ShellTestApi::AddRemoveDisplay() { @@ -273,14 +253,14 @@ WaitForOverviewAnimationStateCallback callback) { auto* overview_controller = Shell::Get()->overview_controller(); if (state == mojom::OverviewAnimationState::kEnterAnimationComplete && - overview_controller->IsSelecting() && + overview_controller->InOverviewSession() && !overview_controller->IsInStartAnimation()) { // If there is no animation applied, call the callback immediately. std::move(callback).Run(); return; } if (state == mojom::OverviewAnimationState::kExitAnimationComplete && - !overview_controller->IsSelecting() && + !overview_controller->InOverviewSession() && !overview_controller->IsCompletingShutdownAnimations()) { // If there is no animation applied, call the callback immediately. std::move(callback).Run();
diff --git a/ash/shell_test_api.h b/ash/shell_test_api.h index f29399a..b8256c7 100644 --- a/ash/shell_test_api.h +++ b/ash/shell_test_api.h
@@ -55,10 +55,6 @@ void IsSystemModalWindowOpen(IsSystemModalWindowOpenCallback cb) override; void EnableTabletModeWindowManager(bool enable) override; void EnableVirtualKeyboard(EnableVirtualKeyboardCallback cb) override; - void SnapWindowInSplitView(const std::string& client_name, - ws::Id window_id, - bool left, - SnapWindowInSplitViewCallback cb) override; void ToggleFullscreen(ToggleFullscreenCallback cb) override; void ToggleOverviewMode(ToggleOverviewModeCallback cb) override; void IsOverviewSelecting(IsOverviewSelectingCallback callback) override;
diff --git a/ash/system/overview/overview_button_tray.cc b/ash/system/overview/overview_button_tray.cc index 6014b96f..134c511 100644 --- a/ash/system/overview/overview_button_tray.cc +++ b/ash/system/overview/overview_button_tray.cc
@@ -84,7 +84,7 @@ OverviewController* overview_controller = Shell::Get()->overview_controller(); // Skip if the second tap happened outside of overview. This can happen if a // window gets activated in between, which cancels overview mode. - if (overview_controller->IsSelecting() && last_press_event_time_ && + if (overview_controller->InOverviewSession() && last_press_event_time_ && event.time_stamp() - last_press_event_time_.value() < kDoubleTapThresholdMs) { base::RecordAction(base::UserMetricsAction("Tablet_QuickSwitch")); @@ -127,9 +127,10 @@ // If not in overview mode record the time of this tap. A subsequent tap will // be checked against this to see if we should quick switch. - last_press_event_time_ = Shell::Get()->overview_controller()->IsSelecting() - ? base::nullopt - : base::make_optional(event.time_stamp()); + last_press_event_time_ = + Shell::Get()->overview_controller()->InOverviewSession() + ? base::nullopt + : base::make_optional(event.time_stamp()); OverviewController* controller = Shell::Get()->overview_controller(); // Note: Toggling overview mode will fail if there is no window to show, the
diff --git a/ash/system/overview/overview_button_tray_unittest.cc b/ash/system/overview/overview_button_tray_unittest.cc index 82a653e..7ae6e3c 100644 --- a/ash/system/overview/overview_button_tray_unittest.cc +++ b/ash/system/overview/overview_button_tray_unittest.cc
@@ -119,23 +119,23 @@ // Tests that activating this control brings up window selection mode. TEST_F(OverviewButtonTrayTest, PerformAction) { - ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // Overview Mode only works when there is a window std::unique_ptr<aura::Window> window( CreateTestWindowInShellWithBounds(gfx::Rect(5, 5, 20, 20))); GetTray()->PerformAction(CreateTapEvent()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Verify tapping on the button again closes overview mode. GetTray()->PerformAction(CreateTapEvent()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } TEST_F(OverviewButtonTrayTest, PerformDoubleTapAction) { TabletModeControllerTestApi().EnterTabletMode(); - ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // Add two windows and activate the second one to test quick switch. std::unique_ptr<aura::Window> window1( @@ -148,21 +148,21 @@ // Verify that after double tapping, we have switched to window 1. PerformDoubleTap(); EXPECT_TRUE(wm::IsActiveWindow(window1.get())); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // Verify that if we double tap on the window selection page, it acts as two // taps, and ends up on the window selection page again. ui::GestureEvent tap = CreateTapEvent(); ASSERT_TRUE(wm::IsActiveWindow(window1.get())); GetTray()->PerformAction(tap); - ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); PerformDoubleTap(); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Verify that if we minimize a window, double tapping the overlay tray button // will bring up the window, and it should be the active window. GetTray()->PerformAction(tap); - ASSERT_TRUE(!Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(!Shell::Get()->overview_controller()->InOverviewSession()); ASSERT_TRUE(wm::IsActiveWindow(window1.get())); wm::GetWindowState(window2.get())->Minimize(); ASSERT_EQ(window2->layer()->GetTargetOpacity(), 0.0); @@ -172,7 +172,7 @@ // Verify that if all windows are minimized, double tapping the tray will have // no effect. - ASSERT_TRUE(!Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(!Shell::Get()->overview_controller()->InOverviewSession()); wm::GetWindowState(window1.get())->Minimize(); wm::GetWindowState(window2.get())->Minimize(); PerformDoubleTap(); @@ -182,7 +182,7 @@ // Tests that tapping on the control will record the user action Tray_Overview. TEST_F(OverviewButtonTrayTest, TrayOverviewUserAction) { - ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // With one window present, tapping on the control to enter overview mode // should record the user action. @@ -191,14 +191,14 @@ CreateTestWindowInShellWithBounds(gfx::Rect(5, 5, 20, 20))); GetTray()->PerformAction( CreateTapEvent(OverviewButtonTray::kDoubleTapThresholdMs)); - ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(1, user_action_tester.GetActionCount(kTrayOverview)); // Tapping on the control to exit overview mode should record the // user action. GetTray()->PerformAction( CreateTapEvent(OverviewButtonTray::kDoubleTapThresholdMs * 2)); - ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(2, user_action_tester.GetActionCount(kTrayOverview)); } @@ -253,7 +253,7 @@ // Tests that the tray only renders as active while selection is ongoing. Any // dismissal of overview mode clears the active state. TEST_F(OverviewButtonTrayTest, ActiveStateOnlyDuringOverviewMode) { - ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); ASSERT_FALSE(GetTray()->is_active()); // Overview Mode only works when there is a window @@ -261,11 +261,11 @@ CreateTestWindowInShellWithBounds(gfx::Rect(5, 5, 20, 20))); EXPECT_TRUE(Shell::Get()->overview_controller()->ToggleOverview()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_TRUE(GetTray()->is_active()); EXPECT_TRUE(Shell::Get()->overview_controller()->ToggleOverview()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_FALSE(GetTray()->is_active()); }
diff --git a/ash/wallpaper/wallpaper_view.cc b/ash/wallpaper/wallpaper_view.cc index ef9d6b6..0627ab5 100644 --- a/ash/wallpaper/wallpaper_view.cc +++ b/ash/wallpaper/wallpaper_view.cc
@@ -94,7 +94,7 @@ ->tablet_mode_controller() ->IsTabletModeWindowManagerEnabled()) { alpha = kTabletModeWallpaperAlpha; - } else if (Shell::Get()->overview_controller()->IsSelecting()) { + } else if (Shell::Get()->overview_controller()->InOverviewSession()) { // Overview mode will apply its own brightness filter on a downscaled image, // so color with full opacity here. alpha = 255; @@ -129,7 +129,7 @@ void HandleClickOrTap(ui::Event* event) { CHECK_EQ(ui::EP_PRETARGET, event->phase()); OverviewController* controller = Shell::Get()->overview_controller(); - if (!controller->IsSelecting()) + if (!controller->InOverviewSession()) return; // Events that happen while app list is sliding out during overview should // be ignored to prevent overview from disappearing out from under the user.
diff --git a/ash/wm/desks/desk_mini_view_animations.cc b/ash/wm/desks/desk_mini_view_animations.cc index c271fa9f..c9cd7c61 100644 --- a/ash/wm/desks/desk_mini_view_animations.cc +++ b/ash/wm/desks/desk_mini_view_animations.cc
@@ -101,7 +101,7 @@ layer->SetTransform(gfx::Transform()); auto* controller = Shell::Get()->overview_controller(); - DCHECK(controller->IsSelecting()); + DCHECK(controller->InOverviewSession()); controller->overview_session()->PositionWindows(true); }
diff --git a/ash/wm/desks/desks_controller.cc b/ash/wm/desks/desks_controller.cc index 1dcf89d..32465398 100644 --- a/ash/wm/desks/desks_controller.cc +++ b/ash/wm/desks/desks_controller.cc
@@ -29,7 +29,7 @@ // overview grid. void AppendWindowsToOverview(const base::flat_set<aura::Window*>& windows, bool should_animate) { - DCHECK(Shell::Get()->overview_controller()->IsSelecting()); + DCHECK(Shell::Get()->overview_controller()->InOverviewSession()); auto* overview_session = Shell::Get()->overview_controller()->overview_session(); @@ -44,7 +44,7 @@ // Removes the given |windows| from the currently active overview mode session. void RemoveWindowsFromOverview(const base::flat_set<aura::Window*>& windows) { - DCHECK(Shell::Get()->overview_controller()->IsSelecting()); + DCHECK(Shell::Get()->overview_controller()->InOverviewSession()); auto* overview_session = Shell::Get()->overview_controller()->overview_session(); @@ -125,7 +125,8 @@ DCHECK(!desks_.empty()); - const bool is_selecting = Shell::Get()->overview_controller()->IsSelecting(); + const bool in_overview = + Shell::Get()->overview_controller()->InOverviewSession(); const base::flat_set<aura::Window*> removed_desk_windows = removed_desk->windows(); @@ -139,7 +140,7 @@ // overview grid in the order of their MRU. Note that this can only be done // after the windows have moved to the active desk above, so that building // the window MRU list should contain those windows. - if (is_selecting) + if (in_overview) AppendWindowsToOverview(removed_desk_windows, /*should_animate=*/true); } else { Desk* target_desk = nullptr; @@ -158,7 +159,7 @@ // "OverviewModeLabel" widgets created by overview mode for these windows. // This way the removed desk tracks only real windows, which are now ready // to be moved to the target desk. - if (is_selecting) + if (in_overview) RemoveWindowsFromOverview(removed_desk_windows); // If overview mode is active, change desk activation without changing @@ -166,11 +167,11 @@ // "OverviewModeFocusedWidget" while overview mode is active. removed_desk->MoveWindowsToDesk(target_desk); ActivateDeskInternal(target_desk, - /*update_window_activation=*/!is_selecting); + /*update_window_activation=*/!in_overview); // Now that the windows from the removed and target desks merged, add them // all without animation to the grid in the order of their MRU. - if (is_selecting) + if (in_overview) AppendWindowsToOverview(target_desk->windows(), /*should_animate=*/false); } @@ -188,7 +189,7 @@ if (desk == active_desk_) { OverviewController* overview_controller = Shell::Get()->overview_controller(); - if (overview_controller->IsSelecting()) { + if (overview_controller->InOverviewSession()) { // Selecting the active desk's mini_view in overview mode is allowed and // should just exit overview mode normally. overview_controller->ToggleOverview(); @@ -240,14 +241,16 @@ for (auto* root : roots) root->GetHost()->compositor()->SetAllowLocksToExtendTimeout(true); - const bool is_selecting = Shell::Get()->overview_controller()->IsSelecting(); + const bool in_overview = + Shell::Get()->overview_controller()->InOverviewSession(); ActivateDeskInternal(ending_desk, /*update_window_activation=*/true); // Activating a desk should not change the overview mode state. - DCHECK_EQ(is_selecting, Shell::Get()->overview_controller()->IsSelecting()); + DCHECK_EQ(in_overview, + Shell::Get()->overview_controller()->InOverviewSession()); - if (is_selecting) { + if (in_overview) { // Exit overview mode immediately without any animations before taking the // ending desk screenshot. This makes sure that the ending desk // screenshot will only show the windows in that desk, not overview stuff.
diff --git a/ash/wm/desks/desks_unittests.cc b/ash/wm/desks/desks_unittests.cc index f8c24d8..425959d 100644 --- a/ash/wm/desks/desks_unittests.cc +++ b/ash/wm/desks/desks_unittests.cc
@@ -53,7 +53,7 @@ DCHECK(root->IsRootWindow()); auto* overview_controller = Shell::Get()->overview_controller(); - DCHECK(overview_controller->IsSelecting()); + DCHECK(overview_controller->InOverviewSession()); return overview_controller->overview_session()->GetGridWithRootWindow(root); } @@ -209,7 +209,7 @@ auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); const auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow()); @@ -267,9 +267,9 @@ // desks, their mini_views should be created upon construction of the desks // bar. overview_controller->ToggleOverview(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); // Get the new grid and the new desk_bar_view. overview_grid = @@ -538,7 +538,7 @@ // grid. auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); const auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow()); const auto* desks_bar_view = overview_grid->GetDesksBarViewForTesting(); @@ -562,7 +562,7 @@ // Expect that desk_4 is now active, and overview mode exited. EXPECT_TRUE(desk_4->is_active()); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); // Exiting overview mode should not restore focus to a window on a // now-inactive desk. Run a loop since the overview session is destroyed async // and until that happens, focus will be on the dummy @@ -575,14 +575,14 @@ auto win2 = CreateTestWindow(gfx::Rect(50, 50, 200, 200)); wm::ActivateWindow(win2.get()); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow()); EXPECT_EQ(1u, overview_grid->window_list().size()); // When exiting overview mode without changing desks, the focus should be // restored to the same window. overview_controller->ToggleOverview(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); // Run a loop since the overview session is destroyed async and until that // happens, focus will be on the dummy "OverviewModeFocusedWidget". base::RunLoop().RunUntilIdle(); @@ -605,7 +605,7 @@ // Enter overview mode. auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); auto roots = Shell::GetAllRootWindows(); ASSERT_EQ(2u, roots.size()); @@ -629,7 +629,7 @@ // Expect that desk_4 is now active, and overview mode exited. EXPECT_TRUE(desk_4->is_active()); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); } TEST_F(DesksTest, RemoveInactiveDeskFromOverview) { @@ -653,7 +653,7 @@ ActivateDesk(desk_4); auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); const auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow()); EXPECT_TRUE(overview_grid->window_list().empty()); @@ -670,7 +670,7 @@ CloseDeskFromMiniView(mini_view, GetEventGenerator()); ASSERT_EQ(3u, desks_bar_view->mini_views().size()); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); ASSERT_EQ(2u, overview_grid->window_list().size()); EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win0.get())); EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win1.get())); @@ -681,7 +681,7 @@ // Make sure overview mode remains active. base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); } TEST_F(DesksTest, RemoveActiveDeskFromOverview) { @@ -707,7 +707,7 @@ // Enter overview mode, and remove desk_2 from its mini-view close button. auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); const auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow()); EXPECT_EQ(1u, overview_grid->window_list().size()); @@ -724,7 +724,7 @@ ASSERT_EQ(1u, desks_bar_view->mini_views().size()); const Desk* desk_1 = controller->desks()[0].get(); EXPECT_TRUE(desk_1->is_active()); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_EQ(3u, overview_grid->window_list().size()); EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win0.get())); EXPECT_TRUE(overview_grid->GetOverviewItemContaining(win1.get())); @@ -740,7 +740,7 @@ // Make sure overview mode remains active. base::RunLoop().RunUntilIdle(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); } TEST_F(DesksTest, ActivateActiveDeskFromOverview) { @@ -755,14 +755,14 @@ // overview mode exits since this is the already active desk. auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); const auto* overview_grid = GetOverviewGridForRoot(Shell::GetPrimaryRootWindow()); const auto* desks_bar_view = overview_grid->GetDesksBarViewForTesting(); const Desk* desk_1 = controller->desks()[0].get(); const auto* mini_view = desks_bar_view->mini_views().front().get(); ClickOnMiniView(mini_view, GetEventGenerator()); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); EXPECT_TRUE(desk_1->is_active()); EXPECT_EQ(desk_1, controller->active_desk()); }
diff --git a/ash/wm/gestures/overview_gesture_handler.cc b/ash/wm/gestures/overview_gesture_handler.cc index e7ec20cc..174776e2 100644 --- a/ash/wm/gestures/overview_gesture_handler.cc +++ b/ash/wm/gestures/overview_gesture_handler.cc
@@ -37,7 +37,7 @@ // Horizontal 3-finger scroll moves selection when already in overview mode. if (std::fabs(scroll_x_) >= std::fabs(scroll_y_)) { - if (!overview_controller->IsSelecting()) { + if (!overview_controller->InOverviewSession()) { scroll_x_ = scroll_y_ = 0; return false; } @@ -51,7 +51,7 @@ } // Use vertical 3-finger scroll gesture up to enter overview, down to exit. - if (overview_controller->IsSelecting()) { + if (overview_controller->InOverviewSession()) { if (scroll_y_ < 0) scroll_x_ = scroll_y_ = 0; if (scroll_y_ < vertical_threshold_pixels_) @@ -66,7 +66,7 @@ // Reset scroll amount on toggling. scroll_x_ = scroll_y_ = 0; base::RecordAction(base::UserMetricsAction("Touchpad_Gesture_Overview")); - if (overview_controller->IsSelecting() && + if (overview_controller->InOverviewSession() && overview_controller->AcceptSelection()) { return true; }
diff --git a/ash/wm/gestures/overview_gesture_handler_unittest.cc b/ash/wm/gestures/overview_gesture_handler_unittest.cc index 441f114c..020c0eb5 100644 --- a/ash/wm/gestures/overview_gesture_handler_unittest.cc +++ b/ash/wm/gestures/overview_gesture_handler_unittest.cc
@@ -31,8 +31,8 @@ Shell::Get()->overview_controller()->ToggleOverview(); } - bool IsSelecting() { - return Shell::Get()->overview_controller()->IsSelecting(); + bool InOverviewSession() { + return Shell::Get()->overview_controller()->InOverviewSession(); } float vertical_threshold_pixels() const { @@ -60,22 +60,22 @@ const float long_scroll = 2 * vertical_threshold_pixels(); generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), 0, -long_scroll, 100, 3); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Swiping up again does nothing. generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), 0, -long_scroll, 100, 3); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Swiping down exits. generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), 0, long_scroll, 100, 3); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); // Swiping down again does nothing. generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), 0, long_scroll, 100, 3); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Tests three finger horizontal scroll gesture to move selection left or right. @@ -94,27 +94,27 @@ // Entering overview mode with an upwards three-finger scroll gesture would // have the same result (allow selection using horizontal scroll). ToggleOverview(); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Long scroll right moves selection to the fourth window. generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), horizontal_scroll * 4, 0, 100, 3); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Short scroll left (3 fingers) moves selection to the third window. generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), -horizontal_scroll, 0, 100, 3); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Short scroll left (3 fingers) moves selection to the second window. generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), -horizontal_scroll, 0, 100, 3); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Swiping down exits and selects the currently-highlighted window. generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), 0, vertical_scroll, 100, 3); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); // Second MRU window is selected (i.e. |window4|). EXPECT_EQ(window4.get(), wm::GetActiveWindow()); @@ -130,11 +130,11 @@ const float long_scroll = 2 * vertical_threshold_pixels(); generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), long_scroll + 100, -long_scroll, 100, 3); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); generator.ScrollSequence(gfx::Point(), base::TimeDelta::FromMilliseconds(5), -long_scroll - 100, -long_scroll, 100, 3); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Tests a scroll up with three fingers without releasing followed by a scroll @@ -161,7 +161,7 @@ generator.Dispatch(&move); } - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Without releasing scroll back down by 600px. for (int i = 0; i < 60; ++i) { @@ -171,7 +171,7 @@ generator.Dispatch(&move); } - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); ui::ScrollEvent fling_start(ui::ET_SCROLL_FLING_START, start, timestamp, 0, 0, 10, 0, 10, num_fingers); generator.Dispatch(&fling_start);
diff --git a/ash/wm/overview/cleanup_animation_observer_unittest.cc b/ash/wm/overview/cleanup_animation_observer_unittest.cc index bd11e4d..9d38512 100644 --- a/ash/wm/overview/cleanup_animation_observer_unittest.cc +++ b/ash/wm/overview/cleanup_animation_observer_unittest.cc
@@ -32,19 +32,16 @@ } // OverviewDelegate: - void OnSelectionEnded() override {} - + void EndOverview() override {} void AddExitAnimationObserver( std::unique_ptr<DelayedAnimationObserver> animation_observer) override { animation_observer->SetOwner(this); observers_.push_back(std::move(animation_observer)); } - void RemoveAndDestroyExitAnimationObserver( DelayedAnimationObserver* animation_observer) override { base::EraseIf(observers_, base::MatchesUniquePtr(animation_observer)); } - void AddEnterAnimationObserver( std::unique_ptr<DelayedAnimationObserver> animation_observer) override {} void RemoveAndDestroyEnterAnimationObserver(
diff --git a/ash/wm/overview/delayed_animation_observer_impl_unittest.cc b/ash/wm/overview/delayed_animation_observer_impl_unittest.cc index dac7cb1..a842233 100644 --- a/ash/wm/overview/delayed_animation_observer_impl_unittest.cc +++ b/ash/wm/overview/delayed_animation_observer_impl_unittest.cc
@@ -25,7 +25,7 @@ ~TestOverviewDelegate() override = default; // OverviewDelegate: - void OnSelectionEnded() override {} + void EndOverview() override {} void AddExitAnimationObserver( std::unique_ptr<DelayedAnimationObserver> animation_observer) override { animation_observer->SetOwner(this);
diff --git a/ash/wm/overview/overview_controller.cc b/ash/wm/overview/overview_controller.cc index cbe42e5f..be2b2237 100644 --- a/ash/wm/overview/overview_controller.cc +++ b/ash/wm/overview/overview_controller.cc
@@ -44,9 +44,9 @@ namespace { -// Do not blur or unblur the wallpaper when entering or exiting overview mode -// when this is true. -bool g_disable_wallpaper_blur_for_tests = false; +// Do not change the wallpaper when entering or exiting overview mode when this +// is true. +bool g_disable_wallpaper_change_for_tests = false; constexpr int kBlurSlideDurationMs = 250; @@ -59,8 +59,8 @@ // overview mode immediately, contents are ready. constexpr int kOcclusionPauseDurationForEndMs = 500; -bool IsBlurAllowed() { - return !g_disable_wallpaper_blur_for_tests && +bool IsWallpaperChangeAllowed() { + return !g_disable_wallpaper_change_for_tests && Shell::Get()->wallpaper_controller()->IsBlurAllowed(); } @@ -92,14 +92,13 @@ // exiting overview mode. Blurs the wallpaper automatically if the wallpaper is // not visible prior to entering overview mode (covered by a window), otherwise // animates the blur and dim. -// TODO(sammiequon): Rename since this dims as well now. -class OverviewController::OverviewBlurController +class OverviewController::OverviewWallpaperController : public ui::CompositorAnimationObserver, public aura::WindowObserver { public: - OverviewBlurController() = default; + OverviewWallpaperController() = default; - ~OverviewBlurController() override { + ~OverviewWallpaperController() override { if (compositor_) compositor_->RemoveAnimationObserver(this); for (aura::Window* root : roots_to_animate_) @@ -253,12 +252,13 @@ // blur animated after Blur or Unblur is called. std::vector<aura::Window*> roots_to_animate_; - DISALLOW_COPY_AND_ASSIGN(OverviewBlurController); + DISALLOW_COPY_AND_ASSIGN(OverviewWallpaperController); }; OverviewController::OverviewController() : occlusion_pause_duration_for_end_ms_(kOcclusionPauseDurationForEndMs), - overview_blur_controller_(std::make_unique<OverviewBlurController>()), + overview_wallpaper_controller_( + std::make_unique<OverviewWallpaperController>()), delayed_animation_task_delay_(kTransition), weak_ptr_factory_(this) { Shell::Get()->activation_client()->AddObserver(this); @@ -266,7 +266,7 @@ OverviewController::~OverviewController() { Shell::Get()->activation_client()->RemoveObserver(this); - overview_blur_controller_.reset(); + overview_wallpaper_controller_.reset(); // Destroy widgets that may be still animating if shell shuts down soon after // exiting overview mode. @@ -281,20 +281,6 @@ } } -// static -bool OverviewController::CanSelect() { - // Don't allow a window overview if the user session is not active (e.g. - // locked or in user-adding screen) or a modal dialog is open or running in - // kiosk app session. - SessionControllerImpl* session_controller = - Shell::Get()->session_controller(); - return session_controller->GetSessionState() == - session_manager::SessionState::ACTIVE && - !Shell::IsSystemModalWindowOpen() && - !Shell::Get()->screen_pinning_controller()->IsPinned() && - !session_controller->IsRunningInAppMode(); -} - bool OverviewController::ToggleOverview( OverviewSession::EnterExitOverviewType type) { // Hide the virtual keyboard as it obstructs the overview mode. @@ -325,7 +311,7 @@ new_type = OverviewSession::EnterExitOverviewType::kWindowsMinimized; } - if (IsSelecting()) { + if (InOverviewSession()) { // Do not allow ending overview if we're in single split mode unless swiping // up from the shelf in tablet mode. if (windows.empty() && @@ -358,10 +344,10 @@ wm::HideAndMaybeMinimizeWithoutAnimation(windows_to_hide_minimize, true); } - OnSelectionEnded(); + EndOverview(); } else { - // Don't start overview if window selection is not allowed. - if (!CanSelect()) + // Don't start overview if it is not allowed. + if (!CanEnterOverview()) return false; TRACE_EVENT_ASYNC_BEGIN0("ui", "OverviewController::EnterOverview", this); @@ -381,8 +367,8 @@ for (auto& observer : observers_) observer.OnOverviewModeStarting(); overview_session_->Init(windows, hide_windows); - if (IsBlurAllowed()) - overview_blur_controller_->Blur(/*animate_only=*/false); + if (IsWallpaperChangeAllowed()) + overview_wallpaper_controller_->Blur(/*animate_only=*/false); // For app dragging, there are no start animations so add a delay to delay // animations observing when the start animation ends, such as the shelf, @@ -397,57 +383,25 @@ if (start_animations_.empty()) OnStartingAnimationComplete(/*canceled=*/false); - OnSelectionStarted(); + if (!last_overview_session_time_.is_null()) { + UMA_HISTOGRAM_LONG_TIMES("Ash.WindowSelector.TimeBetweenUse", + base::Time::Now() - last_overview_session_time_); + } } return true; } -void OverviewController::OnStartingAnimationComplete(bool canceled) { - if (IsBlurAllowed() && !canceled) - overview_blur_controller_->Blur(/*animate_only=*/true); - - for (auto& observer : observers_) - observer.OnOverviewModeStartingAnimationComplete(canceled); - if (overview_session_) - overview_session_->OnStartingAnimationComplete(canceled); - UnpauseOcclusionTracker(kOcclusionPauseDurationForStartMs); - TRACE_EVENT_ASYNC_END1("ui", "OverviewController::EnterOverview", this, - "canceled", canceled); -} - -void OverviewController::OnEndingAnimationComplete(bool canceled) { - // Unblur when animation is completed (or right away if there was no - // delayed animation) unless it's canceled, in which case, we should keep - // the blur. - if (IsBlurAllowed() && !canceled) - overview_blur_controller_->Unblur(); - - for (auto& observer : observers_) - observer.OnOverviewModeEndingAnimationComplete(canceled); - UnpauseOcclusionTracker(occlusion_pause_duration_for_end_ms_); - TRACE_EVENT_ASYNC_END1("ui", "OverviewController::ExitOverview", this, - "canceled", canceled); -} - -void OverviewController::ResetPauser() { - occlusion_tracker_pauser_.reset(); -} - -bool OverviewController::IsSelecting() const { +bool OverviewController::InOverviewSession() const { return overview_session_ && !overview_session_->is_shutting_down(); } -bool OverviewController::IsCompletingShutdownAnimations() { - return !delayed_animations_.empty(); -} - void OverviewController::IncrementSelection(int increment) { - DCHECK(IsSelecting()); + DCHECK(InOverviewSession()); overview_session_->IncrementSelection(increment); } bool OverviewController::AcceptSelection() { - DCHECK(IsSelecting()); + DCHECK(InOverviewSession()); return overview_session_->AcceptSelection(); } @@ -474,7 +428,7 @@ // Exit split view mode if we are already in it. if (split_view_controller->InSplitViewMode()) { // In some cases the window returned by wm::GetActiveWindow will be an item - // in overview mode (maybe the overview mode text selection widget). The + // in overview mode (maybe the overview mode dummy focus widget). The // active window may also be a transient descendant of the left or right // snapped window, in which we want to activate the transient window's // ancestor (left or right snapped window). Manually set |active_window| as @@ -486,7 +440,7 @@ active_window = split_view_controller->GetDefaultSnappedWindow(); DCHECK(active_window); split_view_controller->EndSplitView(); - if (IsSelecting()) + if (InOverviewSession()) ToggleOverview(); MaximizeIfSnapped(active_window); ::wm::ActivateWindow(active_window); @@ -496,7 +450,7 @@ } OverviewItem* item_to_snap = nullptr; - if (!IsSelecting()) { + if (!InOverviewSession()) { // The current active window may be a transient child. aura::Window* active_window = wm::GetActiveWindow(); while (active_window && ::wm::GetTransientParent(active_window)) @@ -548,6 +502,10 @@ return !start_animations_.empty(); } +bool OverviewController::IsCompletingShutdownAnimations() { + return !delayed_animations_.empty(); +} + void OverviewController::PauseOcclusionTracker() { if (occlusion_tracker_pauser_) return; @@ -582,10 +540,9 @@ // TODO(flackr): Make OverviewController observe the activation of // windows, so we can remove OverviewDelegate. -// TODO(sammiequon): Rename to something like EndOverview() and refactor to use -// a single entry point for overview. -void OverviewController::OnSelectionEnded() { - if (!IsSelecting()) +// TODO(sammiequon): Refactor to use a single entry point for overview. +void OverviewController::EndOverview() { + if (!InOverviewSession()) return; if (!occlusion_tracker_pauser_) @@ -617,7 +574,7 @@ // Don't delete |overview_session_| yet since the stack is still using it. base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, overview_session_.release()); - last_selection_time_ = base::Time::Now(); + last_overview_session_time_ = base::Time::Now(); for (auto& observer : observers_) observer.OnOverviewModeEnded(); if (delayed_animations_.empty()) @@ -649,6 +606,21 @@ OnEndingAnimationComplete(/*canceled=*/false); } +void OverviewController::AddEnterAnimationObserver( + std::unique_ptr<DelayedAnimationObserver> animation_observer) { + animation_observer->SetOwner(this); + start_animations_.push_back(std::move(animation_observer)); +} + +void OverviewController::RemoveAndDestroyEnterAnimationObserver( + DelayedAnimationObserver* animation_observer) { + const bool previous_empty = start_animations_.empty(); + base::EraseIf(start_animations_, base::MatchesUniquePtr(animation_observer)); + + if (!previous_empty && start_animations_.empty()) + OnStartingAnimationComplete(/*canceled=*/false); +} + void OverviewController::OnWindowActivating(ActivationReason reason, aura::Window* gained_active, aura::Window* lost_active) { @@ -667,11 +639,11 @@ } bool OverviewController::HasBlurForTest() const { - return overview_blur_controller_->has_blur(); + return overview_wallpaper_controller_->has_blur(); } bool OverviewController::HasBlurAnimationForTest() const { - return overview_blur_controller_->has_blur_animation(); + return overview_wallpaper_controller_->has_blur_animation(); } std::vector<aura::Window*> @@ -685,19 +657,53 @@ return windows; } -void OverviewController::AddEnterAnimationObserver( - std::unique_ptr<DelayedAnimationObserver> animation_observer) { - animation_observer->SetOwner(this); - start_animations_.push_back(std::move(animation_observer)); +// static +void OverviewController::SetDoNotChangeWallpaperForTests() { + g_disable_wallpaper_change_for_tests = true; } -void OverviewController::RemoveAndDestroyEnterAnimationObserver( - DelayedAnimationObserver* animation_observer) { - const bool previous_empty = start_animations_.empty(); - base::EraseIf(start_animations_, base::MatchesUniquePtr(animation_observer)); +bool OverviewController::CanEnterOverview() { + // Don't allow a window overview if the user session is not active (e.g. + // locked or in user-adding screen) or a modal dialog is open or running in + // kiosk app session. + SessionControllerImpl* session_controller = + Shell::Get()->session_controller(); + return session_controller->GetSessionState() == + session_manager::SessionState::ACTIVE && + !Shell::IsSystemModalWindowOpen() && + !Shell::Get()->screen_pinning_controller()->IsPinned() && + !session_controller->IsRunningInAppMode(); +} - if (!previous_empty && start_animations_.empty()) - OnStartingAnimationComplete(/*canceled=*/false); +void OverviewController::OnStartingAnimationComplete(bool canceled) { + if (IsWallpaperChangeAllowed() && !canceled) + overview_wallpaper_controller_->Blur(/*animate_only=*/true); + + for (auto& observer : observers_) + observer.OnOverviewModeStartingAnimationComplete(canceled); + if (overview_session_) + overview_session_->OnStartingAnimationComplete(canceled); + UnpauseOcclusionTracker(kOcclusionPauseDurationForStartMs); + TRACE_EVENT_ASYNC_END1("ui", "OverviewController::EnterOverview", this, + "canceled", canceled); +} + +void OverviewController::OnEndingAnimationComplete(bool canceled) { + // Unblur when animation is completed (or right away if there was no + // delayed animation) unless it's canceled, in which case, we should keep + // the blur. + if (IsWallpaperChangeAllowed() && !canceled) + overview_wallpaper_controller_->Unblur(); + + for (auto& observer : observers_) + observer.OnOverviewModeEndingAnimationComplete(canceled); + UnpauseOcclusionTracker(occlusion_pause_duration_for_end_ms_); + TRACE_EVENT_ASYNC_END1("ui", "OverviewController::ExitOverview", this, + "canceled", canceled); +} + +void OverviewController::ResetPauser() { + occlusion_tracker_pauser_.reset(); } void OverviewController::UpdateMaskAndShadow() { @@ -705,16 +711,4 @@ overview_session_->UpdateMaskAndShadow(); } -// static -void OverviewController::SetDoNotChangeWallpaperBlurForTests() { - g_disable_wallpaper_blur_for_tests = true; -} - -void OverviewController::OnSelectionStarted() { - if (!last_selection_time_.is_null()) { - UMA_HISTOGRAM_LONG_TIMES("Ash.WindowSelector.TimeBetweenUse", - base::Time::Now() - last_selection_time_); - } -} - } // namespace ash
diff --git a/ash/wm/overview/overview_controller.h b/ash/wm/overview/overview_controller.h index f3ad60eff..7b7cd77 100644 --- a/ash/wm/overview/overview_controller.h +++ b/ash/wm/overview/overview_controller.h
@@ -29,22 +29,14 @@ OverviewController(); ~OverviewController() override; - // Returns true if selecting windows in an overview is enabled. This is false - // at certain times, such as when the lock screen is visible. - static bool CanSelect(); - // Attempts to toggle overview mode and returns true if successful (showing // overview would be unsuccessful if there are no windows to show). Depending // on |type| the enter/exit animation will look different. bool ToggleOverview(OverviewSession::EnterExitOverviewType type = OverviewSession::EnterExitOverviewType::kNormal); - // Returns true if window selection mode is active. - bool IsSelecting() const; - - // Returns true if overview has been shutdown, but is still animating to the - // end state ui. - bool IsCompletingShutdownAnimations(); + // Returns true if overview mode is active. + bool InOverviewSession() const; // Moves the current selection by |increment| items. Positive values of // |increment| move the selection forward, negative values move it backward. @@ -63,6 +55,10 @@ // Returns true if we're in start-overview animation. bool IsInStartAnimation(); + // Returns true if overview has been shutdown, but is still animating to the + // end state ui. + bool IsCompletingShutdownAnimations(); + // Pause or unpause the occlusion tracker. Resets the unpause delay if we were // already in the process of unpausing. void PauseOcclusionTracker(); @@ -75,7 +71,7 @@ void DelayedUpdateMaskAndShadow(); // OverviewDelegate: - void OnSelectionEnded() override; + void EndOverview() override; void AddExitAnimationObserver( std::unique_ptr<DelayedAnimationObserver> animation) override; void RemoveAndDestroyExitAnimationObserver( @@ -113,16 +109,17 @@ std::vector<aura::Window*> GetWindowsListInOverviewGridsForTest(); private: - class OverviewBlurController; + class OverviewWallpaperController; friend class OverviewSessionTest; FRIEND_TEST_ALL_PREFIXES(TabletModeControllerTest, DisplayDisconnectionDuringOverview); - // There is no need to blur or unblur the wallpaper for tests. - static void SetDoNotChangeWallpaperBlurForTests(); + // There is no need to blur or dim the wallpaper for tests. + static void SetDoNotChangeWallpaperForTests(); - // Dispatched when window selection begins. - void OnSelectionStarted(); + // Returns true if selecting windows in an overview is enabled. This is false + // at certain times, such as when the lock screen is visible. + bool CanEnterOverview(); void OnStartingAnimationComplete(bool canceled); void OnEndingAnimationComplete(bool canceled); @@ -143,13 +140,13 @@ occlusion_tracker_pauser_; std::unique_ptr<OverviewSession> overview_session_; - base::Time last_selection_time_; + base::Time last_overview_session_time_; int occlusion_pause_duration_for_end_ms_; - // Handles blurring of the wallpaper when entering or exiting overview mode. - // Animates the blurring if necessary. - std::unique_ptr<OverviewBlurController> overview_blur_controller_; + // Handles blurring and dimming of the wallpaper when entering or exiting + // overview mode. Animates the blurring and dimming if necessary. + std::unique_ptr<OverviewWallpaperController> overview_wallpaper_controller_; base::CancelableOnceClosure reset_pauser_task_;
diff --git a/ash/wm/overview/overview_controller_unittest.cc b/ash/wm/overview/overview_controller_unittest.cc index eb4a325..dbad209 100644 --- a/ash/wm/overview/overview_controller_unittest.cc +++ b/ash/wm/overview/overview_controller_unittest.cc
@@ -153,7 +153,7 @@ resizer->Drag(CalculateDragPoint(*resizer, 10, 0), 0); EXPECT_TRUE(wm::GetWindowState(dragged_window.get())->is_dragged()); GetEventGenerator()->PressKey(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_NONE); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); resizer->CompleteDrag(); } @@ -164,7 +164,7 @@ // Enter without windows. auto* shell = Shell::Get(); shell->overview_controller()->ToggleOverview(); - EXPECT_TRUE(shell->overview_controller()->IsSelecting()); + EXPECT_TRUE(shell->overview_controller()->InOverviewSession()); EXPECT_EQ(TestOverviewObserver::COMPLETED, observer.starting_animation_state()); auto* overview_controller = shell->overview_controller(); @@ -173,7 +173,7 @@ // Exit without windows still creates an animation. shell->overview_controller()->ToggleOverview(); - EXPECT_FALSE(shell->overview_controller()->IsSelecting()); + EXPECT_FALSE(shell->overview_controller()->InOverviewSession()); EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.ending_animation_state()); EXPECT_TRUE(overview_controller->HasBlurForTest()); EXPECT_TRUE(overview_controller->HasBlurAnimationForTest()); @@ -195,7 +195,7 @@ // Enter with windows. shell->overview_controller()->ToggleOverview(); - EXPECT_TRUE(shell->overview_controller()->IsSelecting()); + EXPECT_TRUE(shell->overview_controller()->InOverviewSession()); EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.starting_animation_state()); EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.ending_animation_state()); EXPECT_FALSE(overview_controller->HasBlurForTest()); @@ -203,7 +203,7 @@ // Exit with windows before starting animation ends. shell->overview_controller()->ToggleOverview(); - EXPECT_FALSE(shell->overview_controller()->IsSelecting()); + EXPECT_FALSE(shell->overview_controller()->InOverviewSession()); EXPECT_EQ(TestOverviewObserver::CANCELED, observer.starting_animation_state()); EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.ending_animation_state()); @@ -215,7 +215,7 @@ // Enter again before exit animation ends. shell->overview_controller()->ToggleOverview(); - EXPECT_TRUE(shell->overview_controller()->IsSelecting()); + EXPECT_TRUE(shell->overview_controller()->InOverviewSession()); EXPECT_EQ(TestOverviewObserver::UNKNOWN, observer.starting_animation_state()); EXPECT_EQ(TestOverviewObserver::CANCELED, observer.ending_animation_state()); // Blur animation will start when animation is completed. @@ -226,7 +226,7 @@ // Activating window while entering animation should cancel the overview. wm::ActivateWindow(window1.get()); - EXPECT_FALSE(shell->overview_controller()->IsSelecting()); + EXPECT_FALSE(shell->overview_controller()->InOverviewSession()); EXPECT_EQ(TestOverviewObserver::CANCELED, observer.starting_animation_state()); // Blur animation never started. @@ -249,7 +249,7 @@ EXPECT_FALSE(observer.last_animation_was_slide()); // Even with all window minimized, there should not be a slide animation. - ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); wm::GetWindowState(window.get())->Minimize(); Shell::Get()->overview_controller()->ToggleOverview(); EXPECT_FALSE(observer.last_animation_was_slide()); @@ -278,7 +278,7 @@ Shell::Get()->overview_controller()->ToggleOverview( OverviewSession::EnterExitOverviewType::kWindowsMinimized); EXPECT_TRUE(observer.last_animation_was_slide()); - ASSERT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_TRUE(wm::GetWindowState(window.get())->IsMinimized()); // All windows are minimized, so we should use the slide animation. @@ -354,7 +354,7 @@ observer.WaitForEndingAnimationComplete(); // Windows are visible because tracker is paused. - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(OcclusionState::VISIBLE, window2->occlusion_state()); EXPECT_EQ(OcclusionState::VISIBLE, window1->occlusion_state()); WaitForOcclusionStateChange(window2.get());
diff --git a/ash/wm/overview/overview_delegate.h b/ash/wm/overview/overview_delegate.h index 11e71588..451a08e 100644 --- a/ash/wm/overview/overview_delegate.h +++ b/ash/wm/overview/overview_delegate.h
@@ -15,8 +15,7 @@ // Implement this class to handle the selection event from OverviewSession. class ASH_EXPORT OverviewDelegate { public: - // Invoked if selection is ended. - virtual void OnSelectionEnded() = 0; + virtual void EndOverview() = 0; // Passes ownership of |animation_observer| to |this| delegate. virtual void AddExitAnimationObserver(
diff --git a/ash/wm/overview/overview_grid.cc b/ash/wm/overview/overview_grid.cc index 7ef7baab..14a248ff 100644 --- a/ash/wm/overview/overview_grid.cc +++ b/ash/wm/overview/overview_grid.cc
@@ -216,10 +216,10 @@ SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); switch (split_view_controller->state()) { - case SplitViewController::LEFT_SNAPPED: + case SplitViewState::kLeftSnapped: return split_view_controller->GetSnappedWindowBoundsInScreen( dragged_window, SplitViewController::RIGHT); - case SplitViewController::RIGHT_SNAPPED: + case SplitViewState::kRightSnapped: return split_view_controller->GetSnappedWindowBoundsInScreen( dragged_window, SplitViewController::LEFT); default: @@ -302,7 +302,7 @@ void UpdateWindowItemInOverviewContaining(aura::Window* window) { OverviewController* overview_controller = Shell::Get()->overview_controller(); - if (!overview_controller->IsSelecting()) + if (!overview_controller->InOverviewSession()) return; OverviewGrid* grid =
diff --git a/ash/wm/overview/overview_item.cc b/ash/wm/overview/overview_item.cc index 77e834e..3c89481 100644 --- a/ash/wm/overview/overview_item.cc +++ b/ash/wm/overview/overview_item.cc
@@ -379,7 +379,8 @@ void OverviewItem::SetBounds(const gfx::RectF& target_bounds, OverviewAnimationType animation_type) { - if (in_bounds_update_ || !Shell::Get()->overview_controller()->IsSelecting()) + if (in_bounds_update_ || + !Shell::Get()->overview_controller()->InOverviewSession()) return; // Do not animate if the resulting bounds does not change. The original @@ -543,10 +544,9 @@ overview_grid_->IsDropTargetWindow(GetWindow())) { visible = false; } else { - const SplitViewController::State state = - Shell::Get()->split_view_controller()->state(); - visible = state == SplitViewController::LEFT_SNAPPED || - state == SplitViewController::RIGHT_SNAPPED; + const SplitViewState state = Shell::Get()->split_view_controller()->state(); + visible = state == SplitViewState::kLeftSnapped || + state == SplitViewState::kRightSnapped; } if (!visible && !cannot_snap_widget_) @@ -734,7 +734,7 @@ bool should_show = true; OverviewController* overview_controller = Shell::Get()->overview_controller(); if (disable_mask_ || !overview_controller || - !overview_controller->IsSelecting() || + !overview_controller->InOverviewSession() || (!ash::features::ShouldUseShaderRoundedCorner() && overview_grid_->window_list().size() > 10) || overview_controller->IsInStartAnimation() || is_being_dragged_ || @@ -887,7 +887,7 @@ const gfx::Rect& new_bounds, ui::PropertyChangeReason reason) { // Do not keep the overview bounds if we're shutting down. - if (!Shell::Get()->overview_controller()->IsSelecting()) + if (!Shell::Get()->overview_controller()->InOverviewSession()) return; if (reason == ui::PropertyChangeReason::NOT_FROM_ANIMATION) {
diff --git a/ash/wm/overview/overview_item.h b/ash/wm/overview/overview_item.h index 324e5df..274beec8 100644 --- a/ash/wm/overview/overview_item.h +++ b/ash/wm/overview/overview_item.h
@@ -13,6 +13,7 @@ #include "ash/wm/overview/scoped_overview_transform_window.h" #include "base/containers/flat_map.h" #include "base/macros.h" +#include "ui/aura/window.h" #include "ui/aura/window_observer.h" #include "ui/compositor/layer_animation_observer.h" #include "ui/gfx/geometry/rect.h"
diff --git a/ash/wm/overview/overview_session.cc b/ash/wm/overview/overview_session.cc index 8f8314a5..72ddae3a 100644 --- a/ash/wm/overview/overview_session.cc +++ b/ash/wm/overview/overview_session.cc
@@ -352,7 +352,7 @@ } void OverviewSession::CancelSelection() { - delegate_->OnSelectionEnded(); + delegate_->EndOverview(); } void OverviewSession::OnGridEmpty(OverviewGrid* grid) { @@ -922,28 +922,26 @@ CancelSelection(); } -void OverviewSession::OnSplitViewStateChanged( - SplitViewController::State previous_state, - SplitViewController::State state) { +void OverviewSession::OnSplitViewStateChanged(SplitViewState previous_state, + SplitViewState state) { // Do nothing if overview is being shutdown. - if (!Shell::Get()->overview_controller()->IsSelecting()) + if (!Shell::Get()->overview_controller()->InOverviewSession()) return; const bool unsnappable_window_activated = - state == SplitViewController::NO_SNAP && + state == SplitViewState::kNoSnap && Shell::Get()->split_view_controller()->end_reason() == SplitViewController::EndReason::kUnsnappableWindowActivated; // Restore focus unless either a window was just snapped (and activated) or // split view mode was ended by activating an unsnappable window. - if (state != SplitViewController::NO_SNAP || unsnappable_window_activated) + if (state != SplitViewState::kNoSnap || unsnappable_window_activated) ResetFocusRestoreWindow(false); // If two windows were snapped to both sides of the screen or an unsnappable // window was just activated, or we're in single split mode in clamshell mode // and there is no window in overview, end overview mode and bail out. - if (state == SplitViewController::BOTH_SNAPPED || - unsnappable_window_activated || + if (state == SplitViewState::kBothSnapped || unsnappable_window_activated || (Shell::Get()->split_view_controller()->InClamshellSplitViewMode() && IsEmpty())) { CancelSelection(); @@ -956,7 +954,7 @@ grid->UpdateCannotSnapWarningVisibility(); // Notify |split_view_drag_indicators_| if split view mode ended. - if (split_view_drag_indicators_ && state == SplitViewController::NO_SNAP) + if (split_view_drag_indicators_ && state == SplitViewState::kNoSnap) split_view_drag_indicators_->OnSplitViewModeEnded(); } @@ -1088,11 +1086,10 @@ gfx::Rect bounds = display::Screen::GetScreen()->GetPrimaryDisplay().work_area(); auto* split_view_controller = Shell::Get()->split_view_controller(); - if (split_view_controller->state() == SplitViewController::LEFT_SNAPPED) { + if (split_view_controller->state() == SplitViewState::kLeftSnapped) { bounds = split_view_controller->GetSnappedWindowBoundsInScreen( window, SplitViewController::RIGHT); - } else if (split_view_controller->state() == - SplitViewController::RIGHT_SNAPPED) { + } else if (split_view_controller->state() == SplitViewState::kRightSnapped) { bounds = split_view_controller->GetSnappedWindowBoundsInScreen( window, SplitViewController::LEFT); }
diff --git a/ash/wm/overview/overview_session.h b/ash/wm/overview/overview_session.h index 3936b0d..e98f8d6c2 100644 --- a/ash/wm/overview/overview_session.h +++ b/ash/wm/overview/overview_session.h
@@ -12,9 +12,9 @@ #include <vector> #include "ash/ash_export.h" +#include "ash/public/cpp/split_view.h" #include "ash/shell_observer.h" #include "ash/wm/overview/scoped_overview_hide_windows.h" -#include "ash/wm/splitview/split_view_controller.h" #include "base/containers/flat_set.h" #include "base/macros.h" #include "base/time/time.h" @@ -25,10 +25,12 @@ namespace gfx { class Point; +class PointF; } // namespace gfx namespace ui { class KeyEvent; +class ScopedLayerAnimationSettings; } // namespace ui namespace views { @@ -51,7 +53,7 @@ public aura::WindowObserver, public ui::EventHandler, public ShellObserver, - public SplitViewController::Observer { + public SplitViewObserver { public: enum Direction { LEFT, UP, RIGHT, DOWN }; @@ -260,9 +262,9 @@ // ui::EventHandler: void OnKeyEvent(ui::KeyEvent* event) override; - // SplitViewController::Observer: - void OnSplitViewStateChanged(SplitViewController::State previous_state, - SplitViewController::State state) override; + // SplitViewObserver: + void OnSplitViewStateChanged(SplitViewState previous_state, + SplitViewState state) override; void OnSplitViewDividerPositionChanged() override; OverviewDelegate* delegate() { return delegate_; }
diff --git a/ash/wm/overview/overview_session_unittest.cc b/ash/wm/overview/overview_session_unittest.cc index 134c8ad..e98d0bd0 100644 --- a/ash/wm/overview/overview_session_unittest.cc +++ b/ash/wm/overview/overview_session_unittest.cc
@@ -146,7 +146,7 @@ GetPrimaryShelf()->GetShelfViewForTesting()); shelf_view_test_api_->SetAnimationDuration(1); ScopedOverviewTransformWindow::SetImmediateCloseForTests(); - OverviewController::SetDoNotChangeWallpaperBlurForTests(); + OverviewController::SetDoNotChangeWallpaperForTests(); FpsCounter::SetForceReportZeroAnimationForTest(true); ash::PresentationTimeRecorder::SetReportPresentationTimeImmediatelyForTest( true); @@ -233,7 +233,9 @@ GetEventGenerator()->ReleaseKey(key, flags); } - bool IsSelecting() { return overview_controller()->IsSelecting(); } + bool InOverviewSession() { + return overview_controller()->InOverviewSession(); + } const std::vector<std::unique_ptr<OverviewItem>>& GetWindowItemsForRoot( int index) { @@ -417,7 +419,7 @@ // Tests entering overview mode with two windows and selecting one by clicking. TEST_F(OverviewSessionTest, Basic) { // Overview disabled by default. - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); aura::Window* root_window = Shell::GetPrimaryRootWindow(); std::unique_ptr<aura::Window> window1(CreateTestWindow()); @@ -478,7 +480,7 @@ GetEventGenerator()->set_current_screen_location(point); GetEventGenerator()->ClickLeftButton(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); EXPECT_TRUE(window->IsVisible()); EXPECT_EQ(1.f, window->layer()->GetTargetOpacity()); @@ -640,7 +642,7 @@ // Tap on the desktop, which should not cause a crash. Overview mode should // be disengaged. GetEventGenerator()->GestureTapAt(gfx::Point(0, 0)); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); GetEventGenerator()->ReleaseTouchId(kTouchId); } @@ -667,7 +669,7 @@ GetEventGenerator()->PressTouchId(kTouchId); GetEventGenerator()->MoveMouseToCenterOf(window2.get()); GetEventGenerator()->ClickLeftButton(); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); EXPECT_FALSE(wm::IsActiveWindow(window2.get())); // Clicking on |window1| while touching on |window1| should not cause @@ -675,7 +677,7 @@ // be active. GetEventGenerator()->MoveMouseToCenterOf(window1.get()); GetEventGenerator()->ClickLeftButton(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); EXPECT_TRUE(wm::IsActiveWindow(window1.get())); GetEventGenerator()->ReleaseTouchId(kTouchId); } @@ -724,7 +726,7 @@ EXPECT_FALSE(widget->IsClosed()); GetEventGenerator()->ClickLeftButton(); EXPECT_TRUE(widget->IsClosed()); - ASSERT_TRUE(IsSelecting()); + ASSERT_TRUE(InOverviewSession()); aura::Window* minimized_window = minimized_widget->GetNativeWindow(); wm::WindowPreviewView* preview_view = @@ -742,7 +744,7 @@ // All minimized windows are closed, so it should exit overview mode. base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Tests minimizing/unminimizing in overview mode. @@ -755,13 +757,13 @@ widget->Minimize(); EXPECT_TRUE(widget->IsMinimized()); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); EXPECT_TRUE(GetPreviewView(GetWindowItemForWindow(0, window))); widget->Restore(); EXPECT_FALSE(widget->IsMinimized()); EXPECT_FALSE(GetPreviewView(GetWindowItemForWindow(0, window))); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); } // Tests that clicking on the close button on a secondary display effectively @@ -984,11 +986,11 @@ TEST_F(OverviewSessionTest, NewWindowCancelsOverview) { std::unique_ptr<aura::Window> window1(CreateTestWindow()); ToggleOverview(); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // A window being created should exit overview mode. std::unique_ptr<aura::Window> window2(CreateTestWindow()); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Tests that a window activation exits overview mode. @@ -997,11 +999,11 @@ std::unique_ptr<aura::Window> window2(CreateTestWindow()); window2->Focus(); ToggleOverview(); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // A window being activated should exit overview mode. window1->Focus(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); // window1 should be focused after exiting even though window2 was focused on // entering overview because we exited due to an activation. @@ -1017,21 +1019,21 @@ window1->SetProperty(aura::client::kAppType, static_cast<int>(AppType::BROWSER)); std::unique_ptr<aura::Window> window2(CreateTestWindow()); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); // Start drag on |window1|. std::unique_ptr<WindowResizer> resizer(CreateWindowResizer( window1.get(), gfx::Point(), HTCAPTION, ::wm::WINDOW_MOVE_SOURCE_TOUCH)); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); resizer->Drag(gfx::Point(400, 0), 0); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); wm::ActivateWindow(window1.get()); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); resizer->CompleteDrag(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Tests that exiting overview mode without selecting a window restores focus @@ -1059,7 +1061,7 @@ window1.reset(); window2.reset(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Regression test for crash when closing the last overview mode window under @@ -1082,7 +1084,7 @@ child.reset(); // Overview mode exits without crashing. - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Tests that entering overview mode restores a window to its original @@ -1102,7 +1104,7 @@ } EXPECT_NE(initial_bounds, GetTransformedTargetBounds(window.get())); ToggleOverview(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); EXPECT_EQ(initial_bounds, GetTransformedTargetBounds(window.get())); } @@ -1138,7 +1140,7 @@ // not overlap. EXPECT_FALSE(WindowsOverlapping(window.get(), child.get())); ClickWindow(window.get()); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); // Clicking on window1 should activate child1. EXPECT_TRUE(wm::IsActiveWindow(child.get())); @@ -1207,9 +1209,9 @@ ::wm::ActivateWindow(window1.get()); ToggleOverview(); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); UpdateDisplay("400x400"); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Tests removing a display during overview with NON_ZERO_DURATION animation. @@ -1227,12 +1229,12 @@ ::wm::ActivateWindow(window1.get()); ToggleOverview(); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); ui::ScopedAnimationDurationScaleMode test_duration_mode( ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION); UpdateDisplay("400x400"); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } namespace { @@ -1265,12 +1267,12 @@ EXPECT_EQ(gfx::Rect(10, 10, 100, 100), window->bounds()); ToggleOverview(); - ASSERT_TRUE(IsSelecting()); + ASSERT_TRUE(InOverviewSession()); GetEventGenerator()->MoveMouseBy(10, 10); ToggleOverview(); - ASSERT_FALSE(IsSelecting()); + ASSERT_FALSE(InOverviewSession()); GetEventGenerator()->MoveMouseBy(10, 10); GetEventGenerator()->ReleaseLeftButton(); @@ -1434,26 +1436,26 @@ std::unique_ptr<aura::Window> window(CreateTestWindow()); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); SendKey(ui::VKEY_ESCAPE); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); SendKey(ui::VKEY_BROWSER_BACK); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); // Tests that if we snap the only overview window, we cannot exit overview // mode. ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); Shell::Get()->split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); SendKey(ui::VKEY_ESCAPE); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); SendKey(ui::VKEY_BROWSER_BACK); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); } // Regression test for clusterfuzz crash. https://crbug.com/920568 @@ -1576,19 +1578,19 @@ // Pressing the return key without a selection widget should not do anything. SendKey(ui::VKEY_RETURN); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Select the first window. ASSERT_TRUE(SelectWindow(window1.get())); SendKey(ui::VKEY_RETURN); - ASSERT_FALSE(IsSelecting()); + ASSERT_FALSE(InOverviewSession()); EXPECT_TRUE(wm::IsActiveWindow(window1.get())); // Select the second window. ToggleOverview(); ASSERT_TRUE(SelectWindow(window2.get())); SendKey(ui::VKEY_RETURN); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); EXPECT_TRUE(wm::IsActiveWindow(window2.get())); } @@ -1606,13 +1608,13 @@ // Clicking on the background page while not in overview should not toggle // overview. GetEventGenerator()->ClickLeftButton(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); // Switch to overview mode. Clicking should now exit overview mode. ToggleOverview(); - ASSERT_TRUE(IsSelecting()); + ASSERT_TRUE(InOverviewSession()); GetEventGenerator()->ClickLeftButton(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Tests tapping on the desktop itself to cancel overview mode. @@ -1627,13 +1629,13 @@ // Tapping on the background page while not in overview should not toggle // overview. GetEventGenerator()->GestureTapAt(point_in_background_page); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); // Switch to overview mode. Tapping should now exit overview mode. ToggleOverview(); - ASSERT_TRUE(IsSelecting()); + ASSERT_TRUE(InOverviewSession()); GetEventGenerator()->GestureTapAt(point_in_background_page); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Start dragging a window and activate overview mode. This test should not @@ -2836,7 +2838,7 @@ dispatch_helper.set_target(widget->GetNativeWindow()); drag_controller->Drag(event.location(), event.flags()); - ASSERT_TRUE(IsSelecting()); + ASSERT_TRUE(InOverviewSession()); EXPECT_EQ(OverviewSession::EnterExitOverviewType::kWindowDragged, overview_session()->enter_exit_overview_type()); } @@ -2890,7 +2892,7 @@ GetEventGenerator()->set_current_screen_location( gfx::ToRoundedPoint(item->target_bounds().CenterPoint())); GetEventGenerator()->ClickLeftButton(); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Test the split view and overview functionalities in tablet mode. @@ -3046,7 +3048,7 @@ std::unique_ptr<aura::Window> window3(CreateWindow(bounds)); ToggleOverview(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // Drag |window1| selector item to snap to left. @@ -3056,8 +3058,7 @@ DragWindowTo(overview_item1, gfx::PointF(0, 0)); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); // Drag |window2| selector item to attempt to snap to left. Since there is @@ -3067,8 +3068,7 @@ GetWindowItemForWindow(grid_index, window2.get()); DragWindowTo(overview_item2, gfx::PointF(0, 0)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview( window1.get())); @@ -3080,10 +3080,9 @@ 0.f); DragWindowTo(overview_item3, end_location3); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->right_window(), window3.get()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); } // Verify the correct behavior when dragging windows in overview mode. @@ -3094,7 +3093,7 @@ std::unique_ptr<aura::Window> window2 = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); OverviewItem* window_item1 = GetWindowItemForWindow(0, window1.get()); OverviewItem* window_item2 = GetWindowItemForWindow(0, window2.get()); @@ -3137,7 +3136,7 @@ std::unique_ptr<views::Widget> widget(CreateTestWidget()); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); OverviewItem* item = GetWindowItemForWindow(0, widget->GetNativeWindow()); const gfx::PointF start = item->target_bounds().CenterPoint(); @@ -3167,7 +3166,7 @@ std::unique_ptr<views::Widget> widget(CreateTestWidget()); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); EXPECT_EQ(1u, overview_session()->grid_list_for_testing()[0]->size()); OverviewItem* item = GetWindowItemForWindow(0, widget->GetNativeWindow()); @@ -3210,7 +3209,7 @@ std::unique_ptr<aura::Window> window3 = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); @@ -3255,7 +3254,7 @@ std::unique_ptr<aura::Window> window4 = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); OverviewItem* item1 = GetWindowItemForWindow(0, window1.get()); OverviewItem* item2 = GetWindowItemForWindow(0, window2.get()); @@ -3292,7 +3291,7 @@ windows[i] = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); OverviewItem* items[kWindows]; gfx::RectF item_bounds[kWindows]; @@ -3341,7 +3340,7 @@ std::unique_ptr<aura::Window> window3(CreateTestWindow()); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); // Select window one and start the drag. const int grid_index = 0; @@ -3358,7 +3357,7 @@ const gfx::PointF left(0, 0); overview_session()->Drag(overview_item, left); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller()->state()); EXPECT_TRUE(split_view_controller()->left_window() == nullptr); EXPECT_EQ(GetSplitViewRightWindowBounds(window1.get()), GetGridBounds()); @@ -3366,7 +3365,7 @@ // left window of split view mode should be. const gfx::PointF right(window_width, 0); overview_session()->Drag(overview_item, right); - EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller()->state()); EXPECT_TRUE(split_view_controller()->right_window() == nullptr); EXPECT_EQ(GetSplitViewLeftWindowBounds(window1.get()), GetGridBounds()); @@ -3374,14 +3373,13 @@ // dimensions of the work area. const gfx::PointF center(window_width / 2, 0); overview_session()->Drag(overview_item, center); - EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller()->state()); EXPECT_EQ(GetWorkAreaInScreen(window1.get()), GetGridBounds()); // Snap window1 to the left and initialize dragging for window2. overview_session()->Drag(overview_item, left); overview_session()->CompleteDrag(overview_item, left); - ASSERT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); + ASSERT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); ASSERT_EQ(window1.get(), split_view_controller()->left_window()); overview_item = GetWindowItemForWindow(grid_index, window2.get()); overview_item_bounds = overview_item->target_bounds(); @@ -3411,7 +3409,7 @@ SubtractRects(root_window_bounds, shelf_bounds); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); // Verify that after dragging the unsnappable window to the left and right, // the window grid bounds do not change. @@ -3437,7 +3435,7 @@ std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); ToggleOverview(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); // Drag |window1| selector item to snap to left. const int grid_index = 0; @@ -3447,49 +3445,46 @@ // Test that overview mode is active in this single window case. EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); + EXPECT_TRUE(overview_controller()->InOverviewSession()); // Create a new window should exit the overview mode. std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); ::wm::ActivateWindow(window2.get()); - EXPECT_FALSE(overview_controller()->IsSelecting()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_FALSE(overview_controller()->InOverviewSession()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); // If there are only 2 snapped windows, close one of them should enter // overview mode. window2.reset(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); // If there are more than 2 windows in overview std::unique_ptr<aura::Window> window3(CreateWindow(bounds)); std::unique_ptr<aura::Window> window4(CreateWindow(bounds)); ::wm::ActivateWindow(window3.get()); ::wm::ActivateWindow(window4.get()); - EXPECT_FALSE(overview_controller()->IsSelecting()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_FALSE(overview_controller()->InOverviewSession()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); ToggleOverview(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); window3.reset(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); window4.reset(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); // Test that if there is only 1 snapped window, and no window in the overview // grid, ToggleOverview() can't end overview. ToggleOverview(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EndSplitView(); EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); // Test that ToggleOverview() can end overview if we're not in split view // mode. ToggleOverview(); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); // Now enter overview and split view again. Test that exiting tablet mode can // end split view and overview correctly. @@ -3497,23 +3492,21 @@ overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); EXPECT_TRUE(Shell::Get()->split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); Shell::Get()->tablet_mode_controller()->EnableTabletModeWindowManager(false); EXPECT_FALSE(Shell::Get()->split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); // Test that closing all windows in overview can end overview if we're not in // split view mode. ToggleOverview(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); window1.reset(); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); } // Test the overview window drag functionalities when screen rotates. TEST_F(SplitViewOverviewSessionTest, SplitViewRotationTest) { - using svc = SplitViewController; - UpdateDisplay("807x407"); int64_t display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id(); display::DisplayManager* display_manager = Shell::Get()->display_manager(); @@ -3538,7 +3531,7 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_EQ(split_view_controller()->state(), svc::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); // Test that dragging |window2| to the right of the screen snaps it to right. @@ -3547,7 +3540,7 @@ gfx::Rect work_area_rect = GetWorkAreaInScreen(window2.get()); gfx::PointF end_location2(work_area_rect.width(), work_area_rect.height()); DragWindowTo(overview_item2, end_location2); - EXPECT_EQ(split_view_controller()->state(), svc::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); // Test that |left_window_| was snapped to left after rotated 0 degree. @@ -3567,7 +3560,7 @@ // Test that dragging |window1| to the top of the screen snaps it to left. overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF(0, 0)); - EXPECT_EQ(split_view_controller()->state(), svc::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); // Test that dragging |window2| to the bottom of the screen snaps it to right. @@ -3575,7 +3568,7 @@ work_area_rect = GetWorkAreaInScreen(window2.get()); end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height()); DragWindowTo(overview_item2, end_location2, SelectorItemLocation::ORIGIN); - EXPECT_EQ(split_view_controller()->state(), svc::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); // Test that |left_window_| was snapped to top after rotated 270 degree. @@ -3595,7 +3588,7 @@ // Test that dragging |window1| to the left of the screen snaps it to right. overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_EQ(split_view_controller()->state(), svc::RIGHT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); // Test that dragging |window2| to the right of the screen snaps it to left. @@ -3603,7 +3596,7 @@ work_area_rect = GetWorkAreaInScreen(window2.get()); end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height()); DragWindowTo(overview_item2, end_location2, SelectorItemLocation::ORIGIN); - EXPECT_EQ(split_view_controller()->state(), svc::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); // Test that |right_window_| was snapped to left after rotated 180 degree. @@ -3623,7 +3616,7 @@ // Test that dragging |window1| to the top of the screen snaps it to right. overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF(0, 0)); - EXPECT_EQ(split_view_controller()->state(), svc::RIGHT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); // Test that dragging |window2| to the bottom of the screen snaps it to left. @@ -3631,7 +3624,7 @@ work_area_rect = GetWorkAreaInScreen(window2.get()); end_location2 = gfx::PointF(work_area_rect.width(), work_area_rect.height()); DragWindowTo(overview_item2, end_location2); - EXPECT_EQ(split_view_controller()->state(), svc::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); // Test that |right_window_| was snapped to top after rotated 90 degree. @@ -3661,8 +3654,7 @@ GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); const gfx::Rect window1_bounds = window1->GetBoundsInScreen(); const gfx::Rect overview_grid_bounds = GetGridBounds(); const gfx::Rect divider_bounds = @@ -3703,7 +3695,7 @@ std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow(); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); // Snap the snappable window to enter split view mode. split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT); @@ -3721,7 +3713,7 @@ // Verify that we are out of split view and overview mode, and that the active // window is the unsnappable window. EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_EQ(unsnappable_window.get(), wm::GetActiveWindow()); std::unique_ptr<aura::Window> window2 = CreateTestWindow(); @@ -3732,15 +3724,13 @@ // Split view mode should be active. Overview mode should be ended. EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); ToggleOverview(); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); // Now select the unsnappable window. overview_item = GetWindowItemForWindow(grid_index, unsnappable_window.get()); @@ -3751,7 +3741,7 @@ // Split view mode should be ended. And the unsnappable window should be the // active window now. EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_EQ(unsnappable_window.get(), wm::GetActiveWindow()); } @@ -3766,7 +3756,7 @@ std::unique_ptr<aura::Window> unsnappable_window = CreateUnsnappableWindow(); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); const int grid_index = 0; OverviewItem* snappable_overview_item = @@ -3820,7 +3810,7 @@ DragWindowTo(overview_item1, gfx::PointF()); // Test that overview mode and split view mode are both active. EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Drag the divider toward closing the snapped window. gfx::Rect divider_bounds = GetSplitViewDividerBounds(false /* is_dragging */); @@ -3830,7 +3820,7 @@ // Test that split view mode is ended. Overview mode is still active. EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Now drag |window2| selector item to snap to left. OverviewItem* overview_item2 = @@ -3838,7 +3828,7 @@ DragWindowTo(overview_item2, gfx::PointF()); // Test that overview mode and split view mode are both active. EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Drag the divider toward closing the overview window grid. divider_bounds = GetSplitViewDividerBounds(false /*is_dragging=*/); @@ -3850,7 +3840,7 @@ // Test that split view mode is ended. Overview mode is also ended. |window2| // should be activated. EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(window2.get(), wm::GetActiveWindow()); } @@ -3859,7 +3849,7 @@ std::unique_ptr<aura::Window> window2 = CreateTestWindow(); ToggleOverview(); - ASSERT_TRUE(overview_controller()->IsSelecting()); + ASSERT_TRUE(overview_controller()->InOverviewSession()); OverviewItem* overview_item = GetWindowItemForWindow(0, window1.get()); gfx::PointF start_location(overview_item->target_bounds().CenterPoint()); @@ -3870,14 +3860,14 @@ // before the press sequence started. overview_session()->InitiateDrag(overview_item, start_location); overview_session()->ResetDraggedWindowGesture(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_EQ(original_bounds, overview_item->target_bounds()); // Verify that when a overview item is tapped, we exit overview mode, // and the current active window is the item. overview_session()->InitiateDrag(overview_item, start_location); overview_session()->ActivateDraggedWindow(); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_EQ(window1.get(), wm::GetActiveWindow()); } @@ -3901,9 +3891,8 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Then drag the divider to left toward closing the snapped window. gfx::Rect divider_bounds = GetSplitViewDividerBounds(false /*is_dragging=*/); @@ -3915,7 +3904,7 @@ // Test that split view mode is ended. Overview mode is still active. EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Test that |window1| has the dimensions of a tablet mode maxed window, so // that when it is placed back on the grid it will not look skinny. EXPECT_LE(window1->bounds().x(), 0); @@ -3928,9 +3917,8 @@ gfx::Point end_location2 = gfx::Point(work_area_rect.width(), work_area_rect.height()); DragWindowTo(overview_item2, gfx::PointF(end_location2)); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, - split_view_controller()->state()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Then drag the divider to right toward closing the snapped window. divider_bounds = GetSplitViewDividerBounds(false /* is_dragging */); @@ -3943,7 +3931,7 @@ // Test that split view mode is ended. Overview mode is still active. EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Test that |window2| has the dimensions of a tablet mode maxed window, so // that when it is placed back on the grid it will not look skinny. EXPECT_GE(window2->bounds().x(), 0); @@ -3967,9 +3955,8 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); - EXPECT_TRUE(IsSelecting()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); + EXPECT_TRUE(InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); ASSERT_TRUE(split_view_controller()->split_view_divider()); std::vector<aura::Window*> window_list = @@ -3988,7 +3975,7 @@ // Verify that it is still in overview mode and that |window1| is returned to // the overview list. - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); window_list = overview_controller()->GetWindowsListInOverviewGridsForTest(); EXPECT_EQ(3u, window_list.size()); @@ -4031,7 +4018,7 @@ // Releasing close to the edge will activate the left window and exit // overview. - ASSERT_FALSE(IsSelecting()); + ASSERT_FALSE(InOverviewSession()); ToggleOverview(); // Snap a window to the right and test dragging the divider towards the left // edge of the screen. @@ -4068,39 +4055,36 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); // Minimize |window1| will put |window1| back to overview grid. wm::GetWindowState(window1.get())->Minimize(); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); EXPECT_TRUE(GetWindowItemForWindow(grid_index, window1.get())); // Now snap both |window1| and |window2|. overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); ::wm::ActivateWindow(window2.get()); - EXPECT_FALSE(IsSelecting()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_FALSE(InOverviewSession()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); // Minimize |window1| will open overview and put |window1| to overview grid. wm::GetWindowState(window1.get())->Minimize(); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); - EXPECT_TRUE(IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); + EXPECT_TRUE(InOverviewSession()); EXPECT_TRUE(GetWindowItemForWindow(grid_index, window1.get())); // Minimize |window2| also put |window2| to overview grid. wm::GetWindowState(window2.get())->Minimize(); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(IsSelecting()); + EXPECT_TRUE(InOverviewSession()); EXPECT_TRUE(GetWindowItemForWindow(grid_index, window1.get())); EXPECT_TRUE(GetWindowItemForWindow(grid_index, window2.get())); } @@ -4128,8 +4112,7 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); // Drag |window2| to snap to right. OverviewItem* overview_item2 = GetWindowItemForWindow(grid_index, window2.get()); @@ -4138,9 +4121,8 @@ window2.get()); const gfx::PointF end_location2(work_area_rect.width(), 0); DragWindowTo(overview_item2, end_location2); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity()); @@ -4152,13 +4134,11 @@ EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity()); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); // ToggleOverview() directly. ToggleOverview(); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity()); @@ -4168,12 +4148,10 @@ EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity()); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); ::wm::ActivateWindow(window2.get()); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity()); @@ -4183,13 +4161,11 @@ EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_FALSE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_FALSE(window3->layer()->GetTargetTransform().IsIdentity()); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); std::unique_ptr<aura::Window> window4(CreateWindow(bounds)); ::wm::ActivateWindow(window4.get()); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_TRUE(window1->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window2->layer()->GetTargetTransform().IsIdentity()); EXPECT_TRUE(window3->layer()->GetTargetTransform().IsIdentity()); @@ -4209,18 +4185,16 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::LEFT); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_EQ(GetGridBounds(), split_view_controller()->GetSnappedWindowBoundsInScreen( window1.get(), SplitViewController::RIGHT)); split_view_controller()->SwapWindows(); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::RIGHT); EXPECT_EQ(GetGridBounds(), @@ -4238,11 +4212,11 @@ ToggleOverview(); split_view_controller()->SnapWindow(window.get(), SplitViewController::LEFT); ToggleOverview(); - ASSERT_TRUE(IsSelecting()); + ASSERT_TRUE(InOverviewSession()); // Tests that we can exit overview if we swipe up from the shelf. ToggleOverview(OverviewSession::EnterExitOverviewType::kSwipeFromShelf); - EXPECT_FALSE(IsSelecting()); + EXPECT_FALSE(InOverviewSession()); } // Test the split view and overview functionalities in clamshell mode. Split @@ -4301,7 +4275,7 @@ wm::WindowState* window_state1 = wm::GetWindowState(window1.get()); EXPECT_FALSE(window_state1->IsSnapped()); ToggleOverview(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // Drag |window1| selector item to snap to left. const int grid_index = 0; @@ -4312,7 +4286,7 @@ // ended. EXPECT_EQ(window_state1->GetStateType(), mojom::WindowStateType::LEFT_SNAPPED); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // 2. Test if one window is snapped, the other windows are showing in @@ -4320,12 +4294,12 @@ // splitview. std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); ToggleOverview(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF(600, 300)); // SplitView and overview are both active at the moment. - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(window1.get())); EXPECT_TRUE(overview_controller()->overview_session()->IsWindowInOverview( @@ -4334,7 +4308,7 @@ mojom::WindowStateType::RIGHT_SNAPPED); // Close |window2| will end overview and splitview. window2.reset(); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // 3. Test that snap 2 windows will end overview and splitview. @@ -4349,7 +4323,7 @@ mojom::WindowStateType::LEFT_SNAPPED); EXPECT_EQ(wm::GetWindowState(window3.get())->GetStateType(), mojom::WindowStateType::RIGHT_SNAPPED); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // 4. Test if one window is snapped, the other windows are showing in @@ -4371,12 +4345,12 @@ mojom::WindowStateType::LEFT_SNAPPED); EXPECT_EQ(wm::GetWindowState(window3.get())->GetStateType(), mojom::WindowStateType::LEFT_SNAPPED); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); ToggleOverview(); EXPECT_EQ(wm::GetWindowState(window4.get())->GetStateType(), mojom::WindowStateType::RIGHT_SNAPPED); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // 5. Test if one window is snapped, the other window are showing in overview, @@ -4385,11 +4359,11 @@ ToggleOverview(); overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF(0, 0)); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); std::unique_ptr<aura::Window> window5(CreateWindow(bounds)); wm::ActivateWindow(window5.get()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // 6. Test if one window is snapped, the other window is showing in overview, @@ -4398,12 +4372,12 @@ const gfx::Rect overview_bounds = GetGridBounds(); overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF(0, 0)); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_NE(GetGridBounds(), overview_bounds); EXPECT_EQ(GetGridBounds(), GetSplitViewRightWindowBounds(window1.get())); window1.reset(); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // Overview bounds will adjust from snapped bounds to fullscreen bounds. EXPECT_EQ(GetGridBounds(), overview_bounds); @@ -4428,7 +4402,7 @@ base::RunLoop().RunUntilIdle(); // Test that app list is open and overview is ended. EXPECT_TRUE(app_list_controller->IsVisible()); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); ToggleOverview(); base::RunLoop().RunUntilIdle(); @@ -4437,7 +4411,7 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF(0, 0)); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); // Open app list. @@ -4447,18 +4421,18 @@ base::RunLoop().RunUntilIdle(); // Test that app list is open, splitview and overview are both active. EXPECT_TRUE(app_list_controller->IsVisible()); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); // Send ui::VKEY_ESCAPE should dismiss app list. But splitview and overview // should still be active. SendKey(ui::VKEY_ESCAPE); EXPECT_FALSE(app_list_controller->IsVisible()); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); // Send ui::VKEY_ESCAPE should then end overview. SendKey(ui::VKEY_ESCAPE); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); } @@ -4492,7 +4466,7 @@ ui::test::EventGenerator generator1(Shell::GetPrimaryRootWindow(), window1.get()); generator1.DragMouseBy(50, 50); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_NE(GetGridBounds(), overview_full_bounds); EXPECT_NE(GetGridBounds(), overview_snapped_bounds); @@ -4504,12 +4478,12 @@ OverviewItem* overview_item2 = GetWindowItemForWindow(grid_index, window2.get()); DragWindowTo(overview_item2, gfx::PointF(0, 0)); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); ui::test::EventGenerator generator2(Shell::GetPrimaryRootWindow(), window2.get()); generator2.DragMouseBy(50, 50); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); ToggleOverview(); @@ -4519,7 +4493,7 @@ ui::test::EventGenerator generator3(Shell::GetPrimaryRootWindow(), window3.get()); generator3.DragMouseBy(50, 50); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); ToggleOverview(); @@ -4529,7 +4503,7 @@ ui::test::EventGenerator generator4(Shell::GetPrimaryRootWindow(), window4.get()); generator4.DragMouseBy(50, 50); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); } @@ -4547,13 +4521,13 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF(0, 0)); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); ui::test::EventGenerator generator1(Shell::GetPrimaryRootWindow(), window1.get()); generator1.DragMouseBy(50, 50); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); } @@ -4570,12 +4544,12 @@ OverviewItem* overview_item1 = GetWindowItemForWindow(grid_index, window1.get()); DragWindowTo(overview_item1, gfx::PointF(0, 0)); - EXPECT_TRUE(overview_controller()->IsSelecting()); + EXPECT_TRUE(overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); // Now minimize the snapped |window1|. wm::GetWindowState(window1.get())->Minimize(); - EXPECT_FALSE(overview_controller()->IsSelecting()); + EXPECT_FALSE(overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); }
diff --git a/ash/wm/overview/overview_utils.cc b/ash/wm/overview/overview_utils.cc index 0d1c4ff..9cde383 100644 --- a/ash/wm/overview/overview_utils.cc +++ b/ash/wm/overview/overview_utils.cc
@@ -198,7 +198,7 @@ } bool IsSlidingOutOverviewFromShelf() { - if (!Shell::Get()->overview_controller()->IsSelecting()) + if (!Shell::Get()->overview_controller()->InOverviewSession()) return false; if (Shell::Get()
diff --git a/ash/wm/overview/overview_window_drag_controller.cc b/ash/wm/overview/overview_window_drag_controller.cc index 4842f16..f2110dfa 100644 --- a/ash/wm/overview/overview_window_drag_controller.cc +++ b/ash/wm/overview/overview_window_drag_controller.cc
@@ -269,11 +269,11 @@ // right window, snap the current window to left. If split view is active // and the selected window cannot be snapped, exit splitview and activate // the selected window, and also exit the overview. - SplitViewController::State split_state = split_view_controller_->state(); - if (!ShouldAllowSplitView() || split_state == SplitViewController::NO_SNAP) { + SplitViewState split_state = split_view_controller_->state(); + if (!ShouldAllowSplitView() || split_state == SplitViewState::kNoSnap) { overview_session_->SelectWindow(item_); } else if (CanSnapInSplitview(item_->GetWindow())) { - SnapWindow(split_state == SplitViewController::LEFT_SNAPPED + SnapWindow(split_state == SplitViewState::kLeftSnapped ? SplitViewController::RIGHT : SplitViewController::LEFT); } else {
diff --git a/ash/wm/splitview/split_view_controller.cc b/ash/wm/splitview/split_view_controller.cc index 0b4e70d..956e538d 100644 --- a/ash/wm/splitview/split_view_controller.cc +++ b/ash/wm/splitview/split_view_controller.cc
@@ -107,22 +107,6 @@ bounds_in_screen.y())); } -mojom::SplitViewState ToMojomSplitViewState(SplitViewController::State state) { - switch (state) { - case SplitViewController::NO_SNAP: - return mojom::SplitViewState::NO_SNAP; - case SplitViewController::LEFT_SNAPPED: - return mojom::SplitViewState::LEFT_SNAPPED; - case SplitViewController::RIGHT_SNAPPED: - return mojom::SplitViewState::RIGHT_SNAPPED; - case SplitViewController::BOTH_SNAPPED: - return mojom::SplitViewState::BOTH_SNAPPED; - default: - NOTREACHED(); - return mojom::SplitViewState::NO_SNAP; - } -} - mojom::WindowStateType GetStateTypeFromSnapPosition( SplitViewController::SnapPosition snap_position) { DCHECK(snap_position != SplitViewController::NONE); @@ -154,7 +138,7 @@ // Returns the overview session if overview mode is active, otherwise returns // nullptr. OverviewSession* GetOverviewSession() { - return Shell::Get()->overview_controller()->IsSelecting() + return Shell::Get()->overview_controller()->InOverviewSession() ? Shell::Get()->overview_controller()->overview_session() : nullptr; } @@ -309,21 +293,18 @@ EndSplitView(); } -void SplitViewController::BindRequest( - mojom::SplitViewControllerRequest request) { - bindings_.AddBinding(this, std::move(request)); -} - bool SplitViewController::InSplitViewMode() const { return InClamshellSplitViewMode() || InTabletSplitViewMode(); } bool SplitViewController::InClamshellSplitViewMode() const { - return state_ != NO_SNAP && split_view_type_ == SplitViewType::kClamshellType; + return state_ != SplitViewState::kNoSnap && + split_view_type_ == SplitViewType::kClamshellType; } bool SplitViewController::InTabletSplitViewMode() const { - return state_ != NO_SNAP && split_view_type_ == SplitViewType::kTabletType; + return state_ != SplitViewState::kNoSnap && + split_view_type_ == SplitViewType::kTabletType; } void SplitViewController::SnapWindow(aura::Window* window, @@ -342,7 +323,7 @@ UpdateSnappingWindowTransformedBounds(window); RemoveWindowFromOverviewIfApplicable(window); - if (state_ == NO_SNAP) { + if (state_ == SplitViewState::kNoSnap) { // Add observers when the split view mode starts. Shell::Get()->AddShellObserver(this); Shell::Get()->overview_controller()->AddObserver(this); @@ -403,7 +384,7 @@ // Update the divider position and window bounds before snapping a new // window. Since the minimum size of |window| maybe larger than currently // bounds in |snap_position|. - if (state_ != NO_SNAP) { + if (state_ != SplitViewState::kNoSnap) { divider_position_ = GetClosestFixedDividerPosition(); UpdateSnappedWindowsAndDividerBounds(); } @@ -567,7 +548,7 @@ } base::RecordAction(base::UserMetricsAction("SplitView_ResizeWindows")); - if (state_ == BOTH_SNAPPED) { + if (state_ == SplitViewState::kBothSnapped) { presentation_time_recorder_ = CreatePresentationTimeHistogramRecorder( split_view_divider_->divider_widget()->GetCompositor(), kSplitViewResizeMultiHistogram, @@ -719,25 +700,18 @@ } } -void SplitViewController::AddObserver(Observer* observer) { +SplitViewState SplitViewController::GetCurrentState() const { + return state_; +} + +void SplitViewController::AddObserver(SplitViewObserver* observer) { observers_.AddObserver(observer); } -void SplitViewController::RemoveObserver(Observer* observer) { +void SplitViewController::RemoveObserver(SplitViewObserver* observer) { observers_.RemoveObserver(observer); } -void SplitViewController::FlushForTesting() { - mojo_observers_.FlushForTesting(); - bindings_.FlushForTesting(); -} - -void SplitViewController::AddObserver(mojom::SplitViewObserverPtr observer) { - mojom::SplitViewObserver* observer_ptr = observer.get(); - mojo_observers_.AddPtr(std::move(observer)); - observer_ptr->OnSplitViewStateChanged(ToMojomSplitViewState(state_)); -} - void SplitViewController::OnWindowDestroyed(aura::Window* window) { DCHECK(InSplitViewMode()); DCHECK(IsWindowInSplitView(window)); @@ -979,7 +953,7 @@ } aura::Window* root_window = GetDefaultSnappedWindow()->GetRootWindow(); - if (state_ == BOTH_SNAPPED) { + if (state_ == SplitViewState::kBothSnapped) { // If overview is ended because of the window gets snapped, do not do // exiting overview animation. overview_session->SetWindowListNotAnimatedWhenExiting(root_window); @@ -1146,34 +1120,31 @@ } void SplitViewController::UpdateSplitViewStateAndNotifyObservers() { - State previous_state = state_; + SplitViewState previous_state = state_; if (IsSnapped(left_window_) && IsSnapped(right_window_)) - state_ = BOTH_SNAPPED; + state_ = SplitViewState::kBothSnapped; else if (IsSnapped(left_window_)) - state_ = LEFT_SNAPPED; + state_ = SplitViewState::kLeftSnapped; else if (IsSnapped(right_window_)) - state_ = RIGHT_SNAPPED; + state_ = SplitViewState::kRightSnapped; else - state_ = NO_SNAP; + state_ = SplitViewState::kNoSnap; // We still notify observers even if |state_| doesn't change as it's possible // to snap a window to a position that already has a snapped window. - for (Observer& observer : observers_) + for (auto& observer : observers_) observer.OnSplitViewStateChanged(previous_state, state_); - mojo_observers_.ForAllPtrs([this](mojom::SplitViewObserver* observer) { - observer->OnSplitViewStateChanged(ToMojomSplitViewState(state_)); - }); if (previous_state != state_) { - if (previous_state == NO_SNAP) + if (previous_state == SplitViewState::kNoSnap) Shell::Get()->NotifySplitViewModeStarted(); - else if (state_ == NO_SNAP) + else if (state_ == SplitViewState::kNoSnap) Shell::Get()->NotifySplitViewModeEnded(); } } void SplitViewController::NotifyDividerPositionChanged() { - for (Observer& observer : observers_) + for (auto& observer : observers_) observer.OnSplitViewDividerPositionChanged(); } @@ -1413,7 +1384,7 @@ // Track the window that needs to be put back into the overview list if we // remain in overview mode. aura::Window* insert_overview_window = nullptr; - if (Shell::Get()->overview_controller()->IsSelecting()) + if (Shell::Get()->overview_controller()->InOverviewSession()) insert_overview_window = GetDefaultSnappedWindow(); EndSplitView(); if (active_window) { @@ -1457,7 +1428,7 @@ ActivateAndStackSnappedWindow(window); // If there are two window snapped in clamshell mode, splitview mode is ended. - if (state_ == BOTH_SNAPPED && + if (state_ == SplitViewState::kBothSnapped && split_view_type_ == SplitViewType::kClamshellType) { EndSplitView(); } @@ -1757,7 +1728,7 @@ void SplitViewController::RemoveWindowFromOverviewIfApplicable( aura::Window* window) { - if (!Shell::Get()->overview_controller()->IsSelecting()) + if (!Shell::Get()->overview_controller()->InOverviewSession()) return; OverviewSession* overview_session = GetOverviewSession(); @@ -1794,7 +1765,7 @@ } void SplitViewController::StartOverview(bool window_drag) { - if (!Shell::Get()->overview_controller()->IsSelecting()) { + if (!Shell::Get()->overview_controller()->InOverviewSession()) { Shell::Get()->overview_controller()->ToggleOverview( window_drag ? OverviewSession::EnterExitOverviewType::kWindowDragged : OverviewSession::EnterExitOverviewType::kNormal); @@ -1802,7 +1773,7 @@ } void SplitViewController::EndOverview() { - if (Shell::Get()->overview_controller()->IsSelecting()) + if (Shell::Get()->overview_controller()->InOverviewSession()) Shell::Get()->overview_controller()->ToggleOverview(); }
diff --git a/ash/wm/splitview/split_view_controller.h b/ash/wm/splitview/split_view_controller.h index 4e1b50e67..8ac554d 100644 --- a/ash/wm/splitview/split_view_controller.h +++ b/ash/wm/splitview/split_view_controller.h
@@ -10,7 +10,7 @@ #include "ash/accessibility/accessibility_observer.h" #include "ash/ash_export.h" #include "ash/display/screen_orientation_controller.h" -#include "ash/public/interfaces/split_view.mojom.h" +#include "ash/public/cpp/split_view.h" #include "ash/shell_observer.h" #include "ash/wm/overview/overview_observer.h" #include "ash/wm/tablet_mode/tablet_mode_controller.h" @@ -20,8 +20,6 @@ #include "base/macros.h" #include "base/observer_list.h" #include "base/time/time.h" -#include "mojo/public/cpp/bindings/binding_set.h" -#include "mojo/public/cpp/bindings/interface_ptr_set.h" #include "ui/aura/window_observer.h" #include "ui/display/display.h" #include "ui/display/display_observer.h" @@ -43,7 +41,7 @@ // the screen. It also observes the two snapped windows and decides when to exit // the split view mode. // TODO(xdai): Make it work for multi-display non mirror environment. -class ASH_EXPORT SplitViewController : public mojom::SplitViewController, +class ASH_EXPORT SplitViewController : public SplitViewNotifier, public aura::WindowObserver, public ash::wm::WindowStateObserver, public ::wm::ActivationChangeObserver, @@ -53,8 +51,6 @@ public TabletModeObserver, public AccessibilityObserver { public: - enum State { NO_SNAP, LEFT_SNAPPED, RIGHT_SNAPPED, BOTH_SNAPPED }; - // "LEFT" and "RIGHT" are the snap positions corresponding to "primary // landscape" screen orientation. In other screen orientation, we still use // "LEFT" and "RIGHT" but it doesn't literally mean left side of the screen or @@ -90,23 +86,9 @@ kClamshellType, }; - class Observer { - public: - // Called when split view state changed from |previous_state| to |state|. - virtual void OnSplitViewStateChanged( - SplitViewController::State previous_state, - SplitViewController::State state) {} - - // Called when split view divider's position has changed. - virtual void OnSplitViewDividerPositionChanged() {} - }; - SplitViewController(); ~SplitViewController() override; - // Binds the mojom::SplitViewController interface to this object. - void BindRequest(mojom::SplitViewControllerRequest request); - // Returns true if split view mode is active. Please see SplitViewType above // to see the difference between tablet mode and clamshell mode splitview // mode. @@ -176,13 +158,10 @@ void OnResizeLoopStarted(aura::Window* window) override; void OnResizeLoopEnded(aura::Window* window) override; - void AddObserver(Observer* observer); - void RemoveObserver(Observer* observer); - - void FlushForTesting(); - - // mojom::SplitViewObserver: - void AddObserver(mojom::SplitViewObserverPtr observer) override; + // SplitViewNotifier: + SplitViewState GetCurrentState() const override; + void AddObserver(SplitViewObserver* observer) override; + void RemoveObserver(SplitViewObserver* observer) override; // aura::WindowObserver: void OnWindowDestroyed(aura::Window* window) override; @@ -222,7 +201,7 @@ aura::Window* left_window() { return left_window_; } aura::Window* right_window() { return right_window_; } int divider_position() const { return divider_position_; } - State state() const { return state_; } + SplitViewState state() const { return state_; } SnapPosition default_snap_position() const { return default_snap_position_; } SplitViewDivider* split_view_divider() { return split_view_divider_.get(); } bool is_resizing() const { return is_resizing_; } @@ -408,9 +387,6 @@ aura::Window* window, const gfx::Point& last_location_in_screen); - // Bindings for the SplitViewController interface. - mojo::BindingSet<mojom::SplitViewController> bindings_; - // The current left/right snapped window. aura::Window* left_window_ = nullptr; aura::Window* right_window_ = nullptr; @@ -452,7 +428,7 @@ std::unique_ptr<DividerSnapAnimation> divider_snap_animation_; // Current snap state. - State state_ = NO_SNAP; + SplitViewState state_ = SplitViewState::kNoSnap; // The default snap position. It's decided by the first snapped window. If the // first window was snapped left, then |default_snap_position_| equals LEFT, @@ -480,8 +456,7 @@ base::flat_map<aura::Window*, gfx::Rect> snapping_window_transformed_bounds_map_; - base::ObserverList<Observer>::Unchecked observers_; - mojo::InterfacePtrSet<mojom::SplitViewObserver> mojo_observers_; + base::ObserverList<SplitViewObserver>::Unchecked observers_; ScopedObserver<TabletModeController, TabletModeObserver> tablet_mode_observer_{this};
diff --git a/ash/wm/splitview/split_view_controller_unittest.cc b/ash/wm/splitview/split_view_controller_unittest.cc index cb6696c..6464e2fd 100644 --- a/ash/wm/splitview/split_view_controller_unittest.cc +++ b/ash/wm/splitview/split_view_controller_unittest.cc
@@ -272,12 +272,11 @@ std::unique_ptr<aura::Window> window1(CreateWindow(bounds)); std::unique_ptr<aura::Window> window2(CreateWindow(bounds)); - EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap); EXPECT_EQ(split_view_controller()->InSplitViewMode(), false); split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); EXPECT_NE(split_view_controller()->left_window(), window2.get()); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); @@ -287,8 +286,7 @@ split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); EXPECT_NE(split_view_controller()->right_window(), window1.get()); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); @@ -297,7 +295,7 @@ window2.get(), SplitViewController::RIGHT)); EndSplitView(); - EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap); EXPECT_EQ(split_view_controller()->InSplitViewMode(), false); } @@ -344,28 +342,26 @@ split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::LEFT); // Closing one of the two snapped windows will not end split view mode. window1.reset(); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); // Since left window was closed, its default snap position changed to RIGHT. EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::RIGHT); // Window grid is showing no recent items, and has no windows, but it is still // available. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Now close the other snapped window. window2.reset(); EXPECT_EQ(split_view_controller()->InSplitViewMode(), false); - EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // 3 - Then test the scenario with more than two windows. std::unique_ptr<aura::Window> window3(CreateWindow(bounds)); @@ -375,27 +371,25 @@ split_view_controller()->SnapWindow(window4.get(), SplitViewController::RIGHT); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::LEFT); // Close one of the snapped windows. window4.reset(); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::LEFT); // Now overview window grid can be opened. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Close the other snapped window. window3.reset(); EXPECT_EQ(split_view_controller()->InSplitViewMode(), false); - EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap); // Test the overview winow grid should still open. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Tests that if there are two snapped windows, minimizing one of them will open @@ -422,29 +416,27 @@ split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::LEFT); // Minimizing one of the two snapped windows will not end split view mode. wm::GetWindowState(window1.get())->OnWMEvent(&minimize_event); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); // Since left window was minimized, its default snap position changed to // RIGHT. EXPECT_EQ(split_view_controller()->default_snap_position(), SplitViewController::RIGHT); // The overview window grid will open. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Now minimize the other snapped window. wm::GetWindowState(window2.get())->OnWMEvent(&minimize_event); EXPECT_EQ(split_view_controller()->InSplitViewMode(), false); - EXPECT_EQ(split_view_controller()->state(), SplitViewController::NO_SNAP); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kNoSnap); // The overview window grid is still open. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Tests that if one of the snapped window gets maximized / full-screened, the @@ -499,7 +491,7 @@ // Maximize the snapped window will end the split view mode and overview mode. wm::GetWindowState(window1.get())->OnWMEvent(&maximize_event); EXPECT_EQ(split_view_controller()->InSplitViewMode(), false); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); @@ -510,7 +502,7 @@ // mode. wm::GetWindowState(window1.get())->OnWMEvent(&fullscreen_event); EXPECT_EQ(split_view_controller()->InSplitViewMode(), false); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Tests that if split view mode is active, activate another window will snap @@ -525,18 +517,15 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); wm::ActivateWindow(window2.get()); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); wm::ActivateWindow(window3.get()); EXPECT_EQ(split_view_controller()->right_window(), window3.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); } // Tests that if split view mode and overview mode are active at the same time, @@ -555,13 +544,11 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); ToggleOverview(); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->right_window(), window3.get()); CheckOverviewEnterExitHistogram("ExitInSplitView", {1, 0}, {0, 1}); } @@ -578,14 +565,12 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->GetDefaultSnappedWindow(), window1.get()); ToggleOverview(); CheckOverviewEnterExitHistogram("EnterInSplitView", {0, 1}, {0, 0}); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_FALSE( base::ContainsValue(GetWindowsInOverviewGrids(), split_view_controller()->GetDefaultSnappedWindow())); @@ -1135,7 +1120,7 @@ // current active window. LongPressOnOverivewButtonTray(); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(window1.get(), wm::GetActiveWindow()); // Snap |window1| to the right. @@ -1149,7 +1134,7 @@ // current active window. LongPressOnOverivewButtonTray(); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(window1.get(), wm::GetActiveWindow()); // Snap two windows and activate the left window, |window1|. @@ -1224,7 +1209,7 @@ // current active window. LongPressOnOverivewButtonTray(); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(right_window.get(), wm::GetActiveWindow()); } @@ -1237,7 +1222,7 @@ wm::ActivateWindow(window1.get()); ToggleOverview(); - ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); ASSERT_FALSE(split_view_controller()->InSplitViewMode()); CheckOverviewEnterExitHistogram("EnterInTablet", {1, 0}, {0, 0}); @@ -1253,7 +1238,7 @@ ToggleOverview(); CheckOverviewEnterExitHistogram("EnterInTablet2", {2, 0}, {1, 0}); - ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); ASSERT_FALSE(split_view_controller()->InSplitViewMode()); LongPressOnOverivewButtonTray(); @@ -1727,22 +1712,19 @@ split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); // Now lock the screen. GetSessionControllerClient()->LockScreen(); // Change display configuration. Split view mode is still active. UpdateDisplay("400x800"); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); // Now unlock the screen. GetSessionControllerClient()->UnlockScreen(); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); } // Test that when split view and overview are both active when a new window is @@ -1753,13 +1735,12 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); ToggleOverview(); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Now new a window. Test it won't end the overview mode std::unique_ptr<aura::Window> window3(CreateWindow(bounds)); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Tests that when split view ends because of a transition from tablet mode to @@ -1959,9 +1940,9 @@ std::unique_ptr<OverviewStatesObserver> overview_observer = std::make_unique<OverviewStatesObserver>(window1->GetRootWindow()); ToggleOverview(); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); ToggleOverview(); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); CheckOverviewEnterExitHistogram("NormalEnterExit", {1, 0}, {1, 0}); @@ -1969,7 +1950,7 @@ ToggleOverview(); // It will end overview. wm::ActivateWindow(window1.get()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); CheckOverviewEnterExitHistogram("EnterExitByActivation", {2, 0}, {2, 0}); @@ -1979,26 +1960,26 @@ // to ShellObserver list after SplitViewController. overview_observer.reset(new OverviewStatesObserver(window1->GetRootWindow())); ToggleOverview(); // Start overview. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Test |overview_animate_when_exiting_| has been properly reset. EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); CheckOverviewEnterExitHistogram("EnterInSplitView", {2, 1}, {2, 0}); split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_FALSE(overview_observer->overview_animate_when_exiting()); CheckOverviewEnterExitHistogram("ExitBySnap", {2, 1}, {2, 1}); // 4) If ending overview causes a window to snap: ToggleOverview(); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Test |overview_animate_when_exiting_| has been properly reset. EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); CheckOverviewEnterExitHistogram("EnterInSplitView2", {2, 2}, {2, 1}); ToggleOverview(); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_FALSE(overview_observer->overview_animate_when_exiting()); CheckOverviewEnterExitHistogram("ExitInSplitView", {2, 2}, {2, 2}); } @@ -2039,11 +2020,11 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); ToggleOverview(); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); wm::ActivateWindow(window3.get()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Tests that if a snapped window has a bubble transient child, the bubble's @@ -2148,18 +2129,15 @@ SplitViewController::LEFT); split_view_controller()->SnapWindow(normal_window.get(), SplitViewController::RIGHT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey)); wm::ActivateWindow(always_on_top_window.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey)); wm::ActivateWindow(normal_window.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_TRUE(always_on_top_window->GetProperty(aura::client::kAlwaysOnTopKey)); } @@ -2372,7 +2350,7 @@ ->overview_session() ->num_items_for_testing()); split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); - ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(1u, Shell::Get() ->overview_controller() ->overview_session() @@ -2689,7 +2667,7 @@ CreateWindowWithType(bounds, AppType::BROWSER)); Shell::Get()->overview_controller()->ToggleOverview(); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); OverviewSession* overview_session = Shell::Get()->overview_controller()->overview_session(); EXPECT_TRUE(overview_session->IsWindowInOverview(window1.get())); @@ -2701,13 +2679,13 @@ // Since the source window is the dragged window, the overview should have // been opened. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); overview_session = Shell::Get()->overview_controller()->overview_session(); EXPECT_FALSE(overview_session->IsWindowInOverview(window1.get())); EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get())); CompleteDrag(std::move(resizer)); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if a window is in tab-dragging process, the split divider is placed @@ -2758,7 +2736,7 @@ ASSERT_TRUE(resizer.get()); // Overview should have been opened because the dragged window is the source // window. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // 1.a. Drag the window to move a small amount of distance will maximize the // window again. @@ -2771,7 +2749,7 @@ CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMaximized()); EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMaximized()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // 1.b. Drag the window long enough (pass one fourth of the screen vertical // height) to snap the window to splitscreen. @@ -2782,20 +2760,19 @@ CompleteDrag(std::move(resizer)); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Maximize the snapped window to end split view mode and overview mode. wm::GetWindowState(window1.get())->Maximize(); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // 2. If the dragged window is not the source window: resizer = StartDrag(window1.get(), window2.get()); ASSERT_TRUE(resizer.get()); // Overview is not opened for this case. - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // When the drag starts, the source window's bounds are the same with the // work area's bounds. const display::Display display = @@ -2848,9 +2825,8 @@ EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_TRUE(window1->GetProperty(kCanAttachToAnotherWindowKey)); EndSplitView(); @@ -2865,7 +2841,7 @@ resizer.reset(); window1.reset(); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_TRUE(wm::GetWindowState(window2.get())->IsMaximized()); // 4. If the dragged window can't be snapped, then the source window should @@ -2879,7 +2855,7 @@ gfx::Size(display_bounds.width() * 0.67f, display_bounds.height())); EXPECT_FALSE(CanSnapInSplitview(window1.get())); resizer = StartDrag(window1.get(), window2.get()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); DragWindowTo(resizer.get(), gfx::Point(0, GetIndicatorsThreshold(window1.get()) + 10)); EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kCannotSnap); @@ -2918,8 +2894,7 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); @@ -2928,10 +2903,9 @@ StartDrag(window1.get(), window1.get()); ASSERT_TRUE(resizer.get()); EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kNone); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); // In this case overview grid will be opened, containing |window3|. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); OverviewSession* overview_session = Shell::Get()->overview_controller()->overview_session(); EXPECT_FALSE(overview_session->IsWindowInOverview(window1.get())); @@ -2944,18 +2918,17 @@ // be put back to its original position. Overview mode will be ended. DragWindowWithOffset(resizer.get(), 10, 10); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); EXPECT_EQ(split_view_controller()->right_window(), window2.get()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); CheckOverviewEnterExitHistogram("ExitInSplitViewByDrag", {0, 0}, {0, 1}); // 1.b. If the window is dragged long enough, it can replace the other split // window. resizer = StartDrag(window1.get(), window1.get()); ASSERT_TRUE(resizer.get()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); DragWindowTo(resizer.get(), gfx::Point(600, 300)); // Preview window shows up on overview side of screen. EXPECT_EQ(GetIndicatorState(resizer.get()), @@ -2963,10 +2936,9 @@ CheckOverviewEnterExitHistogram("EnterInSplitViewByDrag2", {0, 0}, {0, 1}); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); overview_session = Shell::Get()->overview_controller()->overview_session(); EXPECT_FALSE(overview_session->IsWindowInOverview(window1.get())); EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get())); @@ -2975,25 +2947,22 @@ CheckOverviewEnterExitHistogram("DoNotExitInSplitViewByDrag", {0, 0}, {0, 1}); // Snap |window2| again to test 1.c. split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); CheckOverviewEnterExitHistogram("ExitInSplitViewBySnap", {0, 0}, {0, 2}); // 1.c. If the dragged window is destroyed during dragging (may happen due to // all its tabs are attached into another window), nothing changes. resizer = StartDrag(window1.get(), window1.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); ASSERT_TRUE(resizer.get()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); CheckOverviewEnterExitHistogram("EnterInSplitViewByDrag3", {0, 0}, {0, 2}); resizer->Drag(gfx::Point(100, 100), 0); resizer->CompleteDrag(); resizer.reset(); window1.reset(); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Still in overview. CheckOverviewEnterExitHistogram("DoNotExitInSplitViewByDrag3", {0, 0}, {0, 2}); @@ -3002,8 +2971,7 @@ window1.reset(CreateWindowWithType(bounds, AppType::BROWSER)); split_view_controller()->SnapWindow(window1.get(), SplitViewController::RIGHT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); CheckOverviewEnterExitHistogram("ExitInSplitViewBySnap2", {0, 0}, {0, 3}); @@ -3013,11 +2981,10 @@ // |window2|. resizer = StartDrag(window3.get(), window2.get()); ASSERT_TRUE(resizer.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kNone); EXPECT_EQ(window2->GetBoundsInScreen(), split_view_controller()->GetSnappedWindowBoundsInScreen( @@ -3040,11 +3007,10 @@ split_view_controller()->GetSnappedWindowBoundsInScreen( window2.get(), SplitViewController::LEFT)); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window3.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); CheckOverviewEnterExitHistogram("DoNotEnterInSplitViewByDrag2", {0, 0}, {0, 3}); @@ -3052,27 +3018,25 @@ // the split window. resizer = StartDrag(window2.get(), window1.get()); ASSERT_TRUE(resizer.get()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window3.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); CheckOverviewEnterExitHistogram("DoNotEnterInSplitViewByDrag3", {0, 0}, {0, 3}); DragWindowTo(resizer.get(), gfx::Point(0, 300)); // Preview window shows up on overview side of screen. EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); CheckOverviewEnterExitHistogram("DoNotEnterInSplitViewByDrag4", {0, 0}, {0, 3}); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test the functionalities that are related to dragging a snapped window while @@ -3095,9 +3059,8 @@ split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); ToggleOverview(); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); CheckOverviewEnterExitHistogram("EnterInSplitView", {0, 1}, {0, 0}); @@ -3107,7 +3070,7 @@ ASSERT_TRUE(resizer.get()); // Overivew mode is still active, but split view mode is ended due to dragging // the only snapped window. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // 1.a. If the window is only dragged for a small amount of distance @@ -3121,7 +3084,7 @@ EXPECT_FALSE(split_view_controller()->InSplitViewMode()); CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(window1.get())->IsMaximized()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); // It exits SplitView during drag, so exit animation is performed in tablet // mode. @@ -3137,17 +3100,16 @@ resizer = StartDrag(window1.get(), window1.get()); ASSERT_TRUE(resizer.get()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); CheckOverviewEnterExitHistogram("DoNotExitInSplitView2", {0, 2}, {1, 0}); DragWindowTo(resizer.get(), gfx::Point(0, 300)); EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window1.get()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); OverviewSession* overview_session = Shell::Get()->overview_controller()->overview_session(); EXPECT_TRUE(overview_session->IsWindowInOverview(window2.get())); @@ -3186,10 +3148,9 @@ // Preview window shows up on overview side of screen. EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); overview_session = Shell::Get()->overview_controller()->overview_session(); EXPECT_TRUE(overview_session->IsWindowInOverview(window1.get())); EXPECT_TRUE(overview_session->IsWindowInOverview(window3.get())); @@ -3207,11 +3168,10 @@ EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaRight); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_EQ(split_view_controller()->left_window(), window2.get()); EXPECT_EQ(split_view_controller()->right_window(), window1.get()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); CheckOverviewEnterExitHistogram("ExitInSplitView", {0, 2}, {1, 1}); } @@ -3230,17 +3190,15 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); split_view_controller()->SnapWindow(window2.get(), SplitViewController::RIGHT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // Now drags |window1|. std::unique_ptr<WindowResizer> resizer = StartDrag(window1.get(), window1.get()); // Overview should have been opened. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); // Test that the new window item widget shows up as the first one of the // windows in the grid. @@ -3265,9 +3223,8 @@ drop_target_bounds.CenterPoint().y())); CompleteDrag(std::move(resizer)); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); // Test that the dragged window has been added to the overview mode, and it is // added at the front of the grid. EXPECT_EQ(current_grid->window_list().size(), 2u); @@ -3299,14 +3256,14 @@ ASSERT_TRUE(resizer.get()); // Overview should have been opened because the dragged window is the source // window. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // The value should be properly initialized. EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); // Now release the dragged window. There should be no animation when exiting // overview. CompleteDrag(std::move(resizer)); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_FALSE(overview_observer->overview_animate_when_exiting()); // 2) If dragging a snapped window: @@ -3317,17 +3274,15 @@ resizer = StartDrag(window1.get(), window1.get()); ASSERT_TRUE(resizer.get()); // Overview should have been opened behind the dragged window. - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Split view should still be active. - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); // The value should be properly initialized. EXPECT_TRUE(overview_observer->overview_animate_when_exiting()); CompleteDrag(std::move(resizer)); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_FALSE(overview_observer->overview_animate_when_exiting()); } @@ -3352,7 +3307,7 @@ std::unique_ptr<WindowResizer> resizer = StartDrag(window.get(), window.get()); ASSERT_TRUE(resizer.get()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Drag the window past the indicators threshold to show the indicators. DragWindowTo(resizer.get(), gfx::Point(200, GetIndicatorsThreshold(window.get()))); @@ -3387,13 +3342,13 @@ CreateWindowWithType(bounds, AppType::BROWSER)); OverviewController* selector_controller = Shell::Get()->overview_controller(); - EXPECT_FALSE(selector_controller->IsSelecting()); + EXPECT_FALSE(selector_controller->InOverviewSession()); // Start dragging |window1|. std::unique_ptr<WindowResizer> resizer = StartDrag(window1.get(), window1.get()); // Overview should have been opened. - EXPECT_TRUE(selector_controller->IsSelecting()); + EXPECT_TRUE(selector_controller->InOverviewSession()); // Test that the drop target shows up as the first item in overview. OverviewGrid* current_grid = @@ -3437,22 +3392,19 @@ EXPECT_FALSE(drop_target_widget->IsVisible()); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); - EXPECT_TRUE(selector_controller->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); + EXPECT_TRUE(selector_controller->InOverviewSession()); // Snap another window should end overview. split_view_controller()->SnapWindow(window2.get(), SplitViewController::LEFT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); - EXPECT_FALSE(selector_controller->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); + EXPECT_FALSE(selector_controller->InOverviewSession()); // Now drag |window1| again. Overview and splitview should be both active at // the same time during dragging. resizer = StartDrag(window1.get(), window1.get()); - EXPECT_TRUE(selector_controller->IsSelecting()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_TRUE(selector_controller->InOverviewSession()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); current_grid = selector_controller->overview_session()->GetGridWithRootWindow( window1->GetRootWindow()); @@ -3488,7 +3440,7 @@ // |window1| should now snap to left. |window2| is put back in overview. EXPECT_EQ(split_view_controller()->left_window(), window1.get()); - EXPECT_TRUE(selector_controller->IsSelecting()); + EXPECT_TRUE(selector_controller->InOverviewSession()); EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview( window2.get())); @@ -3496,7 +3448,7 @@ resizer = StartDrag(window1.get(), window1.get()); // Splitview should end now, but overview should still active. EXPECT_FALSE(split_view_controller()->InSplitViewMode()); - EXPECT_TRUE(selector_controller->IsSelecting()); + EXPECT_TRUE(selector_controller->InOverviewSession()); // The size of drop target should still not be the same as the dragged // window's size. current_grid = selector_controller->overview_session()->GetGridWithRootWindow( @@ -3522,7 +3474,7 @@ // Drag |window1|. Overview should open behind the dragged window. std::unique_ptr<WindowResizer> resizer = StartDrag(window1.get(), window1.get()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); // Change the |window1|'s bounds to simulate what might happen in reality. window1->SetBounds(bounds); @@ -3554,11 +3506,11 @@ EXPECT_EQ(drop_target_bounds, gfx::ToEnclosingRect(overview_item->target_bounds())); ToggleOverview(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); // Drag |window1|. Overview should open behind the dragged window. resizer = StartDrag(window1.get(), window1.get()); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); // Change the |window1|'s bounds to simulate what might happen in reality. window1->SetBounds(bounds); @@ -3604,7 +3556,7 @@ 10)); CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(browser_window1.get())->IsMaximized()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); // Drop window into overview if it has beenn dragged further than the distance // threshold. @@ -3631,8 +3583,7 @@ EXPECT_EQ(IndicatorState::kPreviewAreaLeft, GetIndicatorState(resizer.get())); CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(browser_window1.get())->IsSnapped()); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); // Should not consider the drag position if splitview is active. Window should // still back to be snapped. @@ -3640,16 +3591,14 @@ CreateWindowWithType(bounds, AppType::BROWSER)); split_view_controller()->SnapWindow(browser_window2.get(), SplitViewController::RIGHT); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); resizer = StartDrag(browser_window1.get(), browser_window1.get()); drop_target_bounds = GetDropTargetBoundsDuringDrag(browser_window1.get()); DragWindowTo(resizer.get(), gfx::Point(0, drop_target_bounds.y() + 10)); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); CompleteDrag(std::move(resizer)); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EndSplitView(); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); @@ -3670,7 +3619,7 @@ 10)); CompleteDrag(std::move(resizer)); EXPECT_TRUE(wm::GetWindowState(browser_window1.get())->IsMaximized()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Tests that a dragged window should have the active window shadow during @@ -3791,11 +3740,10 @@ EXPECT_TRUE(window_state2->IsSnapped()); CompleteDrag(std::move(resizer)); OverviewController* selector_controller = Shell::Get()->overview_controller(); - EXPECT_TRUE(selector_controller->IsSelecting()); + EXPECT_TRUE(selector_controller->InOverviewSession()); EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview( window2.get())); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_TRUE(window_state2->IsSnapped()); // Drags |window1| by a small distance. Both splitview and overview should be @@ -3806,7 +3754,7 @@ EXPECT_TRUE(window_state2->IsSnapped()); CompleteDrag(std::move(resizer)); - EXPECT_FALSE(selector_controller->IsSelecting()); + EXPECT_FALSE(selector_controller->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); EXPECT_TRUE(window_state1->IsMaximized()); EXPECT_TRUE(window_state2->IsMaximized()); @@ -3925,8 +3873,7 @@ drop_target_bounds.y() + 5)); EXPECT_EQ(GetIndicatorState(resizer.get()), IndicatorState::kPreviewAreaLeft); CompleteDrag(std::move(resizer)); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); } // Tests that if a fling event happens on a tab, the tab might or might not @@ -4022,8 +3969,7 @@ CompleteDrag(std::move(resizer)); EXPECT_EQ(window1->bounds(), snapped_bounds1); EXPECT_EQ(window2->bounds(), snapped_bounds2); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); // 4. If splitview is active and the dragged window is not the source window. resizer = StartDrag(window3.get(), window1.get()); @@ -4036,8 +3982,7 @@ DragWindowTo(resizer.get(), gfx::Point(100, 200)); EXPECT_EQ(window1->bounds(), snapped_bounds1); EXPECT_EQ(window2->bounds(), snapped_bounds2); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); CompleteDrag(std::move(resizer)); // In this case |window3| is supposed to merge back its source window @@ -4046,8 +3991,7 @@ EXPECT_EQ(window2->bounds(), snapped_bounds2); EXPECT_TRUE(window1->GetProperty(kIsDeferredTabDraggingTargetWindowKey)); window1->ClearProperty(kIsDeferredTabDraggingTargetWindowKey); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); // b). Drag the window far enough so that the dragged window doesn't merge // back into its source window. @@ -4073,9 +4017,9 @@ StartDrag(dragged_window.get(), dragged_window.get()); DragWindowTo(resizer.get(), gfx::Point(300, 300)); EXPECT_TRUE(wm::GetWindowState(dragged_window.get())->is_dragged()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); GetEventGenerator()->PressKey(ui::VKEY_MEDIA_LAUNCH_APP1, ui::EF_NONE); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_FALSE(Shell::Get() ->overview_controller() ->overview_session() @@ -4100,16 +4044,14 @@ split_view_controller()->SnapWindow(window1.get(), SplitViewController::LEFT); ToggleOverview(); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); std::unique_ptr<aura::Window> dragged_window( CreateWindowWithType(bounds, AppType::BROWSER)); EXPECT_EQ(split_view_controller()->InSplitViewMode(), true); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); std::unique_ptr<WindowResizer> resizer = StartDrag(dragged_window.get(), window1.get()); @@ -4123,9 +4065,8 @@ wm::ActivateWindow(dragged_window.get()); SetIsInTabDragging(resizer->GetTarget(), /*is_dragging=*/false); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop()); } @@ -4141,16 +4082,14 @@ SplitViewController::LEFT); split_view_controller()->SnapWindow(another_window.get(), SplitViewController::RIGHT); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); // If the dragged window stays as a separate window after drag ends: std::unique_ptr<WindowResizer> resizer = StartDrag(dragged_window.get(), dragged_window.get()); DragWindowWithOffset(resizer.get(), 10, 10); CompleteDrag(std::move(resizer)); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::BOTH_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kBothSnapped); EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop()); // If the dragged window is destroyed after drag ends: @@ -4159,9 +4098,8 @@ resizer->CompleteDrag(); resizer.reset(); dragged_window.reset(); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::RIGHT_SNAPPED); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kRightSnapped); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_TRUE(split_view_divider()->divider_widget()->IsAlwaysOnTop()); } @@ -4187,7 +4125,7 @@ // and overview is not opened behind the dragged window. EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(left_window.get())); EXPECT_TRUE(split_view_controller()->IsWindowInSplitView(right_window.get())); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } class TestWindowDelegateWithWidget : public views::WidgetDelegate { @@ -4309,11 +4247,11 @@ // dropped into overview. SendScrollStartAndUpdate(location); OverviewController* overview_controller = Shell::Get()->overview_controller(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_FALSE( overview_controller->overview_session()->IsWindowInOverview(window())); EndScrollSequence(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_FALSE(split_view_controller()->InSplitViewMode()); EXPECT_TRUE( overview_controller->overview_session()->IsWindowInOverview(window())); @@ -4341,15 +4279,14 @@ location.set_y(long_scroll_delta); SendScrollStartAndUpdate(location); OverviewController* overview_controller = Shell::Get()->overview_controller(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_FALSE( overview_controller->overview_session()->IsWindowInOverview(window())); EndScrollSequence(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_TRUE(split_view_controller()->InSplitViewMode()); EXPECT_EQ(split_view_controller()->left_window(), window()); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_TRUE(wm::GetWindowState(window())->IsSnapped()); // FLING the window with small velocity (smaller than @@ -4357,19 +4294,19 @@ location.set_y(10); SendScrollStartAndUpdate(location); overview_controller = Shell::Get()->overview_controller(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); Fling(location, TabletModeWindowDragDelegate::kFlingToOverviewThreshold - 10.f, 0); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); // FLING the window with large velocity (larger than // kFlingToOverviewThreshold) will drop the window into overview. SendScrollStartAndUpdate(location); overview_controller = Shell::Get()->overview_controller(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); Fling(location, TabletModeWindowDragDelegate::kFlingToOverviewThreshold + 10.f, 0); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); } // Tests the shelf visibility when a fullscreened window is being dragged. @@ -4436,8 +4373,7 @@ // Shelf should be shown during drag. EXPECT_EQ(SHELF_AUTO_HIDE_SHOWN, shelf->GetAutoHideState()); EndScrollSequence(); - EXPECT_EQ(split_view_controller()->state(), - SplitViewController::LEFT_SNAPPED); + EXPECT_EQ(split_view_controller()->state(), SplitViewState::kLeftSnapped); EXPECT_EQ(SHELF_AUTO_HIDE, shelf->GetVisibilityState()); // Shelf should be shown after drag and snapped window should be covered by // the auto-hide-shown shelf. @@ -4473,7 +4409,7 @@ Fling(location, /*velocity_y*/ 0, /*velocity_x=*/large_velocity); OverviewController* overview_controller = Shell::Get()->overview_controller(); OverviewSession* overview_session = overview_controller->overview_session(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_TRUE(overview_session->IsWindowInOverview(window())); ToggleOverview(); EXPECT_TRUE(wm::GetWindowState(window())->IsMaximized()); @@ -4494,7 +4430,7 @@ EXPECT_EQ(IndicatorState::kPreviewAreaRight, GetIndicatorState()); Fling(location, /*velocity_y*/ 0, /*velocity_x=*/-large_velocity); overview_session = overview_controller->overview_session(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_TRUE(overview_session->IsWindowInOverview(window())); ToggleOverview(); @@ -4529,8 +4465,7 @@ SendScrollStartAndUpdate(location); Fling(location, /*velocity_y=*/0, /*velocity_x=*/-large_velocity); EXPECT_TRUE(wm::GetWindowState(window())->IsSnapped()); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); // Fling the window in left snapping area to right should drop the window // into overview. @@ -4539,8 +4474,7 @@ OverviewController* selector_controller = Shell::Get()->overview_controller(); EXPECT_TRUE( selector_controller->overview_session()->IsWindowInOverview(window())); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state()); EXPECT_TRUE(IsTabletMode()); ToggleOverview(); EXPECT_TRUE(IsTabletMode()); @@ -4548,81 +4482,69 @@ // If the window is to the left of the divider but outside the left snapping // area, then flinging to the left should drop the window into overview (like // just ending the drag). - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); location.set_x(display_bounds.CenterPoint().x() - 10); SendScrollStartAndUpdate(location); Fling(location, /*velocity_y=*/0, /*velocity_x=*/-large_velocity); EXPECT_TRUE( selector_controller->overview_session()->IsWindowInOverview(window())); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state()); ToggleOverview(); // If the window is to the left of the divider but outside the left snapping // area, then flinging to the right should drop the window into overview (like // just ending the drag). - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); SendScrollStartAndUpdate(location); Fling(location, /*velocity_y=*/0, /*velocity_x=*/large_velocity); EXPECT_TRUE( selector_controller->overview_session()->IsWindowInOverview(window())); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state()); ToggleOverview(); // If the window is to the right of the divider but outside the right snapping // area, then flinging to the left should drop the window into overview (like // just ending the drag). - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); location.set_x(display_bounds.CenterPoint().x() + 10); SendScrollStartAndUpdate(location); Fling(location, /*velocity_y=*/0, /*velocity_x=*/-large_velocity); EXPECT_TRUE( selector_controller->overview_session()->IsWindowInOverview(window())); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state()); ToggleOverview(); // If the window is to the right of the divider but outside the right snapping // area, then flinging to the right should drop the window into overview (like // just ending the drag). - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); SendScrollStartAndUpdate(location); Fling(location, /*velocity_y=*/0, /*velocity_x=*/large_velocity); EXPECT_TRUE( selector_controller->overview_session()->IsWindowInOverview(window())); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state()); ToggleOverview(); // Fling the window in right snapping area to left should drop the window into // overview. - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); location.set_x(display_bounds.right() - 1); SendScrollStartAndUpdate(location); Fling(location, /*velocity_y=*/0, /*velocity_x=*/-large_velocity); EXPECT_TRUE( selector_controller->overview_session()->IsWindowInOverview(window())); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state()); ToggleOverview(); // Fling the window in right snapping area to right should snap the window to // right side. - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller()->state()); SendScrollStartAndUpdate(location); Fling(location, /*velocity_y=*/0, /*velocity_x=*/large_velocity); EXPECT_EQ(split_view_controller()->right_window(), window()); EXPECT_TRUE(selector_controller->overview_session()->IsWindowInOverview( window2.get())); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, - split_view_controller()->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller()->state()); } // Tests the backdrop bounds during window drag.
diff --git a/ash/wm/splitview/split_view_drag_indicators_unittest.cc b/ash/wm/splitview/split_view_drag_indicators_unittest.cc index 74cc217a..4a0a1fe 100644 --- a/ash/wm/splitview/split_view_drag_indicators_unittest.cc +++ b/ash/wm/splitview/split_view_drag_indicators_unittest.cc
@@ -48,7 +48,7 @@ void ToggleOverview() { auto* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - if (!overview_controller->IsSelecting()) { + if (!overview_controller->InOverviewSession()) { overview_session_ = nullptr; split_view_drag_indicators_ = nullptr; return; @@ -167,7 +167,7 @@ // Verify if the drag is started in the left snap region, the drag needs to // move by |drag_offset_snap_region| towards the right side of the screen // before split view acknowledges the drag (shows the preview area). - ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); generator->set_current_screen_location( gfx::Point(left_item->target_bounds().origin().x() + item_inset, left_item->target_bounds().CenterPoint().y())); @@ -196,7 +196,7 @@ // Verify if the drag is started in the right snap region, the drag needs to // move by |drag_offset_snap_region| towards the left side of the screen // before split view acknowledges the drag. - ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); generator->set_current_screen_location( gfx::Point(right_item->target_bounds().right() - item_inset, right_item->target_bounds().CenterPoint().y())); @@ -309,8 +309,7 @@ // Snap window to the left. overview_session_->CompleteDrag(item, gfx::PointF(edge_inset, y_position)); ASSERT_TRUE(split_view_controller()->InSplitViewMode()); - ASSERT_EQ(SplitViewController::LEFT_SNAPPED, - split_view_controller()->state()); + ASSERT_EQ(SplitViewState::kLeftSnapped, split_view_controller()->state()); // Verify that when there is a left snapped window, dragging an item to the // right will show the right preview area. @@ -422,7 +421,7 @@ gfx::PointF(primary_screen_bounds.CenterPoint())); overview_session_->CompleteDrag( item, gfx::PointF(primary_screen_bounds.CenterPoint())); - ASSERT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + ASSERT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); ASSERT_FALSE(split_view_controller()->InSplitViewMode()); // Select an item on the secondary display and verify the indicators widget
diff --git a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc index 3a3f22b..e840ec2 100644 --- a/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc +++ b/ash/wm/tablet_mode/tablet_mode_browser_window_drag_delegate.cc
@@ -128,7 +128,7 @@ source_window->SetProperty(kBackdropWindowMode, BackdropWindowMode::kDisabled); - DCHECK(!Shell::Get()->overview_controller()->IsSelecting()); + DCHECK(!Shell::Get()->overview_controller()->InOverviewSession()); aura::Window* root_window = dragged_window->GetRootWindow(); std::vector<aura::Window*> windows = @@ -176,7 +176,7 @@ } } - DCHECK(!Shell::Get()->overview_controller()->IsSelecting()); + DCHECK(!Shell::Get()->overview_controller()->InOverviewSession()); // May reshow the home launcher after dragging. Shell::Get()->home_screen_controller()->OnWindowDragEnded();
diff --git a/ash/wm/tablet_mode/tablet_mode_controller.cc b/ash/wm/tablet_mode/tablet_mode_controller.cc index c3481ab..34e30b8 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller.cc
@@ -267,8 +267,8 @@ // side, then overview mode should be started (to be seen on the side with // no snapped window). const auto state = Shell::Get()->split_view_controller()->state(); - if (state == SplitViewController::LEFT_SNAPPED || - state == SplitViewController::RIGHT_SNAPPED) { + if (state == SplitViewState::kLeftSnapped || + state == SplitViewState::kRightSnapped) { Shell::Get()->overview_controller()->ToggleOverview(); }
diff --git a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc index 2a815e4..159052a 100644 --- a/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_controller_unittest.cc
@@ -5,6 +5,7 @@ #include "ash/wm/tablet_mode/tablet_mode_controller.h" #include <math.h> + #include <utility> #include <vector> @@ -24,6 +25,7 @@ #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "ash/wm/overview/overview_controller.h" +#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/splitview/split_view_utils.h" #include "ash/wm/tablet_mode/tablet_mode_controller_test_api.h" #include "ash/wm/wm_event.h" @@ -541,7 +543,7 @@ // Test if this case does not crash. See http://crbug.com/462806 TEST_F(TabletModeControllerTest, DisplayDisconnectionDuringOverview) { // Do not animate wallpaper on entering overview. - OverviewController::SetDoNotChangeWallpaperBlurForTests(); + OverviewController::SetDoNotChangeWallpaperForTests(); UpdateDisplay("800x600,800x600"); std::unique_ptr<aura::Window> w1( @@ -556,7 +558,7 @@ UpdateDisplay("800x600"); base::RunLoop().RunUntilIdle(); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); EXPECT_EQ(w1->GetRootWindow(), w2->GetRootWindow()); } @@ -1129,8 +1131,8 @@ std::unique_ptr<aura::Window> window = CreateTestWindow(); ::wm::ActivateWindow(window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller->state()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if the active window is snapped on the left before tablet mode, @@ -1141,9 +1143,9 @@ std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedLeft(); ::wm::ActivateWindow(window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state()); EXPECT_EQ(window.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if the active window is snapped on the right before tablet mode, @@ -1154,9 +1156,9 @@ std::unique_ptr<aura::Window> window = CreateDesktopWindowSnappedRight(); ::wm::ActivateWindow(window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller->state()); EXPECT_EQ(window.get(), split_view_controller->right_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is snapped on the left and @@ -1170,10 +1172,10 @@ CreateDesktopWindowSnappedRight(); ::wm::ActivateWindow(left_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller->state()); EXPECT_EQ(left_window.get(), split_view_controller->left_window()); EXPECT_EQ(right_window.get(), split_view_controller->right_window()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is snapped on the right @@ -1187,10 +1189,10 @@ CreateDesktopWindowSnappedRight(); ::wm::ActivateWindow(left_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::BOTH_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kBothSnapped, split_view_controller->state()); EXPECT_EQ(left_window.get(), split_view_controller->left_window()); EXPECT_EQ(right_window.get(), split_view_controller->right_window()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is an ARC window snapped @@ -1207,8 +1209,8 @@ CreateDesktopWindowSnappedRight(); ::wm::ActivateWindow(left_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller->state()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is snapped on the left, @@ -1229,9 +1231,9 @@ ::wm::ActivateWindow(right_window.get()); ::wm::ActivateWindow(left_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state()); EXPECT_EQ(left_window.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is a transient child of a @@ -1247,9 +1249,9 @@ ::wm::ActivateWindow(parent.get()); ::wm::ActivateWindow(child.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state()); EXPECT_EQ(parent.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is the app list and the @@ -1264,9 +1266,9 @@ ASSERT_TRUE(::wm::IsActiveWindow( GetAppListTestHelper()->GetAppListView()->GetWidget()->GetNativeView())); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state()); EXPECT_EQ(window.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is being dragged and the @@ -1288,9 +1290,9 @@ ::wm::ActivateWindow(snapped_window.get()); ::wm::ActivateWindow(dragged_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state()); EXPECT_EQ(snapped_window.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is hidden from overview @@ -1308,9 +1310,9 @@ ::wm::ActivateWindow(snapped_window.get()); ::wm::ActivateWindow(window_hidden_from_overview.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state()); EXPECT_EQ(snapped_window.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is snapped on the left but @@ -1338,8 +1340,8 @@ ::wm::ActivateWindow(right_window.get()); ::wm::ActivateWindow(left_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller->state()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is snapped on the right @@ -1368,8 +1370,8 @@ ::wm::ActivateWindow(left_window.get()); ::wm::ActivateWindow(right_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::NO_SNAP, split_view_controller->state()); - EXPECT_FALSE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_EQ(SplitViewState::kNoSnap, split_view_controller->state()); + EXPECT_FALSE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is snapped on the left and @@ -1399,9 +1401,9 @@ ::wm::ActivateWindow(right_window.get()); ::wm::ActivateWindow(left_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state()); EXPECT_EQ(left_window.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if before tablet mode, the active window is snapped on the right @@ -1430,9 +1432,9 @@ ::wm::ActivateWindow(left_window.get()); ::wm::ActivateWindow(right_window.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::RIGHT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kRightSnapped, split_view_controller->state()); EXPECT_EQ(right_window.get(), split_view_controller->right_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that if overview is triggered on entering tablet mode, then the app list @@ -1458,9 +1460,9 @@ std::unique_ptr<aura::Window> window2 = CreateDesktopWindowSnappedLeft(); ::wm::ActivateWindow(window1.get()); tablet_mode_controller()->EnableTabletModeWindowManager(true); - EXPECT_EQ(SplitViewController::LEFT_SNAPPED, split_view_controller->state()); + EXPECT_EQ(SplitViewState::kLeftSnapped, split_view_controller->state()); EXPECT_EQ(window1.get(), split_view_controller->left_window()); - EXPECT_TRUE(Shell::Get()->overview_controller()->IsSelecting()); + EXPECT_TRUE(Shell::Get()->overview_controller()->InOverviewSession()); } // Test that it is okay to write code that first starts split view by snapping a
diff --git a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc index 27c2458..98c19c4b 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_drag_delegate.cc
@@ -60,7 +60,7 @@ // Returns the overview session if overview mode is active, otherwise returns // nullptr. OverviewSession* GetOverviewSession() { - return Shell::Get()->overview_controller()->IsSelecting() + return Shell::Get()->overview_controller()->InOverviewSession() ? Shell::Get()->overview_controller()->overview_session() : nullptr; } @@ -141,13 +141,13 @@ BackdropWindowMode::kDisabled); OverviewController* controller = Shell::Get()->overview_controller(); - bool was_overview_open = controller->IsSelecting(); + bool was_overview_open = controller->InOverviewSession(); const bool was_splitview_active = split_view_controller_->InSplitViewMode(); // If the dragged window is one of the snapped windows, SplitViewController // might open overview in the dragged window side of the screen. split_view_controller_->OnWindowDragStarted(dragged_window_); - if (ShouldOpenOverviewWhenDragStarts() && !controller->IsSelecting()) { + if (ShouldOpenOverviewWhenDragStarts() && !controller->InOverviewSession()) { OverviewButtonTray* overview_button_tray = RootWindowController::ForWindow(dragged_window_) ->GetStatusAreaWidget() @@ -158,7 +158,7 @@ OverviewSession::EnterExitOverviewType::kWindowDragged); } - if (controller->IsSelecting()) { + if (controller->InOverviewSession()) { // Only do animation if overview was open before the drag started. If the // overview is opened because of the window drag, do not do animation. GetOverviewSession()->OnWindowDragStarted(dragged_window_, @@ -193,7 +193,7 @@ if (was_splitview_active) tablet_mode_controller->increment_app_window_drag_in_splitview_count(); } - if (controller->IsSelecting()) { + if (controller->InOverviewSession()) { UMA_HISTOGRAM_COUNTS_100( "Tablet.WindowDrag.OpenedWindowsNumber", shell->mru_window_tracker()->BuildMruWindowList().size()); @@ -296,7 +296,7 @@ void TabletModeWindowDragDelegate::FlingOrSwipe(ui::GestureEvent* event) { if (ShouldFlingIntoOverview(event)) { - DCHECK(Shell::Get()->overview_controller()->IsSelecting()); + DCHECK(Shell::Get()->overview_controller()->InOverviewSession()); Shell::Get()->overview_controller()->overview_session()->AddItem( dragged_window_, /*reposition=*/true, /*animate=*/false); } @@ -394,7 +394,7 @@ void TabletModeWindowDragDelegate::UpdateDraggedWindowTransform( const gfx::Point& location_in_screen) { - DCHECK(Shell::Get()->overview_controller()->IsSelecting()); + DCHECK(Shell::Get()->overview_controller()->InOverviewSession()); // Calculate the desired scale along the y-axis. The scale of the window // during drag is based on the distance from |y_location_in_screen| to the y @@ -456,7 +456,7 @@ // overview is not opened when drag starts (if it's tab-dragging and the // dragged window is not the same with the source window), we should not fling // the dragged window into overview in this case. - if (!Shell::Get()->overview_controller()->IsSelecting()) + if (!Shell::Get()->overview_controller()->InOverviewSession()) return false; const gfx::Point location_in_screen = GetEventLocationInScreen(event);
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager.cc b/ash/wm/tablet_mode/tablet_mode_window_manager.cc index 4c2794d..e96f941 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_manager.cc
@@ -40,8 +40,8 @@ // active before cancelling it. bool CancelOverview() { OverviewController* controller = Shell::Get()->overview_controller(); - if (controller->IsSelecting()) { - controller->OnSelectionEnded(); + if (controller->InOverviewSession()) { + controller->EndOverview(); return true; } return false; @@ -346,7 +346,7 @@ default: break; } - if (split_view_controller->state() == SplitViewController::BOTH_SNAPPED) + if (split_view_controller->state() == SplitViewState::kBothSnapped) break; } } @@ -354,10 +354,10 @@ // Ensure that overview mode is active if and only if there is a window // snapped to one side but no window snapped to the other side. OverviewController* overview_controller = Shell::Get()->overview_controller(); - SplitViewController::State state = split_view_controller->state(); - if (overview_controller->IsSelecting() != - (state == SplitViewController::LEFT_SNAPPED || - state == SplitViewController::RIGHT_SNAPPED)) { + SplitViewState state = split_view_controller->state(); + if (overview_controller->InOverviewSession() != + (state == SplitViewState::kLeftSnapped || + state == SplitViewState::kRightSnapped)) { overview_controller->ToggleOverview(); } }
diff --git a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc index 5e4ec41..5ced090 100644 --- a/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc +++ b/ash/wm/tablet_mode/tablet_mode_window_manager_unittest.cc
@@ -1316,17 +1316,17 @@ OverviewController* overview_controller = Shell::Get()->overview_controller(); ASSERT_TRUE(overview_controller->ToggleOverview()); - ASSERT_TRUE(overview_controller->IsSelecting()); + ASSERT_TRUE(overview_controller->InOverviewSession()); TabletModeWindowManager* manager = CreateTabletModeWindowManager(); ASSERT_TRUE(manager); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); ASSERT_TRUE(overview_controller->ToggleOverview()); - ASSERT_TRUE(overview_controller->IsSelecting()); + ASSERT_TRUE(overview_controller->InOverviewSession()); // Destroy the manager again and check that the windows return to their // previous state. DestroyTabletModeWindowManager(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); } // Test that an edge swipe from the top will end full screen mode.
diff --git a/ash/wm/toplevel_window_event_handler_unittest.cc b/ash/wm/toplevel_window_event_handler_unittest.cc index 96d3ddb9..448b62f4 100644 --- a/ash/wm/toplevel_window_event_handler_unittest.cc +++ b/ash/wm/toplevel_window_event_handler_unittest.cc
@@ -1188,7 +1188,7 @@ EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged()); OverviewController* overview_controller = Shell::Get()->overview_controller(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview( non_dragged_window_.get())); @@ -1202,7 +1202,7 @@ // Overview mode is no longer active and |non_dragged_window_| is not in the // overview grid after tapping it in overview grid. - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); EXPECT_FALSE(overview_controller->overview_session()); } @@ -1221,7 +1221,7 @@ EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged()); OverviewController* overview_controller = Shell::Get()->overview_controller(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview( non_dragged_window_.get())); } @@ -1241,7 +1241,7 @@ EXPECT_FALSE(wm::GetWindowState(dragged_window_.get())->is_dragged()); OverviewController* overview_controller = Shell::Get()->overview_controller(); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); } // Tests that the window drag will be reverted if the screen is being rotated. @@ -1270,7 +1270,7 @@ EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->is_dragged()); OverviewController* overview_controller = Shell::Get()->overview_controller(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); EXPECT_TRUE(overview_controller->overview_session()->IsWindowInOverview( non_dragged_window_.get())); @@ -1280,7 +1280,7 @@ EXPECT_EQ(test_api.GetCurrentOrientation(), OrientationLockType::kPortraitPrimary); EXPECT_TRUE(wm::GetWindowState(dragged_window_.get())->IsMaximized()); - EXPECT_FALSE(overview_controller->IsSelecting()); + EXPECT_FALSE(overview_controller->InOverviewSession()); EXPECT_FALSE(wm::GetWindowState(dragged_window_.get())->is_dragged()); }
diff --git a/ash/wm/window_finder.cc b/ash/wm/window_finder.cc index 9032d1f..1168a22a 100644 --- a/ash/wm/window_finder.cc +++ b/ash/wm/window_finder.cc
@@ -96,7 +96,7 @@ const std::set<aura::Window*>& ignore) { ash::OverviewController* overview_controller = ash::Shell::Get()->overview_controller(); - if (!overview_controller->IsSelecting()) + if (!overview_controller->InOverviewSession()) return nullptr; ash::OverviewGrid* grid =
diff --git a/ash/wm/window_finder_unittest.cc b/ash/wm/window_finder_unittest.cc index 6ab3203c0..594a1a4 100644 --- a/ash/wm/window_finder_unittest.cc +++ b/ash/wm/window_finder_unittest.cc
@@ -83,7 +83,7 @@ OverviewController* overview_controller = Shell::Get()->overview_controller(); overview_controller->ToggleOverview(); - EXPECT_TRUE(overview_controller->IsSelecting()); + EXPECT_TRUE(overview_controller->InOverviewSession()); // Get |window1| and |window2|'s transformed bounds in overview. OverviewGrid* grid =
diff --git a/ash/wm/wm_shadow_controller_delegate.cc b/ash/wm/wm_shadow_controller_delegate.cc index 9d19241..6ea4f9f 100644 --- a/ash/wm/wm_shadow_controller_delegate.cc +++ b/ash/wm/wm_shadow_controller_delegate.cc
@@ -31,9 +31,9 @@ // Hide the shadow while we are in overview mode. OverviewController* overview_controller = Shell::Get()->overview_controller(); - if (overview_controller && overview_controller->IsSelecting()) { + if (overview_controller && overview_controller->InOverviewSession()) { OverviewSession* overview_session = overview_controller->overview_session(); - // IsSelecting() being true implies |overview_session| exists. + // InOverviewSession() being true implies |overview_session| exists. DCHECK(overview_session); if (overview_session->IsWindowInOverview(window)) return false;
diff --git a/ash/wm/workspace/backdrop_controller.cc b/ash/wm/workspace/backdrop_controller.cc index 5e5e19b..da90575d 100644 --- a/ash/wm/workspace/backdrop_controller.cc +++ b/ash/wm/workspace/backdrop_controller.cc
@@ -18,6 +18,7 @@ #include "ash/wallpaper/wallpaper_controller.h" #include "ash/wm/always_on_top_controller.h" #include "ash/wm/overview/overview_controller.h" +#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/window_animations.h" #include "ash/wm/window_state.h" #include "ash/wm/window_util.h" @@ -125,7 +126,7 @@ // No need to continue update for recursive calls or in overview mode. OverviewController* overview_controller = Shell::Get()->overview_controller(); if (pause_update_ || - (overview_controller && overview_controller->IsSelecting())) { + (overview_controller && overview_controller->InOverviewSession())) { return; } @@ -190,9 +191,8 @@ UpdateBackdrop(); } -void BackdropController::OnSplitViewStateChanged( - SplitViewController::State previous_state, - SplitViewController::State state) { +void BackdropController::OnSplitViewStateChanged(SplitViewState previous_state, + SplitViewState state) { UpdateBackdrop(); } @@ -321,10 +321,10 @@ aura::Window* window = GetTopmostWindowWithBackdrop(); SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); - SplitViewController::State state = split_view_controller->state(); - if ((state == SplitViewController::LEFT_SNAPPED && + SplitViewState state = split_view_controller->state(); + if ((state == SplitViewState::kLeftSnapped && window == split_view_controller->left_window()) || - (state == SplitViewController::RIGHT_SNAPPED && + (state == SplitViewState::kRightSnapped && window == split_view_controller->right_window())) { return false; } @@ -337,14 +337,14 @@ SplitViewController* split_view_controller = Shell::Get()->split_view_controller(); - SplitViewController::State state = split_view_controller->state(); - DCHECK(state == SplitViewController::LEFT_SNAPPED || - state == SplitViewController::RIGHT_SNAPPED); + SplitViewState state = split_view_controller->state(); + DCHECK(state == SplitViewState::kLeftSnapped || + state == SplitViewState::kRightSnapped); aura::Window* snapped_window = split_view_controller->GetDefaultSnappedWindow(); SplitViewController::SnapPosition snap_position = - (state == SplitViewController::LEFT_SNAPPED) ? SplitViewController::LEFT - : SplitViewController::RIGHT; + (state == SplitViewState::kLeftSnapped) ? SplitViewController::LEFT + : SplitViewController::RIGHT; return split_view_controller->GetSnappedWindowBoundsInScreenUnadjusted( snapped_window, snap_position); }
diff --git a/ash/wm/workspace/backdrop_controller.h b/ash/wm/workspace/backdrop_controller.h index 2dc74b30..adb59f62 100644 --- a/ash/wm/workspace/backdrop_controller.h +++ b/ash/wm/workspace/backdrop_controller.h
@@ -8,11 +8,12 @@ #include <memory> #include "ash/accessibility/accessibility_observer.h" +#include "ash/public/cpp/split_view.h" #include "ash/shell_observer.h" #include "ash/wallpaper/wallpaper_controller_observer.h" #include "ash/wm/overview/overview_observer.h" -#include "ash/wm/splitview/split_view_controller.h" #include "base/macros.h" +#include "ui/gfx/geometry/rect.h" namespace aura { class Window; @@ -47,7 +48,7 @@ class BackdropController : public AccessibilityObserver, public ShellObserver, public OverviewObserver, - public SplitViewController::Observer, + public SplitViewObserver, public WallpaperControllerObserver { public: explicit BackdropController(aura::Window* container); @@ -81,9 +82,9 @@ // AccessibilityObserver: void OnAccessibilityStatusChanged() override; - // SplitViewController::Observer: - void OnSplitViewStateChanged(SplitViewController::State previous_state, - SplitViewController::State state) override; + // SplitViewObserver: + void OnSplitViewStateChanged(SplitViewState previous_state, + SplitViewState state) override; void OnSplitViewDividerPositionChanged() override; // WallpaperControllerObserver:
diff --git a/ash/wm/workspace_controller.cc b/ash/wm/workspace_controller.cc index d2a98c5f..d106faa 100644 --- a/ash/wm/workspace_controller.cc +++ b/ash/wm/workspace_controller.cc
@@ -73,7 +73,7 @@ // the same regardles of the window we have. // The |overview_controller| can be null during shutdown. if (Shell::Get()->overview_controller() && - Shell::Get()->overview_controller()->IsSelecting()) { + Shell::Get()->overview_controller()->InOverviewSession()) { return wm::WORKSPACE_WINDOW_STATE_DEFAULT; }
diff --git a/base/android/java/src/org/chromium/base/BuildInfo.java b/base/android/java/src/org/chromium/base/BuildInfo.java index 38489ca..0e636934 100644 --- a/base/android/java/src/org/chromium/base/BuildInfo.java +++ b/base/android/java/src/org/chromium/base/BuildInfo.java
@@ -166,10 +166,9 @@ abiString = String.format("ABI1: %s, ABI2: %s", Build.CPU_ABI, Build.CPU_ABI2); } - // Use lastUpdateTime when developing locally, since versionCode does not normally - // change in this case. - long version = versionCode > 10 ? versionCode : pi.lastUpdateTime; - extractedFileSuffix = String.format("@%x", version); + // Append lastUpdateTime to versionCode, since versionCode is unlikely to change when + // developing locally but lastUpdateTime is. + extractedFileSuffix = String.format("@%x_%x", versionCode, pi.lastUpdateTime); // The value is truncated, as this is used for crash and UMA reporting. androidBuildFingerprint = Build.FINGERPRINT.substring(
diff --git a/base/task/common/task_annotator.cc b/base/task/common/task_annotator.cc index d5d0428..1d76a20 100644 --- a/base/task/common/task_annotator.cc +++ b/base/task/common/task_annotator.cc
@@ -95,6 +95,10 @@ debug::ScopedTaskRunActivity task_activity(*pending_task); + TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("toplevel.ipc"), + "TaskAnnotator::RunTask", "ipc_program_counter", + pending_task->ipc_program_counter); + TRACE_EVENT_WITH_FLOW0( TRACE_DISABLED_BY_DEFAULT("toplevel.flow"), trace_event_name, TRACE_ID_MANGLE(GetTaskTraceID(*pending_task)), TRACE_EVENT_FLAG_FLOW_IN);
diff --git a/base/trace_event/builtin_categories.h b/base/trace_event/builtin_categories.h index 860caac..f656990 100644 --- a/base/trace_event/builtin_categories.h +++ b/base/trace_event/builtin_categories.h
@@ -198,6 +198,7 @@ X(TRACE_DISABLED_BY_DEFAULT("system_stats")) \ X(TRACE_DISABLED_BY_DEFAULT("thread_pool_diagnostics")) \ X(TRACE_DISABLED_BY_DEFAULT("toplevel.flow")) \ + X(TRACE_DISABLED_BY_DEFAULT("toplevel.ipc")) \ X(TRACE_DISABLED_BY_DEFAULT("v8.compile")) \ X(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler")) \ X(TRACE_DISABLED_BY_DEFAULT("v8.cpu_profiler.hires")) \
diff --git a/build/android/pylib/local/device/local_device_gtest_run.py b/build/android/pylib/local/device/local_device_gtest_run.py index 76d3e1b..be75fda 100644 --- a/build/android/pylib/local/device/local_device_gtest_run.py +++ b/build/android/pylib/local/device/local_device_gtest_run.py
@@ -526,7 +526,8 @@ with logcat_monitor.LogcatMonitor( device.adb, filter_specs=local_device_environment.LOGCAT_FILTERS, - output_file=logcat_file.name) as logmon: + output_file=logcat_file.name, + check_error=False) as logmon: with contextlib_ext.Optional( trace_event.trace(str(test)), self._env.trace_output):
diff --git a/build/android/pylib/local/device/local_device_instrumentation_test_run.py b/build/android/pylib/local/device/local_device_instrumentation_test_run.py index 4332e74..9b9a2a8 100644 --- a/build/android/pylib/local/device/local_device_instrumentation_test_run.py +++ b/build/android/pylib/local/device/local_device_instrumentation_test_run.py
@@ -534,8 +534,8 @@ device.adb, filter_specs=local_device_environment.LOGCAT_FILTERS, output_file=logcat_file.name, - transform_func=self._test_instance.MaybeDeobfuscateLines - ) as logmon: + transform_func=self._test_instance.MaybeDeobfuscateLines, + check_error=False) as logmon: with _LogTestEndpoints(device, test_name): with contextlib_ext.Optional( trace_event.trace(test_name),
diff --git a/build/android/test_runner.py b/build/android/test_runner.py index b26bade..9a6a935f 100755 --- a/build/android/test_runner.py +++ b/build/android/test_runner.py
@@ -932,7 +932,7 @@ test_name=args.command, cs_base_url='http://cs.chromium.org', local_output=True) - results_detail_file.write(result_html_string) + results_detail_file.write(result_html_string.encode('utf-8')) results_detail_file.flush() logging.critical('TEST RESULTS: %s', results_detail_file.Link())
diff --git a/build/fuchsia/linux.sdk.sha1 b/build/fuchsia/linux.sdk.sha1 index 69e4b30..2262e8c 100644 --- a/build/fuchsia/linux.sdk.sha1 +++ b/build/fuchsia/linux.sdk.sha1
@@ -1 +1 @@ -8914010619758962160 \ No newline at end of file +8913984631952060992 \ No newline at end of file
diff --git a/build/fuchsia/mac.sdk.sha1 b/build/fuchsia/mac.sdk.sha1 index dfeaf29..5d0c70db 100644 --- a/build/fuchsia/mac.sdk.sha1 +++ b/build/fuchsia/mac.sdk.sha1
@@ -1 +1 @@ -8914022441954645264 \ No newline at end of file +8914004655801404528 \ No newline at end of file
diff --git a/chrome/VERSION b/chrome/VERSION index c8fa725..991e640 100644 --- a/chrome/VERSION +++ b/chrome/VERSION
@@ -1,4 +1,4 @@ MAJOR=76 MINOR=0 -BUILD=3789 +BUILD=3790 PATCH=0
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn index febeddd..57df018 100644 --- a/chrome/android/BUILD.gn +++ b/chrome/android/BUILD.gn
@@ -2600,6 +2600,7 @@ "java/src/org/chromium/chrome/browser/rappor/RapporServiceBridge.java", "java/src/org/chromium/chrome/browser/rlz/RevenueStats.java", "java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java", + "java/src/org/chromium/chrome/browser/safe_browsing/FileTypePolicies.java", "java/src/org/chromium/chrome/browser/search_engines/TemplateUrl.java", "java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java", "java/src/org/chromium/chrome/browser/send_tab_to_self/NotificationManager.java",
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni index 05290d6..3e6f22d 100644 --- a/chrome/android/chrome_java_sources.gni +++ b/chrome/android/chrome_java_sources.gni
@@ -849,7 +849,6 @@ "java/src/org/chromium/chrome/browser/locale/LocaleManager.java", "java/src/org/chromium/chrome/browser/locale/LocaleTemplateUrlLoader.java", "java/src/org/chromium/chrome/browser/locale/SogouPromoDialog.java", - "java/src/org/chromium/chrome/browser/locationcustomizations/LocationCustomizations.java", "java/src/org/chromium/chrome/browser/login/ChromeHttpAuthHandler.java", "java/src/org/chromium/chrome/browser/login/LoginPrompt.java", "java/src/org/chromium/chrome/browser/media/MediaCaptureNotificationService.java", @@ -1356,6 +1355,7 @@ "java/src/org/chromium/chrome/browser/rappor/RapporServiceBridge.java", "java/src/org/chromium/chrome/browser/rlz/RevenueStats.java", "java/src/org/chromium/chrome/browser/rlz/RlzPingHandler.java", + "java/src/org/chromium/chrome/browser/safe_browsing/FileTypePolicies.java", "java/src/org/chromium/chrome/browser/search_engines/SearchEngineChoiceNotification.java", "java/src/org/chromium/chrome/browser/search_engines/TemplateUrl.java", "java/src/org/chromium/chrome/browser/search_engines/TemplateUrlService.java",
diff --git a/chrome/android/features/tab_ui/java/res/drawable/selected_tab_background.xml b/chrome/android/features/tab_ui/java/res/drawable/selected_tab_background.xml index 76e45e9..6c49104 100644 --- a/chrome/android/features/tab_ui/java/res/drawable/selected_tab_background.xml +++ b/chrome/android/features/tab_ui/java/res/drawable/selected_tab_background.xml
@@ -6,6 +6,6 @@ <shape xmlns:android="http://schemas.android.com/apk/res/android"> <stroke android:width="2dp" - android:color="@color/modern_blue_600" /> + android:color="@color/light_active_color" /> <corners android:radius="@dimen/default_rounded_corner_radius" /> </shape> \ No newline at end of file
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java index db98904..b5eb4e6 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/GridTabSwitcherCoordinator.java
@@ -45,7 +45,7 @@ ActivityLifecycleDispatcher lifecycleDispatcher, ToolbarManager toolbarManager, TabModelSelector tabModelSelector, TabContentManager tabContentManager, CompositorViewHolder compositorViewHolder, ChromeFullscreenManager fullscreenManager, - TabCreatorManager tabCreatorManager) { + TabCreatorManager tabCreatorManager, Runnable backPress) { PropertyModel containerViewModel = new PropertyModel(TabListContainerProperties.ALL_KEYS); TabListMediator.GridCardOnClickListenerProvider gridCardOnClickListenerProvider; if (FeatureUtilities.isTabGroupsAndroidUiImprovementsEnabled()) { @@ -86,8 +86,8 @@ org.chromium.chrome.tab_ui.R.layout.grid_tab_switcher_layout, COMPONENT_NAME); HistoryNavigationLayout navigation = compositorViewHolder.findViewById(R.id.history_navigation); - navigation.setNavigationDelegate( - HistoryNavigationDelegate.createForTabSwitcher(tabModelSelector::getCurrentTab)); + navigation.setNavigationDelegate(HistoryNavigationDelegate.createForTabSwitcher( + context, backPress, tabModelSelector::getCurrentTab)); mContainerViewChangeProcessor = PropertyModelChangeProcessor.create(containerViewModel, mTabGridCoordinator.getContainerView(), TabGridContainerViewBinder::bind);
diff --git a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleImpl.java b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleImpl.java index 5879a14..c15dcfe 100644 --- a/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleImpl.java +++ b/chrome/android/features/tab_ui/java/src/org/chromium/chrome/browser/tasks/tab_management/TabManagementModuleImpl.java
@@ -29,7 +29,7 @@ return new GridTabSwitcherCoordinator(activity, activity.getLifecycleDispatcher(), activity.getToolbarManager(), activity.getTabModelSelector(), activity.getTabContentManager(), activity.getCompositorViewHolder(), - activity.getFullscreenManager(), activity); + activity.getFullscreenManager(), activity, activity::onBackPressed); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java index 855e52fd..b71be10 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/ChromeTabbedActivity.java
@@ -95,7 +95,6 @@ import org.chromium.chrome.browser.infobar.DataReductionPromoInfoBar; import org.chromium.chrome.browser.language.LanguageAskPrompt; import org.chromium.chrome.browser.locale.LocaleManager; -import org.chromium.chrome.browser.locationcustomizations.LocationCustomizations; import org.chromium.chrome.browser.metrics.ActivityStopMetrics; import org.chromium.chrome.browser.metrics.LaunchMetrics; import org.chromium.chrome.browser.metrics.MainIntentBehaviorMetrics; @@ -798,7 +797,6 @@ mLocaleManager.setSnackbarManager(getSnackbarManager()); mLocaleManager.startObservingPhoneChanges(); - LocationCustomizations.initialize(); if (!ChromeFeatureList.isEnabled(ChromeFeatureList.INTEREST_FEED_CONTENT_SUGGESTIONS)) { if (isWarmOnResume()) {
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java index b6cf195..c164ff8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/compositor/layouts/phone/StackLayoutBase.java
@@ -533,7 +533,8 @@ if (mNavigationEnabled && mNavigationHandler == null) { Tab currentTab = mTabModelSelector.getCurrentTab(); mNavigationHandler = new NavigationHandler(mViewContainer, - new TabSwitcherActionDelegate(mTabModelSelector::getCurrentTab), + new TabSwitcherActionDelegate(currentTab.getActivity()::onBackPressed, + mTabModelSelector::getCurrentTab), NavigationGlowFactory.forSceneLayer(mViewContainer, mSceneLayer, currentTab.getActivity().getWindowAndroid())); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java index 33266622..a81b15df 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchManager.java
@@ -463,13 +463,14 @@ mReceivedContextualCardsEntityData = false; String selection = mSelectionController.getSelectedText(); - boolean isTap = mSelectionController.getSelectionType() == SelectionType.TAP; - if (isTap) { + boolean canResolve = mSelectionController.getSelectionType() == SelectionType.TAP + || mSelectionController.getSelectionType() == SelectionType.RESOLVING_LONG_PRESS; + if (canResolve) { // If the user action was not a long-press, we should not delay before loading content. mShouldLoadDelayedSearch = false; } - if (isTap && mPolicy.shouldPreviousGestureResolve()) { - // For a resolving Tap we'll figure out translation need after the Resolve. + if (canResolve && mPolicy.shouldPreviousGestureResolve()) { + // For a resolving gestures we'll figure out translation need after the Resolve. } else if (!TextUtils.isEmpty(selection)) { boolean shouldPrefetch = mPolicy.shouldPrefetchSearchResult(); mSearchRequest = new ContextualSearchRequest(selection, shouldPrefetch); @@ -480,7 +481,7 @@ // Record metrics for manual refinement of the search term from long-press. // TODO(donnd): remove this section once metrics have been analyzed. - if (!isTap && mSearchPanel.isPeeking()) { + if (!canResolve && mSearchPanel.isPeeking()) { boolean isSingleWord = !CONTAINS_WHITESPACE_PATTERN.matcher(selection.trim()).find(); RecordUserAction.record(isSingleWord ? "ContextualSearch.ManualRefineSingleWord"
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java index 843b77f0..d402419 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchSelectionController.java
@@ -258,7 +258,6 @@ mClearingSelection = true; SelectionPopupController controller = getSelectionPopupController(); if (controller != null) controller.clearSelection(); - mHandler.handleSelectionCleared(); resetSelectionStates(); mClearingSelection = false; } @@ -405,7 +404,7 @@ void handleShowUnhandledTapUIIfNeeded(int x, int y, int fontSizeDips, int textRunLength) { mWasTapGestureDetected = false; // TODO(donnd): refactor to avoid needing a new handler API method as suggested by Pedro. - if (mSelectionType != SelectionType.LONG_PRESS) { + if (mSelectionType != SelectionType.LONG_PRESS && !mAreSelectionHandlesShown) { if (mTapTimeNanoseconds != 0) { mTapDurationMs = (int) ((System.nanoTime() - mTapTimeNanoseconds) / TimeUtils.NANOSECONDS_PER_MILLISECOND); @@ -418,7 +417,7 @@ mTextRunLength = textRunLength; mHandler.handleValidTap(); } else { - // Long press; reset last tap state. + // Long press, or long-press selection handles shown; reset last tap state. mLastTapState = null; mHandler.handleInvalidTap(); } @@ -450,8 +449,7 @@ // been suppressed if each of the heuristics were satisfied. mHandler.handleMetricsForWouldSuppressTap(tapHeuristics); - boolean shouldSuppressTapBasedOnHeuristics = - tapHeuristics.shouldSuppressTap() || mAreSelectionHandlesShown; + boolean shouldSuppressTapBasedOnHeuristics = tapHeuristics.shouldSuppressTap(); boolean shouldOverrideMlTapSuppression = tapHeuristics.shouldOverrideMlTapSuppression(); // Make sure Tap Suppression features are consistent.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java index 628a4f9..9bccef8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/contextualsearch/SelectionClientManager.java
@@ -44,6 +44,9 @@ */ SelectionClientManager(WebContents webContents) { if (ChromeFeatureList.isEnabled(ChromeFeatureList.CHROME_SMART_SELECTION) + // TODO(donnd): revert this line when crbug.com/956277 is fixed. + && !ChromeFeatureList.isEnabled( + ChromeFeatureList.CONTEXTUAL_SEARCH_LONGPRESS_RESOLVE) && Build.VERSION.SDK_INT > Build.VERSION_CODES.O) { assert webContents != null; mOptionalSelectionClient = SelectionClient.createSmartSelectionClient(webContents);
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java index 6d82d4e..c836775d8 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadBroadcastManager.java
@@ -353,7 +353,7 @@ String referrer = IntentUtils.safeGetStringExtra(intent, Intent.EXTRA_REFERRER); DownloadManagerService.openDownloadedContent(context, downloadFilename, isSupportedMimeType, isOffTheRecord, contentId.id, id, originalUrl, referrer, - DownloadMetrics.DownloadOpenSource.NOTIFICATION); + DownloadMetrics.DownloadOpenSource.NOTIFICATION, null); }); }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java index abd86b86..0ff04e9f 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadManagerService.java
@@ -797,17 +797,18 @@ @Nullable static Intent getLaunchIntentForDownload(@Nullable String filePath, long downloadId, - boolean isSupportedMimeType, String originalUrl, String referrer) { + boolean isSupportedMimeType, String originalUrl, String referrer, + @Nullable String mimeType) { assert !ThreadUtils.runningOnUiThread(); if (downloadId == DownloadItem.INVALID_DOWNLOAD_ID) { if (!ContentUriUtils.isContentUri(filePath)) return null; return getLaunchIntentFromDownloadUri( - filePath, isSupportedMimeType, originalUrl, referrer); + filePath, isSupportedMimeType, originalUrl, referrer, mimeType); } DownloadManagerBridge.DownloadQueryResult queryResult = DownloadManagerBridge.queryDownloadResult(downloadId); - String mimeType = queryResult.mimeType; + if (mimeType == null) mimeType = queryResult.mimeType; Uri contentUri = filePath == null ? queryResult.contentUri @@ -827,23 +828,27 @@ * @param isSupportedMimeType Whether the MIME type is supported by browser. * @param originalUrl The original url of the downloaded file * @param referrer Referrer of the downloaded file. + * @param mimeType MIME type of the downloaded file. * @return the intent to launch for the given download item. */ @Nullable - private static Intent getLaunchIntentFromDownloadUri( - String contentUri, boolean isSupportedMimeType, String originalUrl, String referrer) { + private static Intent getLaunchIntentFromDownloadUri(String contentUri, + boolean isSupportedMimeType, String originalUrl, String referrer, + @Nullable String mimeType) { assert !ThreadUtils.runningOnUiThread(); assert ContentUriUtils.isContentUri(contentUri); Uri uri = Uri.parse(contentUri); - try (Cursor cursor = ContextUtils.getApplicationContext().getContentResolver().query( - uri, null, null, null, null)) { - if (cursor == null || cursor.getCount() == 0) return null; - cursor.moveToNext(); - String mimeType = cursor.getString(cursor.getColumnIndex(MediaColumns.MIME_TYPE)); - return createLaunchIntent( - uri, uri, mimeType, isSupportedMimeType, originalUrl, referrer); + if (mimeType == null) { + try (Cursor cursor = ContextUtils.getApplicationContext().getContentResolver().query( + uri, null, null, null, null)) { + if (cursor == null || cursor.getCount() == 0) return null; + cursor.moveToNext(); + mimeType = cursor.getString(cursor.getColumnIndex(MediaColumns.MIME_TYPE)); + cursor.close(); + } } + return createLaunchIntent(uri, uri, mimeType, isSupportedMimeType, originalUrl, referrer); } /** @@ -878,7 +883,8 @@ static boolean canResolveDownloadItem(DownloadItem download, boolean isSupportedMimeType) { assert !ThreadUtils.runningOnUiThread(); Intent intent = getLaunchIntentForDownload(download.getDownloadInfo().getFilePath(), - download.getSystemDownloadId(), isSupportedMimeType, null, null); + download.getSystemDownloadId(), isSupportedMimeType, null, null, + download.getDownloadInfo().getMimeType()); return (intent == null) ? false : ExternalNavigationDelegateImpl.resolveIntent(intent, true); } @@ -896,7 +902,7 @@ if (isOMADownloadDescription(mimeType)) return true; Intent intent = getLaunchIntentForDownload(filePath, systemDownloadId, - DownloadManagerService.isSupportedMimeType(mimeType), null, null); + DownloadManagerService.isSupportedMimeType(mimeType), null, null, mimeType); return intent != null && ExternalNavigationDelegateImpl.resolveIntent(intent, true); } @@ -906,7 +912,7 @@ openDownloadedContent(ContextUtils.getApplicationContext(), downloadInfo.getFilePath(), isSupportedMimeType(downloadInfo.getMimeType()), downloadInfo.isOffTheRecord(), downloadInfo.getDownloadGuid(), downloadId, downloadInfo.getOriginalUrl(), - downloadInfo.getReferrer(), source); + downloadInfo.getReferrer(), source, downloadInfo.getMimeType()); } /** @@ -915,23 +921,24 @@ * * @param context Context to use. * @param filePath Path to the downloaded item. - * @param isSupportedMimeType MIME type of the downloaded item. + * @param isSupportedMimeType Whether the MIME type is supported by Chrome. * @param isOffTheRecord Whether the download was for a off the record profile. * @param downloadGuid GUID of the download item in DownloadManager. * @param downloadId ID of the download item in DownloadManager. * @param originalUrl The original url of the downloaded file. * @param referrer Referrer of the downloaded file. * @param source The source that tries to open the download. + * @param mimeType MIME type of the download, could be null. */ protected static void openDownloadedContent(final Context context, final String filePath, final boolean isSupportedMimeType, final boolean isOffTheRecord, final String downloadGuid, final long downloadId, final String originalUrl, - final String referrer, @DownloadOpenSource int source) { + final String referrer, @DownloadOpenSource int source, @Nullable String mimeType) { new AsyncTask<Intent>() { @Override public Intent doInBackground() { return getLaunchIntentForDownload( - filePath, downloadId, isSupportedMimeType, originalUrl, referrer); + filePath, downloadId, isSupportedMimeType, originalUrl, referrer, mimeType); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationDelegate.java index e2cb0f9..4ed99c2b 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/HistoryNavigationDelegate.java
@@ -69,23 +69,27 @@ // Implementation for tab switcher. Can't go forward, and going back exits // the switcher. Can exit Chrome if there's no current tab to go back to. private static class TabSwitcherNavigationDelegate extends HistoryNavigationDelegate { - private Supplier<Tab> mCurrentTab; + private final Runnable mBackPress; + private final Supplier<Tab> mCurrentTab; - private TabSwitcherNavigationDelegate(Supplier<Tab> currentTab) { - super(currentTab.get().getActivity()); + private TabSwitcherNavigationDelegate( + Context context, Runnable backPress, Supplier<Tab> currentTab) { + super(context); + mBackPress = backPress; mCurrentTab = currentTab; } @Override public NavigationHandler.ActionDelegate createActionDelegate() { - return new TabSwitcherActionDelegate(mCurrentTab); + return new TabSwitcherActionDelegate(mBackPress, mCurrentTab); } } /** * Creates {@link HistoryNavigationDelegate} for tab switcher. */ - public static HistoryNavigationDelegate createForTabSwitcher(Supplier<Tab> currentTab) { - return new TabSwitcherNavigationDelegate(currentTab); + public static HistoryNavigationDelegate createForTabSwitcher( + Context context, Runnable backPress, Supplier<Tab> currentTab) { + return new TabSwitcherNavigationDelegate(context, backPress, currentTab); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabSwitcherActionDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabSwitcherActionDelegate.java index afa83d2..a8122e7 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabSwitcherActionDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabSwitcherActionDelegate.java
@@ -5,7 +5,6 @@ package org.chromium.chrome.browser.gesturenav; import org.chromium.base.Supplier; -import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.tab.Tab; /** @@ -15,14 +14,11 @@ */ public class TabSwitcherActionDelegate implements NavigationHandler.ActionDelegate { private final Supplier<Tab> mCurrentTab; - private final ChromeActivity mActivity; + private final Runnable mBackPress; - public TabSwitcherActionDelegate(Supplier<Tab> currentTab) { + public TabSwitcherActionDelegate(Runnable backPress, Supplier<Tab> currentTab) { + mBackPress = backPress; mCurrentTab = currentTab; - - // Cache the activity at the beginning since it may not be reachable - // later when current tab becomes null. - mActivity = currentTab.get().getActivity(); } @Override @@ -33,7 +29,7 @@ @Override public void navigate(boolean forward) { assert !forward : "Should be called only for back navigation"; - mActivity.onBackPressed(); + mBackPress.run(); } @Override
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedActionDelegate.java b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedActionDelegate.java index 803d70a..ad5002a 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedActionDelegate.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/gesturenav/TabbedActionDelegate.java
@@ -4,7 +4,6 @@ package org.chromium.chrome.browser.gesturenav; -import org.chromium.chrome.browser.ChromeActivity; import org.chromium.chrome.browser.tab.Tab; /** @@ -14,11 +13,9 @@ */ public class TabbedActionDelegate implements NavigationHandler.ActionDelegate { private final Tab mTab; - private final ChromeActivity mActivity; public TabbedActionDelegate(Tab tab) { mTab = tab; - mActivity = tab.getActivity(); } @Override @@ -31,7 +28,7 @@ if (forward) { mTab.goForward(); } else { - mActivity.onBackPressed(); + mTab.getActivity().onBackPressed(); } }
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/locationcustomizations/LocationCustomizations.java b/chrome/android/java/src/org/chromium/chrome/browser/locationcustomizations/LocationCustomizations.java deleted file mode 100644 index 86d61bc..0000000 --- a/chrome/android/java/src/org/chromium/chrome/browser/locationcustomizations/LocationCustomizations.java +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright 2019 The Chromium 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.locationcustomizations; - -import org.chromium.chrome.browser.locale.LocaleManager; -import org.chromium.chrome.browser.preferences.Pref; -import org.chromium.chrome.browser.preferences.PrefServiceBridge; - -/** - * Does customizations specified by users locations. - */ -public class LocationCustomizations { - /** - * Initialize location customizations. - */ - public static void initialize() { - if (LocaleManager.getInstance().isSpecialUser()) { - PrefServiceBridge.getInstance().setBoolean(Pref.NTP_ARTICLES_SECTION_ENABLED, false); - } - } -}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/FileTypePolicies.java b/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/FileTypePolicies.java new file mode 100644 index 0000000..6de2d59 --- /dev/null +++ b/chrome/android/java/src/org/chromium/chrome/browser/safe_browsing/FileTypePolicies.java
@@ -0,0 +1,23 @@ +// Copyright 2019 The Chromium 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.safe_browsing; + +import org.chromium.base.annotations.JNINamespace; + +/** + * This class reports UMA values based on files' extensions. + */ +@JNINamespace("safe_browsing") +public final class FileTypePolicies { + /** + * @param path The file path. + * @return The UMA value for the file. + */ + public static int umaValueForFile(String path) { + return nativeUmaValueForFile(path); + } + + private static native int nativeUmaValueForFile(String path); +}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java b/chrome/android/java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java index b3ce122..f3b389e 100644 --- a/chrome/android/java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java +++ b/chrome/android/java/src/org/chromium/chrome/browser/webshare/ShareServiceImpl.java
@@ -18,6 +18,7 @@ import org.chromium.base.task.PostTask; import org.chromium.base.task.TaskRunner; import org.chromium.base.task.TaskTraits; +import org.chromium.chrome.browser.safe_browsing.FileTypePolicies; import org.chromium.chrome.browser.share.ShareHelper; import org.chromium.chrome.browser.share.ShareParams; import org.chromium.content_public.browser.WebContents; @@ -195,6 +196,11 @@ } for (SharedFile file : files) { + RecordHistogram.recordSparseHistogram( + "WebShare.Unverified", FileTypePolicies.umaValueForFile(file.name)); + } + + for (SharedFile file : files) { if (isDangerousFilename(file.name) || isDangerousMimeType(file.blob.contentType)) { callback.call(ShareError.PERMISSION_DENIED); return;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java index 664a26f..b27bfc3 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupTest.java
@@ -48,7 +48,6 @@ import java.util.ArrayList; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; /** @@ -166,7 +165,7 @@ private void loadForm(final String formDataUrl, final String inputText, @Nullable Callback<Activity> updateActivity) - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, TimeoutException { mActivityTestRule.startMainActivityWithURL(formDataUrl); if (updateActivity != null) { updateActivity.onResult(mActivityTestRule.getActivity()); @@ -204,7 +203,7 @@ private void loadAndFillForm(final String formDataUrl, final String inputText, @Nullable Callback<Activity> updateActivity) - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, TimeoutException { loadForm(formDataUrl, inputText, updateActivity); final WebContents webContents = mActivityTestRule.getActivity().getCurrentWebContents(); @@ -224,7 +223,7 @@ } private void loadAndFillForm(final String formDataUrl, final String inputText) - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, TimeoutException { loadAndFillForm(formDataUrl, inputText, null); } @@ -236,8 +235,7 @@ @MediumTest @Feature({"autofill"}) @DisabledTest(message = "Flaky. crbug.com/936183") - public void testClickAutofillPopupSuggestion() - throws InterruptedException, ExecutionException, TimeoutException { + public void testClickAutofillPopupSuggestion() throws InterruptedException, TimeoutException { loadAndFillForm(BASIC_PAGE_DATA, "J"); final WebContents webContents = mActivityTestRule.getActivity().getCurrentWebContents(); @@ -283,8 +281,7 @@ @Test @MediumTest @Feature({"autofill"}) - public void testLoggingInitiatedElementFilled() - throws InterruptedException, ExecutionException, TimeoutException { + public void testLoggingInitiatedElementFilled() throws InterruptedException, TimeoutException { loadAndFillForm(INITIATING_ELEMENT_FILLED, "o"); final String profileFullName = FIRST_NAME + " " + LAST_NAME; final int loggedEntries = 4; @@ -303,8 +300,7 @@ @Test @MediumTest @Feature({"autofill"}) - public void testLoggingAnotherElementFilled() - throws InterruptedException, ExecutionException, TimeoutException { + public void testLoggingAnotherElementFilled() throws InterruptedException, TimeoutException { loadAndFillForm(ANOTHER_ELEMENT_FILLED, "J"); final String profileFullName = FIRST_NAME + " " + LAST_NAME; final int loggedEntries = 3; @@ -322,8 +318,7 @@ @Test @MediumTest @Feature({"autofill"}) - public void testNotLoggingInvalidOption() - throws InterruptedException, ExecutionException, TimeoutException { + public void testNotLoggingInvalidOption() throws InterruptedException, TimeoutException { loadAndFillForm(INVALID_OPTION, "o"); final String profileFullName = FIRST_NAME + " " + LAST_NAME; final int loggedEntries = 3; @@ -339,8 +334,7 @@ @MediumTest @Feature({"autofill"}) @EnableFeatures(ChromeFeatureList.AUTOFILL_REFRESH_STYLE_ANDROID) - public void testScreenOrientationPortrait() - throws InterruptedException, ExecutionException, TimeoutException { + public void testScreenOrientationPortrait() throws InterruptedException, TimeoutException { runTestScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } @@ -348,13 +342,12 @@ @MediumTest @Feature({"autofill"}) @EnableFeatures(ChromeFeatureList.AUTOFILL_REFRESH_STYLE_ANDROID) - public void testScreenOrientationLandscape() - throws InterruptedException, ExecutionException, TimeoutException { + public void testScreenOrientationLandscape() throws InterruptedException, TimeoutException { runTestScreenOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); } private void runTestScreenOrientation(int orientation) - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, TimeoutException { // TODO(crbug.com/905081): Also test different screen sizes. loadForm(BASIC_PAGE_DATA, "J", activity -> activity.setRequestedOrientation(orientation));
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java index 6b50832..2f55f8c 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillPopupWithKeyboardTest.java
@@ -33,7 +33,6 @@ import org.chromium.ui.DropdownPopupWindowInterface; import org.chromium.ui.R; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicReference; @@ -63,7 +62,7 @@ @RetryOnFailure @DisabledTest public void testShowAutofillPopupAndKeyboardimultaneously() - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, TimeoutException { mActivityTestRule.startMainActivityWithURL(UrlUtils.encodeHtmlDataUri("<html><head>" + "<meta name=\"viewport\"" + "content=\"width=device-width, initial-scale=1.0, maximum-scale=1.0\" /></head>" @@ -118,7 +117,7 @@ return viewRef.get().findViewById(R.id.dropdown_popup_window) != null; } }); - Object popupObject = TestThreadUtils.runOnUiThreadBlocking( + Object popupObject = TestThreadUtils.runOnUiThreadBlockingNoException( () -> viewRef.get().findViewById(R.id.dropdown_popup_window).getTag()); Assert.assertTrue(popupObject instanceof DropdownPopupWindowInterface); final DropdownPopupWindowInterface popup = (DropdownPopupWindowInterface) popupObject;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java index b4376d0..749dece 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/AutofillTestHelper.java
@@ -10,7 +10,6 @@ import org.chromium.content_public.browser.test.util.TestThreadUtils; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; /** @@ -36,34 +35,33 @@ () -> PersonalDataManager.getInstance().setSyncServiceForTesting()); } - AutofillProfile getProfile(final String guid) throws ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + AutofillProfile getProfile(final String guid) { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getProfile(guid)); } - List<AutofillProfile> getProfilesToSuggest(final boolean includeNameInLabel) throws - ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + List<AutofillProfile> getProfilesToSuggest(final boolean includeNameInLabel) { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getProfilesToSuggest(includeNameInLabel)); } - List<AutofillProfile> getProfilesForSettings() throws ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + List<AutofillProfile> getProfilesForSettings() { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getProfilesForSettings()); } - int getNumberOfProfilesToSuggest() throws ExecutionException { + int getNumberOfProfilesToSuggest() { return getProfilesToSuggest(false).size(); } - int getNumberOfProfilesForSettings() throws ExecutionException { + int getNumberOfProfilesForSettings() { return getProfilesForSettings().size(); } - public String setProfile(final AutofillProfile profile) throws InterruptedException, - ExecutionException, TimeoutException { + public String setProfile(final AutofillProfile profile) + throws InterruptedException, TimeoutException { int callCount = mOnPersonalDataChangedHelper.getCallCount(); - String guid = TestThreadUtils.runOnUiThreadBlocking( + String guid = TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().setProfile(profile)); mOnPersonalDataChangedHelper.waitForCallback(callCount); return guid; @@ -76,42 +74,42 @@ mOnPersonalDataChangedHelper.waitForCallback(callCount); } - public CreditCard getCreditCard(final String guid) throws ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + public CreditCard getCreditCard(final String guid) { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getCreditCard(guid)); } - List<CreditCard> getCreditCardsToSuggest() throws ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + List<CreditCard> getCreditCardsToSuggest() { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getCreditCardsToSuggest( /*includeServerCards=*/true)); } - List<CreditCard> getCreditCardsForSettings() throws ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + List<CreditCard> getCreditCardsForSettings() { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getCreditCardsForSettings()); } - int getNumberOfCreditCardsToSuggest() throws ExecutionException { + int getNumberOfCreditCardsToSuggest() { return getCreditCardsToSuggest().size(); } - int getNumberOfCreditCardsForSettings() throws ExecutionException { + int getNumberOfCreditCardsForSettings() { return getCreditCardsForSettings().size(); } - public String setCreditCard(final CreditCard card) throws InterruptedException, - ExecutionException, TimeoutException { + public String setCreditCard(final CreditCard card) + throws InterruptedException, TimeoutException { int callCount = mOnPersonalDataChangedHelper.getCallCount(); - String guid = TestThreadUtils.runOnUiThreadBlocking( + String guid = TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().setCreditCard(card)); mOnPersonalDataChangedHelper.waitForCallback(callCount); return guid; } public void addServerCreditCard(final CreditCard card) - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, TimeoutException { int callCount = mOnPersonalDataChangedHelper.getCallCount(); TestThreadUtils.runOnUiThreadBlocking( () -> PersonalDataManager.getInstance().addServerCreditCardForTest(card)); @@ -165,9 +163,8 @@ * @param guid The GUID of the profile to query. * @return The non-negative use count of the profile. */ - public int getProfileUseCountForTesting(final String guid) throws InterruptedException, - ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + public int getProfileUseCountForTesting(final String guid) throws InterruptedException { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getProfileUseCountForTesting(guid)); } @@ -179,9 +176,8 @@ * absolute point in coordinated universal time (UTC) represented as microseconds since * the Windows epoch. For more details see the comment header in time.h. */ - public long getProfileUseDateForTesting(final String guid) throws InterruptedException, - ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + public long getProfileUseDateForTesting(final String guid) throws InterruptedException { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getProfileUseDateForTesting(guid)); } @@ -226,9 +222,8 @@ * @param guid The GUID of the credit card to query. * @return The non-negative use count of the credit card. */ - public int getCreditCardUseCountForTesting(final String guid) throws InterruptedException, - ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + public int getCreditCardUseCountForTesting(final String guid) throws InterruptedException { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getCreditCardUseCountForTesting(guid)); } @@ -240,9 +235,8 @@ * an absolute point in coordinated universal time (UTC) represented as microseconds * since the Windows epoch. For more details see the comment header in time.h. */ - public long getCreditCardUseDateForTesting(final String guid) throws InterruptedException, - ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + public long getCreditCardUseDateForTesting(final String guid) throws InterruptedException { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getCreditCardUseDateForTesting(guid)); } @@ -253,20 +247,21 @@ * coordinated universal time (UTC) represented as microseconds since the Windows epoch. * For more details see the comment header in time.h. */ - public long getCurrentDateForTesting() throws InterruptedException, ExecutionException { - return TestThreadUtils.runOnUiThreadBlocking( + public long getCurrentDateForTesting() throws InterruptedException { + return TestThreadUtils.runOnUiThreadBlockingNoException( () -> PersonalDataManager.getInstance().getCurrentDateForTesting()); } private void registerDataObserver() { try { int callCount = mOnPersonalDataChangedHelper.getCallCount(); - boolean isDataLoaded = TestThreadUtils.runOnUiThreadBlocking( - () -> PersonalDataManager.getInstance().registerDataObserver( - () -> mOnPersonalDataChangedHelper.notifyCalled())); + boolean isDataLoaded = TestThreadUtils.runOnUiThreadBlockingNoException( + () + -> PersonalDataManager.getInstance().registerDataObserver( + () -> mOnPersonalDataChangedHelper.notifyCalled())); if (isDataLoaded) return; mOnPersonalDataChangedHelper.waitForCallback(callCount); - } catch (TimeoutException | InterruptedException | ExecutionException e) { + } catch (TimeoutException | InterruptedException e) { throw new AssertionError(e); } }
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java index 4492f352..0d309d4 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/autofill/PersonalDataManagerTest.java
@@ -23,7 +23,6 @@ import java.util.LinkedList; import java.util.List; -import java.util.concurrent.ExecutionException; import java.util.concurrent.TimeoutException; /** @@ -52,8 +51,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testAddAndEditProfiles() - throws InterruptedException, ExecutionException, TimeoutException { + public void testAddAndEditProfiles() throws InterruptedException, TimeoutException { AutofillProfile profile = new AutofillProfile("" /* guid */, "" /* origin */, "John Smith", "Acme Inc.", "1 Main\nApt A", "CA", "San Francisco", "", "94102", "", "US", "4158889999", "john@acme.inc", ""); @@ -84,8 +82,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testUpdateLanguageCodeInProfile() - throws InterruptedException, ExecutionException, TimeoutException { + public void testUpdateLanguageCodeInProfile() throws InterruptedException, TimeoutException { AutofillProfile profile = new AutofillProfile("" /* guid */, "" /* origin */, "John Smith", "Acme Inc.", "1 Main\nApt A", "CA", "San Francisco", "", "94102", "", "US", "4158889999", "john@acme.inc", "fr"); @@ -114,8 +111,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testAddAndDeleteProfile() - throws InterruptedException, ExecutionException, TimeoutException { + public void testAddAndDeleteProfile() throws InterruptedException, TimeoutException { String profileOneGUID = mHelper.setProfile(createTestProfile()); Assert.assertEquals(1, mHelper.getNumberOfProfilesForSettings()); @@ -127,8 +123,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testAddAndEditCreditCards() - throws InterruptedException, ExecutionException, TimeoutException { + public void testAddAndEditCreditCards() throws InterruptedException, TimeoutException { CreditCard card = new CreditCard( "" /* guid */, "" /* origin */, "Visa", "1234123412341234", "", "5", "2020"); String cardOneGUID = mHelper.setCreditCard(card); @@ -166,8 +161,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testAddAndDeleteCreditCard() - throws InterruptedException, ExecutionException, TimeoutException { + public void testAddAndDeleteCreditCard() throws InterruptedException, TimeoutException { CreditCard card = new CreditCard( "" /* guid */, "Chrome settings" /* origin */, "Visa", "1234123412341234", "", "5", "2020"); @@ -181,8 +175,7 @@ @Test @SmallTest @Feature({"Autofill"}) - public void testRespectCountryCodes() - throws InterruptedException, ExecutionException, TimeoutException { + public void testRespectCountryCodes() throws InterruptedException, TimeoutException { // The constructor should accept country names and ISO 3166-1-alpha-2 country codes. // getCountryCode() should return a country code. AutofillProfile profile1 = new AutofillProfile("" /* guid */, "" /* origin */, "John Smith", @@ -208,8 +201,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testMultilineStreetAddress() - throws InterruptedException, ExecutionException, TimeoutException { + public void testMultilineStreetAddress() throws InterruptedException, TimeoutException { final String streetAddress1 = "Chez Mireille COPEAU Appartment. 2\n" + "Entree A Batiment Jonquille\n" + "25 RUE DE L'EGLISE"; @@ -244,7 +236,7 @@ @Test @SmallTest @Feature({"Autofill"}) - public void testLabels() throws InterruptedException, ExecutionException, TimeoutException { + public void testLabels() throws InterruptedException, TimeoutException { AutofillProfile profile1 = new AutofillProfile("" /* guid */, "" /* origin */, "John Major", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", "555 123-4567", "jm@example.com", ""); @@ -284,8 +276,7 @@ @Test @SmallTest @Feature({"Autofill"}) - public void testProfilesFrecency() - throws InterruptedException, ExecutionException, TimeoutException { + public void testProfilesFrecency() throws InterruptedException, TimeoutException { // Create 3 profiles. AutofillProfile profile1 = new AutofillProfile("" /* guid */, "" /* origin */, "John Major", "Acme Inc.", "123 Main", "California", "Los Angeles", "", "90210", "", "US", @@ -325,8 +316,7 @@ @Test @SmallTest @Feature({"Autofill"}) - public void testCreditCardsFrecency() - throws InterruptedException, ExecutionException, TimeoutException { + public void testCreditCardsFrecency() throws InterruptedException, TimeoutException { // Create 3 credit cards. CreditCard card1 = new CreditCard( "" /* guid */, "" /* origin */, "Visa", "1234123412341234", "", "5", "2020"); @@ -362,8 +352,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testCreditCardsDeduping() - throws InterruptedException, ExecutionException, TimeoutException { + public void testCreditCardsDeduping() throws InterruptedException, TimeoutException { // Create a local card and an identical server card. CreditCard card1 = new CreditCard("" /* guid */, "" /* origin */, true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5", "2020", "Visa", @@ -390,7 +379,7 @@ @Feature({"Autofill"}) @RetryOnFailure public void testProfileUseStatsSettingAndGetting() - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, TimeoutException { String guid = mHelper.setProfile(createTestProfile()); // Make sure the profile does not have the specific use stats form the start. @@ -410,7 +399,7 @@ @Feature({"Autofill"}) @RetryOnFailure public void testCreditCardUseStatsSettingAndGetting() - throws InterruptedException, ExecutionException, TimeoutException { + throws InterruptedException, TimeoutException { String guid = mHelper.setCreditCard(new CreditCard("" /* guid */, "" /* origin */, true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5", "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN, @@ -432,8 +421,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testRecordAndLogProfileUse() - throws InterruptedException, ExecutionException, TimeoutException { + public void testRecordAndLogProfileUse() throws InterruptedException, TimeoutException { String guid = mHelper.setProfile(createTestProfile()); // Set specific use stats for the profile. @@ -458,8 +446,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testRecordAndLogCreditCardUse() - throws InterruptedException, ExecutionException, TimeoutException { + public void testRecordAndLogCreditCardUse() throws InterruptedException, TimeoutException { String guid = mHelper.setCreditCard(new CreditCard("" /* guid */, "" /* origin */, true /* isLocal */, false /* isCached */, "John Doe", "1234123412341234", "", "5", "2020", "Visa", 0 /* issuerIconDrawableId */, CardType.UNKNOWN, @@ -487,8 +474,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testGetProfilesToSuggest_NoName() - throws InterruptedException, ExecutionException, TimeoutException { + public void testGetProfilesToSuggest_NoName() throws InterruptedException, TimeoutException { mHelper.setProfile(createTestProfile()); List<AutofillProfile> profiles = @@ -501,8 +487,7 @@ @SmallTest @Feature({"Autofill"}) @RetryOnFailure - public void testGetProfilesToSuggest_WithName() - throws InterruptedException, ExecutionException, TimeoutException { + public void testGetProfilesToSuggest_WithName() throws InterruptedException, TimeoutException { mHelper.setProfile(createTestProfile()); List<AutofillProfile> profiles =
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java index e8d2ab3..604a5119 100644 --- a/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java +++ b/chrome/android/javatests/src/org/chromium/chrome/browser/contextualsearch/ContextualSearchTapEventTest.java
@@ -15,7 +15,6 @@ import org.junit.runner.RunWith; import org.chromium.base.test.util.CommandLineFlags; -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.browser.ChromeActivity; @@ -321,7 +320,6 @@ @SmallTest @Feature({"ContextualSearch"}) @Restriction(Restriction.RESTRICTION_TYPE_NON_LOW_END_DEVICE) - @DisabledTest(message = "See https://crbug.com/959040") public void testTapProcessIsRobustWhenSelectionGetsClearedDLD() throws InterruptedException { Assert.assertEquals(mPanelManager.getRequestPanelShowCount(), 0);
diff --git a/chrome/browser/android/vr/gvr_input_delegate.cc b/chrome/browser/android/vr/gvr_input_delegate.cc index 70a52af..e27e817 100644 --- a/chrome/browser/android/vr/gvr_input_delegate.cc +++ b/chrome/browser/android/vr/gvr_input_delegate.cc
@@ -42,7 +42,7 @@ // TODO(https://crbug.com/942201): Get correct ID string once WebXR spec issue // #550 (https://github.com/immersive-web/webxr/issues/550) is resolved. - CopyToUString(base::UTF8ToUTF16("unknown"), gamepad.id, + CopyToUString(base::UTF8ToUTF16("daydream-controller"), gamepad.id, base::size(gamepad.id)); gamepad.hand = data.right_handed ? device::GamepadHand::kRight
diff --git a/chrome/browser/apps/app_service/arc_apps.cc b/chrome/browser/apps/app_service/arc_apps.cc index 6837e965..e6a4924f 100644 --- a/chrome/browser/apps/app_service/arc_apps.cc +++ b/chrome/browser/apps/app_service/arc_apps.cc
@@ -500,7 +500,9 @@ app->app_type = apps::mojom::AppType::kArc; app->app_id = app_id; - app->readiness = apps::mojom::Readiness::kReady; + app->readiness = app_info.suspended + ? apps::mojom::Readiness::kDisabledByPolicy + : apps::mojom::Readiness::kReady; app->name = app_info.name; app->short_name = app->name;
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn index 1c7d7ea..0d99794 100644 --- a/chrome/browser/chromeos/BUILD.gn +++ b/chrome/browser/chromeos/BUILD.gn
@@ -1264,7 +1264,6 @@ "login/screens/assistant_optin_flow_screen.h", "login/screens/base_screen.cc", "login/screens/base_screen.h", - "login/screens/base_screen_delegate.h", "login/screens/chrome_user_selection_screen.cc", "login/screens/chrome_user_selection_screen.h", "login/screens/demo_preferences_screen.cc", @@ -1651,6 +1650,8 @@ "policy/remote_commands/device_command_fetch_status_job.h", "policy/remote_commands/device_command_reboot_job.cc", "policy/remote_commands/device_command_reboot_job.h", + "policy/remote_commands/device_command_refresh_machine_certificate_job.cc", + "policy/remote_commands/device_command_refresh_machine_certificate_job.h", "policy/remote_commands/device_command_screenshot_job.cc", "policy/remote_commands/device_command_screenshot_job.h", "policy/remote_commands/device_command_set_volume_job.cc", @@ -2171,14 +2172,10 @@ "login/enrollment/mock_enrollment_screen.h", "login/mock_network_state_helper.cc", "login/mock_network_state_helper.h", - "login/screens/mock_base_screen_delegate.cc", - "login/screens/mock_base_screen_delegate.h", "login/screens/mock_error_screen.cc", "login/screens/mock_error_screen.h", "login/screens/mock_network_screen.cc", "login/screens/mock_network_screen.h", - "login/screens/mock_supervision_transition_screen.cc", - "login/screens/mock_supervision_transition_screen.h", "login/screens/mock_update_screen.cc", "login/screens/mock_update_screen.h", "login/screens/mock_welcome_screen.cc",
diff --git a/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc b/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc index 968c595..711c4f2 100644 --- a/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc +++ b/chrome/browser/chromeos/extensions/file_manager/device_event_router.cc
@@ -76,7 +76,7 @@ if (is_resuming_ || is_starting_up_) return; - const std::string& device_path = disk.system_path_prefix(); + const std::string& device_path = disk.storage_device_path(); if (!disk.is_read_only() && disk.is_mounted() && GetDeviceState(device_path) != DEVICE_HARD_UNPLUGGED_AND_REPORTED) { OnDeviceEvent(file_manager_private::DEVICE_EVENT_TYPE_HARD_UNPLUGGED, @@ -89,7 +89,7 @@ const Volume& volume) { DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - const std::string& device_path = volume.system_path_prefix().AsUTF8Unsafe(); + const std::string& device_path = volume.storage_device_path().AsUTF8Unsafe(); SetDeviceState(device_path, DEVICE_STATE_USUAL); }
diff --git a/chrome/browser/chromeos/extensions/file_manager/device_event_router_unittest.cc b/chrome/browser/chromeos/extensions/file_manager/device_event_router_unittest.cc index 6840024..8b9fea9 100644 --- a/chrome/browser/chromeos/extensions/file_manager/device_event_router_unittest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/device_event_router_unittest.cc
@@ -76,7 +76,7 @@ return *Disk::Builder() .SetDevicePath(device_path) .SetMountPath(mount_path) - .SetSystemPathPrefix(device_path) + .SetStorageDevicePath(device_path) .SetIsReadOnlyHardware(is_read_only_hardware) .SetFileSystemType("vfat") .SetIsMounted(is_mounted)
diff --git a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc index 8aab51e..d031c82 100644 --- a/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc +++ b/chrome/browser/chromeos/extensions/file_manager/file_manager_private_apitest.cc
@@ -62,7 +62,7 @@ const char* product_id; const char* product_name; const char* fs_uuid; - const char* system_path_prefix; + const char* storage_device_path; chromeos::DeviceType device_type; uint64_t size_in_bytes; bool is_parent; @@ -95,7 +95,7 @@ "abcd", "product1", "FFFF-FFFF", - "system_path_prefix1", + "storage_device_path1", chromeos::DEVICE_TYPE_USB, 1073741824, false, @@ -116,7 +116,7 @@ "cdef", "product2", "0FFF-FFFF", - "system_path_prefix2", + "storage_device_path2", chromeos::DEVICE_TYPE_MOBILE, 47723, true, @@ -137,7 +137,7 @@ "ef01", "product3", "00FF-FFFF", - "system_path_prefix3", + "storage_device_path3", chromeos::DEVICE_TYPE_OPTICAL_DISC, 0, true, @@ -303,8 +303,8 @@ .SetProductId(kTestDisks[disk_info_index].product_id) .SetProductName(kTestDisks[disk_info_index].product_name) .SetFileSystemUUID(kTestDisks[disk_info_index].fs_uuid) - .SetSystemPathPrefix( - kTestDisks[disk_info_index].system_path_prefix) + .SetStorageDevicePath( + kTestDisks[disk_info_index].storage_device_path) .SetDeviceType(kTestDisks[disk_info_index].device_type) .SetSizeInBytes(kTestDisks[disk_info_index].size_in_bytes) .SetIsParent(kTestDisks[disk_info_index].is_parent)
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc index b0ae8a1..1c4b7950 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.cc
@@ -750,12 +750,18 @@ base::BindOnce(&GetFileMetadataRespondOnUIThread, std::move(callback))); } -// Gets the available space of the |path|. -int64_t GetLocalDiskSpace(const base::FilePath& path) { - if (!base::PathExists(path)) { - return std::numeric_limits<int64_t>::min(); +// Gets the available space of the |paths|, stopping on the first path that +// doesn't exist. +std::vector<int64_t> GetLocalDiskSpaces( + const std::vector<base::FilePath>& paths) { + std::vector<int64_t> result; + for (const auto& path : paths) { + if (!base::PathExists(path)) { + break; + } + result.push_back(base::SysInfo::AmountOfFreeDiskSpace(path)); } - return base::SysInfo::AmountOfFreeDiskSpace(path); + return result; } } // namespace @@ -820,21 +826,22 @@ return; } - base::FilePath destination_dir; - if (destination_url_.filesystem_id() == - drive::util::GetDriveMountPointPath(chrome_details_.GetProfile()) - .BaseName() - .value()) { - // Google Drive's cache is limited by the available space on the local disk. - destination_dir = file_manager::util::GetMyFilesFolderForProfile( - chrome_details_.GetProfile()); - } else { - destination_dir = destination_url_.path().DirName(); + auto* drive_integration_service = + drive::util::GetIntegrationServiceByProfile(chrome_details_.GetProfile()); + std::vector<base::FilePath> destination_dirs; + if (drive_integration_service && + drive_integration_service->GetMountPointPath().IsParent( + destination_url_.path())) { + // Google Drive's cache is limited by the available space on the local disk + // as well as the cloud storage. + destination_dirs.push_back(file_manager::util::GetMyFilesFolderForProfile( + chrome_details_.GetProfile())); } + destination_dirs.push_back(destination_url_.path().DirName()); base::PostTaskWithTraitsAndReplyWithResult( FROM_HERE, {base::MayBlock()}, - base::BindOnce(&GetLocalDiskSpace, destination_dir), + base::BindOnce(&GetLocalDiskSpaces, std::move(destination_dirs)), base::BindOnce( &FileManagerPrivateInternalStartCopyFunction::RunAfterCheckDiskSpace, this, file_info.size)); @@ -842,40 +849,51 @@ void FileManagerPrivateInternalStartCopyFunction::RunAfterCheckDiskSpace( int64_t space_needed, - int64_t space_available) { - if (space_available < 0) { + const std::vector<int64_t>& spaces_available) { + auto* drive_integration_service = + drive::util::GetIntegrationServiceByProfile(chrome_details_.GetProfile()); + if (spaces_available.empty()) { // It might be a virtual path. In this case we just assume that it has // enough space. RunAfterFreeDiskSpace(true); - } else if (destination_url_.filesystem_id() == - file_manager::util::GetDownloadsMountPointName( - chrome_details_.GetProfile()) || - destination_url_.filesystem_id() == - drive::util::GetDriveMountPointPath( - chrome_details_.GetProfile()) - .BaseName() - .value()) { - // If the destination directory is local hard drive or Google Drive we - // must leave some additional space to make sure we don't break the system. - if (space_available - cryptohome::kMinFreeSpaceInBytes > space_needed) { - RunAfterFreeDiskSpace(true); - } else { - // Also we can try to secure needed space by freeing Drive caches. - drive::FileSystemInterface* const drive_file_system = - drive::util::GetFileSystemByProfile(chrome_details_.GetProfile()); - if (!drive_file_system) { - RunAfterFreeDiskSpace(false); - } else { - drive_file_system->FreeDiskSpaceIfNeededFor( - space_needed, - base::Bind(&FileManagerPrivateInternalStartCopyFunction:: - RunAfterFreeDiskSpace, - this)); - } - } - } else { - RunAfterFreeDiskSpace(space_available > space_needed); + return; } + // If the target is not internal storage or Drive, succeed if sufficient space + // is available. + if (destination_url_.filesystem_id() != + file_manager::util::GetDownloadsMountPointName( + chrome_details_.GetProfile()) && + !(drive_integration_service && + drive_integration_service->GetMountPointPath().IsParent( + destination_url_.path()))) { + RunAfterFreeDiskSpace(spaces_available[0] > space_needed); + return; + } + + // If there isn't enough cloud space, fail. + if (spaces_available.size() > 1 && spaces_available[1] < space_needed) { + RunAfterFreeDiskSpace(false); + return; + } + + // If the destination directory is local hard drive or Google Drive we + // must leave some additional space to make sure we don't break the system. + if (spaces_available[0] - cryptohome::kMinFreeSpaceInBytes > space_needed) { + RunAfterFreeDiskSpace(true); + return; + } + // Also we can try to secure needed space by freeing Drive caches. + drive::FileSystemInterface* const drive_file_system = + drive::util::GetFileSystemByProfile(chrome_details_.GetProfile()); + if (!drive_file_system) { + RunAfterFreeDiskSpace(false); + return; + } + drive_file_system->FreeDiskSpaceIfNeededFor( + space_needed, + base::Bind( + &FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace, + this)); } void FileManagerPrivateInternalStartCopyFunction::RunAfterFreeDiskSpace(
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h index 570d7b96ad..205df85 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_file_system.h
@@ -260,7 +260,8 @@ // Part of RunAsync(). Called after the amount of space on the destination // is known. - void RunAfterCheckDiskSpace(int64_t space_needed, int64_t space_available); + void RunAfterCheckDiskSpace(int64_t space_needed, + const std::vector<int64_t>& spaces_available); // Part of RunAsync(). Called after FreeDiskSpaceIfNeededFor() is completed on // IO thread.
diff --git a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc index d67bbc2e..a614e6bc 100644 --- a/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc +++ b/chrome/browser/chromeos/extensions/file_manager/private_api_util.cc
@@ -362,7 +362,7 @@ break; } volume_metadata->device_path = std::make_unique<std::string>( - volume.system_path_prefix().AsUTF8Unsafe()); + volume.storage_device_path().AsUTF8Unsafe()); volume_metadata->is_parent_device = std::make_unique<bool>(volume.is_parent()); } else {
diff --git a/chrome/browser/chromeos/file_manager/file_tasks.cc b/chrome/browser/chromeos/file_manager/file_tasks.cc index 0cc78d3f..d338f7b 100644 --- a/chrome/browser/chromeos/file_manager/file_tasks.cc +++ b/chrome/browser/chromeos/file_manager/file_tasks.cc
@@ -7,14 +7,17 @@ #include <stddef.h> #include <map> +#include <string> #include <utility> #include "apps/launcher.h" #include "base/bind.h" +#include "base/feature_list.h" #include "base/metrics/histogram_macros.h" #include "base/stl_util.h" #include "base/strings/string_split.h" #include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" #include "chrome/browser/chromeos/crostini/crostini_util.h" #include "chrome/browser/chromeos/drive/file_system_util.h" #include "chrome/browser/chromeos/file_manager/app_id.h" @@ -27,7 +30,9 @@ #include "chrome/browser/chromeos/file_manager/open_with_browser.h" #include "chrome/browser/chromeos/fileapi/file_system_backend.h" #include "chrome/browser/extensions/extension_tab_util.h" +#include "chrome/browser/extensions/launch_util.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/extensions/app_launch_params.h" #include "chrome/browser/ui/extensions/application_launch.h" #include "chrome/browser/ui/webui/extensions/extension_icon_source.h" #include "chrome/common/extensions/api/file_browser_handlers/file_browser_handler.h" @@ -41,13 +46,16 @@ #include "extensions/browser/api/file_handlers/mime_util.h" #include "extensions/browser/entry_info.h" #include "extensions/browser/extension_host.h" +#include "extensions/browser/extension_prefs.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" #include "extensions/browser/extension_util.h" #include "extensions/common/constants.h" #include "extensions/common/extension_set.h" #include "storage/browser/fileapi/file_system_url.h" +#include "third_party/blink/public/common/features.h" #include "third_party/blink/public/common/mime_util/mime_util.h" +#include "ui/base/window_open_disposition.h" using extensions::Extension; using extensions::api::file_manager_private::Verb; @@ -410,8 +418,22 @@ std::vector<base::FilePath> paths; for (size_t i = 0; i != file_urls.size(); ++i) paths.push_back(file_urls[i].path()); - apps::LaunchPlatformAppWithFileHandler(extension_task_profile, extension, - task.action_id, paths); + + if (!extension->from_bookmark()) { + apps::LaunchPlatformAppWithFileHandler(extension_task_profile, extension, + task.action_id, paths); + } else { + extensions::LaunchContainer launch_container = + extensions::GetLaunchContainer( + extensions::ExtensionPrefs::Get(extension_task_profile), + extension); + AppLaunchParams params(extension_task_profile, extension, + launch_container, + WindowOpenDisposition::NEW_FOREGROUND_TAB, + extensions::AppLaunchSource::SOURCE_FILE_HANDLER); + params.override_url = GURL(task.action_id); + OpenApplication(params); + } if (!done.is_null()) std::move(done).Run( extensions::api::file_manager_private::TASK_RESULT_MESSAGE_SENT); @@ -461,10 +483,18 @@ ++iter) { const Extension* extension = iter->get(); - // Check that the extension can be launched via an event. This includes all - // platform apps plus whitelisted extensions. - if (!CanLaunchViaEvent(extension)) + bool is_bookmark_app = + extension->from_bookmark() && + extension->GetType() == extensions::Manifest::TYPE_HOSTED_APP; + // Check that the extension can be launched with files. This includes all + // platform apps plus whitelisted extensions, and bookmark apps, if + // file handling is enabled. + if (!CanLaunchViaEvent(extension) && + (!is_bookmark_app || + !base::FeatureList::IsEnabled(blink::features::kNativeFileSystemAPI) || + !base::FeatureList::IsEnabled(blink::features::kFileHandlingAPI))) { continue; + } if (profile->IsOffTheRecord() && !extensions::util::IsIncognitoEnabled(extension->id(), profile))
diff --git a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc index 5c92448..259f967 100644 --- a/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc +++ b/chrome/browser/chromeos/file_manager/file_tasks_unittest.cc
@@ -34,8 +34,10 @@ #include "extensions/browser/extension_system.h" #include "extensions/common/constants.h" #include "extensions/common/extension_builder.h" +#include "extensions/common/manifest.h" #include "google_apis/drive/drive_api_parser.h" #include "testing/gtest/include/gtest/gtest.h" +#include "third_party/blink/public/common/features.h" #include "url/gurl.h" using extensions::api::file_manager_private::Verb; @@ -530,6 +532,81 @@ ASSERT_TRUE(tasks.empty()); } +TEST_F(FileManagerFileTasksComplexTest, WebAppsCanHandleFiles) { + const char kGraphrId[] = "ppcpljkgngnngojbghcdiojhbneibgdg"; + const char kGraphrFileAction[] = "https://graphr.tld/open-files/?name=raw"; + extensions::ExtensionBuilder graphr; + graphr.SetManifest( + extensions::DictionaryBuilder() + .Set("name", "Graphr") + .Set("version", "1.0.0") + .Set("manifest_version", 2) + .Set("app", + extensions::DictionaryBuilder() + .Set("launch", extensions::DictionaryBuilder() + .Set("web_url", "https://graphr.tld") + .Build()) + .Build()) + .Set( + "file_handlers", + extensions::DictionaryBuilder() + .Set(kGraphrFileAction, + extensions::DictionaryBuilder() + .Set("title", "Raw") + .Set("types", extensions::ListBuilder() + .Append("text/csv") + .Build()) + .Set("extensions", + extensions::ListBuilder().Append("csv").Build()) + .Build()) + .Build()) + .Build()); + graphr.SetID(kGraphrId); + graphr.AddFlags(extensions::Extension::InitFromValueFlags::FROM_BOOKMARK); + + extension_service_->AddExtension(graphr.Build().get()); + const extensions::Extension* extension = + extension_service_->GetExtensionById(kGraphrId, false); + + ASSERT_EQ(extension->GetType(), extensions::Manifest::Type::TYPE_HOSTED_APP); + ASSERT_TRUE(extension->from_bookmark()); + + std::vector<FullTaskDescriptor> tasks; + std::vector<extensions::EntryInfo> entries; + entries.emplace_back(drive::util::GetDriveMountPointPath(&test_profile_) + .AppendASCII("foo.csv"), + "text/csv", false); + + { + // Bookmark Apps should not be able to handle files unless + // kNativeFileSystemAPI and kFileHandlingAPI are enabled. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures({}, + {blink::features::kNativeFileSystemAPI, + blink::features::kFileHandlingAPI}); + FindFileHandlerTasks(&test_profile_, entries, &tasks); + EXPECT_EQ(0u, tasks.size()); + tasks.clear(); + } + + { + // When the flags are enabled, it should be possible to handle files from + // bookmark apps. + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitWithFeatures({blink::features::kNativeFileSystemAPI, + blink::features::kFileHandlingAPI}, + {}); + // Test that when enabled, bookmark apps can handle files + FindFileHandlerTasks(&test_profile_, entries, &tasks); + // Graphr should be a valid handler. + ASSERT_EQ(1u, tasks.size()); + EXPECT_EQ(kGraphrId, tasks[0].task_descriptor().app_id); + EXPECT_EQ(kGraphrFileAction, tasks[0].task_descriptor().action_id); + EXPECT_EQ(file_tasks::TaskType::TASK_TYPE_FILE_HANDLER, + tasks[0].task_descriptor().task_type); + } +} + // The basic logic is similar to a test case for FindFileHandlerTasks above. TEST_F(FileManagerFileTasksComplexTest, FindFileBrowserHandlerTasks) { // Copied from FindFileHandlerTasks test above.
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.cc b/chrome/browser/chromeos/file_manager/volume_manager.cc index 9fd75da..c1ab69c2 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.cc +++ b/chrome/browser/chromeos/file_manager/volume_manager.cc
@@ -283,7 +283,7 @@ volume->file_system_type_ = disk->file_system_type(); volume->volume_label_ = disk->device_label(); volume->device_type_ = disk->device_type(); - volume->system_path_prefix_ = base::FilePath(disk->system_path_prefix()); + volume->storage_device_path_ = base::FilePath(disk->storage_device_path()); volume->is_parent_ = disk->is_parent(); volume->is_read_only_ = disk->is_read_only(); volume->is_read_only_removable_device_ = disk->is_read_only_hardware(); @@ -449,7 +449,7 @@ // Keep source_path empty. volume->source_ = SOURCE_DEVICE; volume->mount_path_ = path; - volume->system_path_prefix_ = device_path; + volume->storage_device_path_ = device_path; volume->mount_condition_ = chromeos::disks::MOUNT_CONDITION_NONE; volume->is_read_only_ = read_only; volume->volume_id_ = GenerateVolumeId(*volume); @@ -465,7 +465,7 @@ const base::FilePath& device_path, const base::FilePath& mount_path) { std::unique_ptr<Volume> volume(new Volume()); - volume->system_path_prefix_ = device_path; + volume->storage_device_path_ = device_path; volume->mount_path_ = mount_path; return volume; }
diff --git a/chrome/browser/chromeos/file_manager/volume_manager.h b/chrome/browser/chromeos/file_manager/volume_manager.h index 6ced669..3588c1a5 100644 --- a/chrome/browser/chromeos/file_manager/volume_manager.h +++ b/chrome/browser/chromeos/file_manager/volume_manager.h
@@ -147,8 +147,8 @@ return mount_condition_; } MountContext mount_context() const { return mount_context_; } - const base::FilePath& system_path_prefix() const { - return system_path_prefix_; + const base::FilePath& storage_device_path() const { + return storage_device_path_; } const std::string& volume_label() const { return volume_label_; } bool is_parent() const { return is_parent_; } @@ -215,9 +215,9 @@ // interaction or not. MountContext mount_context_; - // Path of the system device this device's block is a part of. + // Path of the storage device this device's block is a part of. // (e.g. /sys/devices/pci0000:00/.../8:0:0:0/) - base::FilePath system_path_prefix_; + base::FilePath storage_device_path_; // Label for the volume if the volume is either removable or a provided // file system. In case of removables, if disk is a parent, then its label,
diff --git a/chrome/browser/chromeos/login/enable_debugging_browsertest.cc b/chrome/browser/chromeos/login/enable_debugging_browsertest.cc index 98187c4..6b80b7c0 100644 --- a/chrome/browser/chromeos/login/enable_debugging_browsertest.cc +++ b/chrome/browser/chromeos/login/enable_debugging_browsertest.cc
@@ -232,6 +232,8 @@ test::OobeJS().ExpectHidden("debugging"); InvokeEnableDebuggingScreen(); test::OobeJS().ExpectVisible("debugging"); + test::OobeJS().ExpectVisible({"debugging-remove-protection-button"}); + test::OobeJS().ExpectVisible({"enable-debugging-help-link"}); debug_daemon_client_->WaitUntilCalled(); base::RunLoop().RunUntilIdle(); VerifyRemoveProtectionScreen(); @@ -257,6 +259,12 @@ test::OobeJS().ExpectHasClass("setup-view", {"debugging"}); test::OobeJS().ExpectHasNoClass("done-view", {"debugging"}); test::OobeJS().ExpectHasNoClass("wait-view", {"debugging"}); + + test::OobeJS().ExpectVisible("enable-debugging-passwords"); + test::OobeJS().ExpectVisible("enable-debugging-password"); + test::OobeJS().ExpectVisible("enable-debugging-password2"); + test::OobeJS().ExpectVisible("enable-debugging-setup-details"); + test::OobeJS().ExpectVisible("enable-debugging-password-note"); } TestDebugDaemonClient* debug_daemon_client_ = nullptr; @@ -298,8 +306,45 @@ debug_daemon_client_->ResetWait(); ClickEnableButton(); debug_daemon_client_->WaitUntilCalled(); - base::RunLoop().RunUntilIdle(); - test::OobeJS().ExpectHasClass("done-view", {"debugging"}); + test::OobeJS().CreateHasClassWaiter(true, "done-view", {"debugging"}); + EXPECT_EQ(debug_daemon_client_->num_enable_debugging_features(), 1); + EXPECT_EQ(debug_daemon_client_->num_remove_protection(), 0); +} + +// Show setup screen. Type in matching passwords. +// Click on [Enable] button. Wait until done screen is shown. +IN_PROC_BROWSER_TEST_F(EnableDebuggingTest, SetupMatchingPasswords) { + ShowSetupScreen(); + debug_daemon_client_->ResetWait(); + test::OobeJS().TypeIntoPath("test0000", {"enable-debugging-password"}); + test::OobeJS().TypeIntoPath("test0000", {"enable-debugging-password2"}); + ClickEnableButton(); + debug_daemon_client_->WaitUntilCalled(); + test::OobeJS().CreateHasClassWaiter(true, "done-view", {"debugging"}); + + EXPECT_EQ(debug_daemon_client_->num_enable_debugging_features(), 1); + EXPECT_EQ(debug_daemon_client_->num_remove_protection(), 0); +} + +// Show setup screen. Type in different passwords. +// Click on [Enable] button. Assert done screen is not shown. +// Then confirm that typing in matching passwords enables debugging features. +IN_PROC_BROWSER_TEST_F(EnableDebuggingTest, SetupNotMatchingPasswords) { + ShowSetupScreen(); + debug_daemon_client_->ResetWait(); + test::OobeJS().TypeIntoPath("test0000", {"enable-debugging-password"}); + test::OobeJS().TypeIntoPath("test9999", {"enable-debugging-password2"}); + ClickEnableButton(); + test::OobeJS().CreateHasClassWaiter(false, "done-view", {"debugging"}); + + EXPECT_EQ(debug_daemon_client_->num_enable_debugging_features(), 0); + EXPECT_EQ(debug_daemon_client_->num_remove_protection(), 0); + + test::OobeJS().TypeIntoPath("test0000", {"enable-debugging-password2"}); + ClickEnableButton(); + debug_daemon_client_->WaitUntilCalled(); + test::OobeJS().CreateHasClassWaiter(true, "done-view", {"debugging"}); + EXPECT_EQ(debug_daemon_client_->num_enable_debugging_features(), 1); EXPECT_EQ(debug_daemon_client_->num_remove_protection(), 0); } @@ -367,8 +412,7 @@ test::OobeJS().ExpectHidden("debugging"); InvokeEnableDebuggingScreen(); test::OobeJS().ExpectVisible("debugging"); - base::RunLoop().RunUntilIdle(); - test::OobeJS().ExpectHasClass("error-view", {"debugging"}); + test::OobeJS().CreateHasClassWaiter(true, "error-view", {"debugging"}); test::OobeJS().ExpectHasNoClass("remove-protection-view", {"debugging"}); test::OobeJS().ExpectHasNoClass("setup-view", {"debugging"}); test::OobeJS().ExpectHasNoClass("done-view", {"debugging"});
diff --git a/chrome/browser/chromeos/login/screens/base_screen_delegate.h b/chrome/browser/chromeos/login/screens/base_screen_delegate.h deleted file mode 100644 index fa4235b41..0000000 --- a/chrome/browser/chromeos/login/screens/base_screen_delegate.h +++ /dev/null
@@ -1,23 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_BASE_SCREEN_DELEGATE_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_BASE_SCREEN_DELEGATE_H_ - -namespace chromeos { - -// Interface that handles notifications received from any of login wizard -// screens. -class BaseScreenDelegate { - public: - // Forces current screen showing. - virtual void ShowCurrentScreen() = 0; - - protected: - virtual ~BaseScreenDelegate() {} -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_BASE_SCREEN_DELEGATE_H_
diff --git a/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.cc b/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.cc deleted file mode 100644 index 594c4f5..0000000 --- a/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.cc +++ /dev/null
@@ -1,13 +0,0 @@ -// Copyright (c) 2011 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h" - -namespace chromeos { - -MockBaseScreenDelegate::MockBaseScreenDelegate() {} - -MockBaseScreenDelegate::~MockBaseScreenDelegate() {} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h b/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h deleted file mode 100644 index 000ea786..0000000 --- a/chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h +++ /dev/null
@@ -1,28 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_BASE_SCREEN_DELEGATE_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_BASE_SCREEN_DELEGATE_H_ - -#include <string> - -#include "chrome/browser/chromeos/login/screens/base_screen.h" -#include "chrome/browser/chromeos/login/screens/base_screen_delegate.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace chromeos { - -// Interface that handles notifications received from any of login wizard -// screens. -class MockBaseScreenDelegate : public BaseScreenDelegate { - public: - MockBaseScreenDelegate(); - virtual ~MockBaseScreenDelegate(); - - MOCK_METHOD0(ShowCurrentScreen, void()); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_BASE_SCREEN_DELEGATE_H_
diff --git a/chrome/browser/chromeos/login/screens/mock_supervision_transition_screen.cc b/chrome/browser/chromeos/login/screens/mock_supervision_transition_screen.cc deleted file mode 100644 index f7a4a21..0000000 --- a/chrome/browser/chromeos/login/screens/mock_supervision_transition_screen.cc +++ /dev/null
@@ -1,39 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/chromeos/login/screens/mock_supervision_transition_screen.h" - -namespace chromeos { - -MockSupervisionTransitionScreen::MockSupervisionTransitionScreen( - SupervisionTransitionScreenView* view, - const base::RepeatingClosure& exit_callback) - : SupervisionTransitionScreen(view, exit_callback) {} - -MockSupervisionTransitionScreen::~MockSupervisionTransitionScreen() = default; - -void MockSupervisionTransitionScreen::ExitScreen() { - exit_callback()->Run(); -} - -MockSupervisionTransitionScreenView::MockSupervisionTransitionScreenView() = - default; - -MockSupervisionTransitionScreenView::~MockSupervisionTransitionScreenView() { - if (screen_) - screen_->OnViewDestroyed(this); -} - -void MockSupervisionTransitionScreenView::Bind( - SupervisionTransitionScreen* screen) { - screen_ = screen; - MockBind(screen); -} - -void MockSupervisionTransitionScreenView::Unbind() { - screen_ = nullptr; - MockUnbind(); -} - -} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/mock_supervision_transition_screen.h b/chrome/browser/chromeos/login/screens/mock_supervision_transition_screen.h deleted file mode 100644 index 4028e580..0000000 --- a/chrome/browser/chromeos/login/screens/mock_supervision_transition_screen.h +++ /dev/null
@@ -1,50 +0,0 @@ -// Copyright (c) 2018 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_SUPERVISION_TRANSITION_SCREEN_H_ -#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_SUPERVISION_TRANSITION_SCREEN_H_ - -#include "chrome/browser/chromeos/login/screens/supervision_transition_screen.h" -#include "chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h" -#include "testing/gmock/include/gmock/gmock.h" - -namespace chromeos { - -class MockSupervisionTransitionScreen : public SupervisionTransitionScreen { - public: - MockSupervisionTransitionScreen(SupervisionTransitionScreenView* view, - const base::RepeatingClosure& exit_callback); - virtual ~MockSupervisionTransitionScreen(); - - MOCK_METHOD0(Show, void()); - MOCK_METHOD0(Hide, void()); - - void ExitScreen(); - - private: - DISALLOW_COPY_AND_ASSIGN(MockSupervisionTransitionScreen); -}; - -class MockSupervisionTransitionScreenView - : public SupervisionTransitionScreenView { - public: - MockSupervisionTransitionScreenView(); - virtual ~MockSupervisionTransitionScreenView(); - - void Bind(SupervisionTransitionScreen* screen) override; - void Unbind() override; - - MOCK_METHOD0(Show, void()); - MOCK_METHOD0(Hide, void()); - MOCK_METHOD1(MockBind, void(SupervisionTransitionScreen* screen)); - MOCK_METHOD0(MockUnbind, void()); - - private: - SupervisionTransitionScreen* screen_ = nullptr; - DISALLOW_COPY_AND_ASSIGN(MockSupervisionTransitionScreenView); -}; - -} // namespace chromeos - -#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_SUPERVISION_TRANSITION_SCREEN_H_
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.cc b/chrome/browser/chromeos/login/screens/mock_update_screen.cc index b5ac712..a405ec96e 100644 --- a/chrome/browser/chromeos/login/screens/mock_update_screen.cc +++ b/chrome/browser/chromeos/login/screens/mock_update_screen.cc
@@ -10,11 +10,10 @@ namespace chromeos { MockUpdateScreen::MockUpdateScreen( - BaseScreenDelegate* base_screen_delegate, UpdateView* view, ErrorScreen* error_screen, const UpdateScreen::ScreenExitCallback& exit_callback) - : UpdateScreen(base_screen_delegate, view, error_screen, exit_callback) {} + : UpdateScreen(view, error_screen, exit_callback) {} MockUpdateScreen::~MockUpdateScreen() {}
diff --git a/chrome/browser/chromeos/login/screens/mock_update_screen.h b/chrome/browser/chromeos/login/screens/mock_update_screen.h index 84565705..230ae6af 100644 --- a/chrome/browser/chromeos/login/screens/mock_update_screen.h +++ b/chrome/browser/chromeos/login/screens/mock_update_screen.h
@@ -5,7 +5,6 @@ #ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_UPDATE_SCREEN_H_ #define CHROME_BROWSER_CHROMEOS_LOGIN_SCREENS_MOCK_UPDATE_SCREEN_H_ -#include "chrome/browser/chromeos/login/screens/base_screen_delegate.h" #include "chrome/browser/chromeos/login/screens/update_screen.h" #include "chrome/browser/ui/webui/chromeos/login/update_screen_handler.h" #include "testing/gmock/include/gmock/gmock.h" @@ -14,15 +13,13 @@ class MockUpdateScreen : public UpdateScreen { public: - MockUpdateScreen(BaseScreenDelegate* base_screen_delegate, - UpdateView* view, + MockUpdateScreen(UpdateView* view, ErrorScreen* error_screen, const ScreenExitCallback& exit_callback); virtual ~MockUpdateScreen(); MOCK_METHOD0(Show, void()); MOCK_METHOD0(Hide, void()); - MOCK_METHOD0(StartNetworkCheck, void()); void RunExit(UpdateScreen::Result result); };
diff --git a/chrome/browser/chromeos/login/screens/supervision_transition_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/supervision_transition_screen_browsertest.cc new file mode 100644 index 0000000..267398dc --- /dev/null +++ b/chrome/browser/chromeos/login/screens/supervision_transition_screen_browsertest.cc
@@ -0,0 +1,192 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <memory> +#include <string> + +#include "base/run_loop.h" +#include "base/timer/timer.h" +#include "chrome/browser/chromeos/arc/arc_service_launcher.h" +#include "chrome/browser/chromeos/arc/arc_session_manager.h" +#include "chrome/browser/chromeos/arc/arc_util.h" +#include "chrome/browser/chromeos/login/mixin_based_in_process_browser_test.h" +#include "chrome/browser/chromeos/login/test/js_checker.h" +#include "chrome/browser/chromeos/login/test/login_manager_mixin.h" +#include "chrome/browser/chromeos/login/test/login_screen_tester.h" +#include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h" +#include "chrome/browser/chromeos/login/test/user_policy_mixin.h" +#include "chrome/browser/chromeos/login/ui/login_display_host.h" +#include "chrome/browser/profiles/profile.h" +#include "chrome/browser/profiles/profile_manager.h" +#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" +#include "chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h" +#include "chromeos/constants/chromeos_switches.h" +#include "chromeos/login/auth/stub_authenticator_builder.h" +#include "chromeos/login/auth/user_context.h" +#include "components/arc/arc_prefs.h" +#include "components/arc/session/arc_session_runner.h" +#include "components/arc/session/arc_supervision_transition.h" +#include "components/arc/test/fake_arc_session.h" +#include "components/prefs/pref_service.h" +#include "components/user_manager/user_type.h" + +namespace chromeos { + +// Param returns the original user type. +class SupervisionTransitionScreenTest + : public MixinBasedInProcessBrowserTest, + public testing::WithParamInterface<user_manager::UserType> { + public: + SupervisionTransitionScreenTest() = default; + ~SupervisionTransitionScreenTest() override = default; + + // MixinBasedInProcessBrowserTest: + void SetUpCommandLine(base::CommandLine* command_line) override { + command_line->AppendSwitchASCII(switches::kArcAvailability, + "officially-supported"); + MixinBasedInProcessBrowserTest::SetUpCommandLine(command_line); + } + + void SetUpOnMainThread() override { + ASSERT_TRUE(user_policy_.RequestCachedPolicyUpdate()); + + arc::ArcServiceLauncher::Get()->ResetForTesting(); + arc::ArcSessionManager::Get()->SetArcSessionRunnerForTesting( + std::make_unique<arc::ArcSessionRunner>( + base::BindRepeating(arc::FakeArcSession::Create))); + + MixinBasedInProcessBrowserTest::SetUpOnMainThread(); + } + + // The tests simulate user type changes between regular and child user. + // This returns the intended user type after transition. GetParam() returns + // the initial user type. + user_manager::UserType GetTargetUserType() const { + return GetParam() == user_manager::USER_TYPE_REGULAR + ? user_manager::USER_TYPE_CHILD + : user_manager::USER_TYPE_REGULAR; + } + + LoginManagerMixin::TestUserInfo user_{ + AccountId::FromUserEmailGaiaId("user@gmail.com", "user"), GetParam()}; + LoginManagerMixin login_manager_{&mixin_host_, {user_}}; + + UserPolicyMixin user_policy_{&mixin_host_, user_.account_id}; +}; + +IN_PROC_BROWSER_TEST_P(SupervisionTransitionScreenTest, + PRE_SuccessfulTransition) { + login_manager_.LoginAndWaitForActiveSession( + LoginManagerMixin::CreateDefaultUserContext(user_)); + + Profile* profile = ProfileManager::GetPrimaryUserProfile(); + profile->GetPrefs()->SetBoolean(arc::prefs::kArcSignedIn, true); + arc::SetArcPlayStoreEnabledForProfile(profile, true); +} + +IN_PROC_BROWSER_TEST_P(SupervisionTransitionScreenTest, SuccessfulTransition) { + LoginManagerMixin::TestUserInfo transitioned_user(user_.account_id, + GetTargetUserType()); + UserContext user_context = + LoginManagerMixin::CreateDefaultUserContext(transitioned_user); + + login_manager_.AttemptLoginUsingAuthenticator( + user_context, std::make_unique<StubAuthenticatorBuilder>(user_context)); + + OobeScreenWaiter(SupervisionTransitionScreenView::kScreenId).Wait(); + + test::OobeJS().ExpectVisiblePath( + {"supervision-transition-md", "supervisionTransitionDialog"}); + test::OobeJS().ExpectHiddenPath( + {"supervision-transition-md", "supervisionTransitionErrorDialog"}); + + EXPECT_FALSE(test::LoginScreenTester().IsGuestButtonShown()); + EXPECT_FALSE(test::LoginScreenTester().IsAddUserButtonShown()); + + ProfileManager::GetPrimaryUserProfile()->GetPrefs()->SetInteger( + arc::prefs::kArcSupervisionTransition, + static_cast<int>(arc::ArcSupervisionTransition::NO_TRANSITION)); + + EXPECT_FALSE(ProfileManager::GetPrimaryUserProfile()->GetPrefs()->GetBoolean( + arc::prefs::kArcDataRemoveRequested)); + + login_manager_.WaitForActiveSession(); +} + +IN_PROC_BROWSER_TEST_P(SupervisionTransitionScreenTest, PRE_TransitionTimeout) { + login_manager_.LoginAndWaitForActiveSession( + LoginManagerMixin::CreateDefaultUserContext(user_)); + + Profile* profile = ProfileManager::GetPrimaryUserProfile(); + profile->GetPrefs()->SetBoolean(arc::prefs::kArcSignedIn, true); + arc::SetArcPlayStoreEnabledForProfile(profile, true); +} + +IN_PROC_BROWSER_TEST_P(SupervisionTransitionScreenTest, TransitionTimeout) { + LoginManagerMixin::TestUserInfo transitioned_user(user_.account_id, + GetTargetUserType()); + UserContext user_context = + LoginManagerMixin::CreateDefaultUserContext(transitioned_user); + + login_manager_.AttemptLoginUsingAuthenticator( + user_context, std::make_unique<StubAuthenticatorBuilder>(user_context)); + + OobeScreenWaiter(SupervisionTransitionScreenView::kScreenId).Wait(); + + test::OobeJS().ExpectVisiblePath( + {"supervision-transition-md", "supervisionTransitionDialog"}); + test::OobeJS().ExpectHiddenPath( + {"supervision-transition-md", "supervisionTransitionErrorDialog"}); + + EXPECT_FALSE(test::LoginScreenTester().IsGuestButtonShown()); + EXPECT_FALSE(test::LoginScreenTester().IsAddUserButtonShown()); + + base::OneShotTimer* timer = + LoginDisplayHost::default_host() + ->GetOobeUI() + ->GetHandler<SupervisionTransitionScreenHandler>() + ->GetTimerForTesting(); + ASSERT_TRUE(timer->IsRunning()); + timer->FireNow(); + + EXPECT_TRUE(ProfileManager::GetPrimaryUserProfile()->GetPrefs()->GetBoolean( + arc::prefs::kArcDataRemoveRequested)); + + test::OobeJS() + .CreateVisibilityWaiter(true, {"supervision-transition-md", + "supervisionTransitionErrorDialog"}) + ->Wait(); + test::OobeJS().ExpectHiddenPath( + {"supervision-transition-md", "supervisionTransitionDialog"}); + + EXPECT_FALSE(test::LoginScreenTester().IsGuestButtonShown()); + EXPECT_FALSE(test::LoginScreenTester().IsAddUserButtonShown()); + + test::OobeJS().TapOnPath({"supervision-transition-md", "accept-button"}); + + login_manager_.WaitForActiveSession(); +} + +IN_PROC_BROWSER_TEST_P(SupervisionTransitionScreenTest, + PRE_SkipTransitionIfArcNeverStarted) { + login_manager_.LoginAndWaitForActiveSession( + LoginManagerMixin::CreateDefaultUserContext(user_)); +} + +IN_PROC_BROWSER_TEST_P(SupervisionTransitionScreenTest, + SkipTransitionIfArcNeverStarted) { + LoginManagerMixin::TestUserInfo transitioned_user(user_.account_id, + GetTargetUserType()); + + // Login should go through without being interrupted. + login_manager_.LoginAndWaitForActiveSession( + LoginManagerMixin::CreateDefaultUserContext(transitioned_user)); +} + +INSTANTIATE_TEST_SUITE_P(/* no prefix */, + SupervisionTransitionScreenTest, + testing::Values(user_manager::USER_TYPE_REGULAR, + user_manager::USER_TYPE_CHILD)); + +} // namespace chromeos
diff --git a/chrome/browser/chromeos/login/screens/update_screen.cc b/chrome/browser/chromeos/login/screens/update_screen.cc index 8886b89..5e15204c 100644 --- a/chrome/browser/chromeos/login/screens/update_screen.cc +++ b/chrome/browser/chromeos/login/screens/update_screen.cc
@@ -18,7 +18,6 @@ #include "base/time/default_tick_clock.h" #include "chrome/browser/chromeos/login/error_screens_histogram_helper.h" #include "chrome/browser/chromeos/login/screen_manager.h" -#include "chrome/browser/chromeos/login/screens/base_screen_delegate.h" #include "chrome/browser/chromeos/login/screens/error_screen.h" #include "chrome/browser/chromeos/login/screens/network_error.h" #include "chrome/browser/chromeos/login/startup_utils.h" @@ -84,6 +83,8 @@ // its login page before error message appears. const int kDelayErrorMessageSec = 10; +const int kShowDelayMs = 400; + } // anonymous namespace // static @@ -91,14 +92,12 @@ return static_cast<UpdateScreen*>(manager->GetScreen(UpdateView::kScreenId)); } -UpdateScreen::UpdateScreen(BaseScreenDelegate* base_screen_delegate, - UpdateView* view, +UpdateScreen::UpdateScreen(UpdateView* view, ErrorScreen* error_screen, const ScreenExitCallback& exit_callback) : BaseScreen(UpdateView::kScreenId), tick_clock_(base::DefaultTickClock::GetInstance()), reboot_check_delay_(kWaitForRebootTimeSec), - base_screen_delegate_(base_screen_delegate), view_(view), error_screen_(error_screen), exit_callback_(exit_callback), @@ -142,6 +141,7 @@ void UpdateScreen::ExitUpdate(Result result) { DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); network_portal_detector::GetInstance()->RemoveObserver(this); + show_timer_.Stop(); exit_callback_.Run(result); } @@ -324,6 +324,10 @@ } else { UpdateErrorMessage(network, status); + // StartUpdateCheck, which gets called when the error clears up, will add + // the update engine observer back. + DBusThreadManager::Get()->GetUpdateEngineClient()->RemoveObserver(this); + if (status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL) DelayErrorMessage(); else @@ -337,6 +341,10 @@ ExitUpdate(Result::UPDATE_NOT_REQUIRED); } +base::OneShotTimer* UpdateScreen::GetShowTimerForTesting() { + return &show_timer_; +} + base::OneShotTimer* UpdateScreen::GetErrorMessageTimerForTesting() { return &error_message_timer_; } @@ -346,21 +354,23 @@ } void UpdateScreen::Show() { - is_shown_ = true; - histogram_helper_->OnScreenShow(); - if (view_) { #if !defined(OFFICIAL_BUILD) view_->SetCancelUpdateShortcutEnabled(true); #endif view_->SetProgress(kBeforeUpdateCheckProgress); view_->SetRequiresPermissionForCellular(false); - - view_->Show(); } + + show_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(kShowDelayMs), + base::BindOnce(&UpdateScreen::MakeSureScreenIsShown, + weak_factory_.GetWeakPtr())); + + StartNetworkCheck(); } void UpdateScreen::Hide() { + show_timer_.Stop(); if (view_) view_->Hide(); is_shown_ = false; @@ -488,9 +498,15 @@ } void UpdateScreen::MakeSureScreenIsShown() { - if (!is_shown_) { - base_screen_delegate_->ShowCurrentScreen(); - } + show_timer_.Stop(); + + if (is_shown_ || !view_) + return; + + is_shown_ = true; + histogram_helper_->OnScreenShow(); + + view_->Show(); } void UpdateScreen::StartUpdateCheck() { @@ -519,6 +535,8 @@ error_message_timer_.Stop(); is_shown_ = false; + show_timer_.Stop(); + state_ = State::STATE_ERROR; connect_request_subscription_ = error_screen_->RegisterConnectRequestCallback(base::BindRepeating(
diff --git a/chrome/browser/chromeos/login/screens/update_screen.h b/chrome/browser/chromeos/login/screens/update_screen.h index aefbff7b..a971882 100644 --- a/chrome/browser/chromeos/login/screens/update_screen.h +++ b/chrome/browser/chromeos/login/screens/update_screen.h
@@ -23,7 +23,6 @@ namespace chromeos { -class BaseScreenDelegate; class ErrorScreen; class ErrorScreensHistogramHelper; class NetworkState; @@ -68,8 +67,7 @@ }; using ScreenExitCallback = base::RepeatingCallback<void(Result result)>; - UpdateScreen(BaseScreenDelegate* base_screen_delegate, - UpdateView* view, + UpdateScreen(UpdateView* view, ErrorScreen* error_screen, const ScreenExitCallback& exit_callback); ~UpdateScreen() override; @@ -78,9 +76,6 @@ // associated View if this class is destroyed before it. void OnViewDestroyed(UpdateView* view); - // Starts network check. Made virtual to simplify mocking. - virtual void StartNetworkCheck(); - void SetIgnoreIdleStatus(bool ignore_idle_status); // UpdateEngineClient::Observer implementation: @@ -99,6 +94,7 @@ void Hide() override; void OnUserAction(const std::string& action_id) override; + base::OneShotTimer* GetShowTimerForTesting(); base::OneShotTimer* GetErrorMessageTimerForTesting(); base::OneShotTimer* GetRebootTimerForTesting(); @@ -128,6 +124,9 @@ STATE_ERROR }; + // Starts network check. + void StartNetworkCheck(); + // Callback to UpdateEngineClient::SetUpdateOverCellularOneTimePermission // called in response to user confirming that the OS update can proceed // despite being over cellular charges. @@ -194,7 +193,6 @@ // Ignore fist IDLE status that is sent before update screen initiated check. bool ignore_idle_status_ = true; - BaseScreenDelegate* base_screen_delegate_; UpdateView* view_; ErrorScreen* error_screen_; ScreenExitCallback exit_callback_; @@ -227,6 +225,14 @@ std::unique_ptr<ErrorScreensHistogramHelper> histogram_helper_; + // Showing the update screen view will be delayed for a small amount of time + // after UpdateScreen::Show() is called. If the screen determines that an + // update is not required before the delay expires, the UpdateScreen will exit + // without actually showing any UI. The goal is to avoid short flashes of + // update screen UI when update check is done quickly enough. + // This holds the timer to show the actual update screen UI. + base::OneShotTimer show_timer_; + // Timer for the captive portal detector to show portal login page. // If redirect did not happen during this delay, error message is shown // instead.
diff --git a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc index b22806c..4c16261 100644 --- a/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/update_screen_browsertest.cc
@@ -15,7 +15,6 @@ #include "base/time/time.h" #include "chrome/browser/chromeos/login/login_wizard.h" #include "chrome/browser/chromeos/login/mixin_based_in_process_browser_test.h" -#include "chrome/browser/chromeos/login/screens/base_screen_delegate.h" #include "chrome/browser/chromeos/login/screens/error_screen.h" #include "chrome/browser/chromeos/login/screens/update_screen.h" #include "chrome/browser/chromeos/login/test/js_checker.h" @@ -50,25 +49,6 @@ return host ? host->GetOobeUI() : nullptr; } -class TestErrorScreenDelegate : public BaseScreenDelegate { - public: - TestErrorScreenDelegate() = default; - ~TestErrorScreenDelegate() override = default; - - void set_parent_screen(UpdateScreen* parent_screen) { - parent_screen_ = parent_screen; - } - - // BaseScreenDelegate: - void ShowCurrentScreen() override { parent_screen_->Show(); } - - private: - // The update screen under test, that uses this delegate. - // Should be set using |set_parent_screen()| after the update screen is - // created. - BaseScreen* parent_screen_; -}; - } // namespace class UpdateScreenTest : public MixinBasedInProcessBrowserTest { @@ -91,14 +71,11 @@ tick_clock_.Advance(base::TimeDelta::FromMinutes(1)); error_screen_ = GetOobeUI()->GetErrorScreen(); - error_delegate_ = std::make_unique<TestErrorScreenDelegate>(); update_screen_ = std::make_unique<UpdateScreen>( - error_delegate_.get(), GetOobeUI()->GetView<UpdateScreenHandler>(), - error_screen_, + GetOobeUI()->GetView<UpdateScreenHandler>(), error_screen_, base::BindRepeating(&UpdateScreenTest::HandleScreenExit, base::Unretained(this))); update_screen_->set_tick_clock_for_testing(&tick_clock_); - error_delegate_->set_parent_screen(update_screen_.get()); MixinBasedInProcessBrowserTest::SetUpOnMainThread(); } @@ -107,7 +84,6 @@ MixinBasedInProcessBrowserTest::TearDownOnMainThread(); update_screen_.reset(); - error_delegate_.reset(); base::RunLoop run_loop; LoginDisplayHost::default_host()->Finalize(run_loop.QuitClosure()); @@ -126,7 +102,6 @@ NetworkPortalDetectorMixin network_portal_detector_{&mixin_host_}; - std::unique_ptr<TestErrorScreenDelegate> error_delegate_; std::unique_ptr<UpdateScreen> update_screen_; // Error screen - owned by OobeUI. ErrorScreen* error_screen_ = nullptr; @@ -151,11 +126,12 @@ DISALLOW_COPY_AND_ASSIGN(UpdateScreenTest); }; -// The wizard controller will not call Show() if the update screen detects that -// there is no update in time - this tests that StartNetworkCheck() on it's own -// does not cause update screen to be shown if no update is found. IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestUpdateCheckDoneBeforeShow) { - update_screen_->StartNetworkCheck(); + update_screen_->Show(); + // For this test, the show timer is expected not to fire - cancel it + // immediately. + EXPECT_TRUE(update_screen_->GetShowTimerForTesting()->IsRunning()); + update_screen_->GetShowTimerForTesting()->Stop(); UpdateEngineClient::Status status; status.status = UpdateEngineClient::UPDATE_STATUS_IDLE; @@ -184,7 +160,8 @@ } IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestUpdateNotFoundAfterScreenShow) { - update_screen_->StartNetworkCheck(); + update_screen_->Show(); + EXPECT_TRUE(update_screen_->GetShowTimerForTesting()->IsRunning()); UpdateEngineClient::Status status; status.status = UpdateEngineClient::UPDATE_STATUS_IDLE; @@ -195,8 +172,7 @@ fake_update_engine_client_->set_default_status(status); fake_update_engine_client_->NotifyObserversThatStatusChanged(status); - // If show is called explicitly, the update screen is expected to be shown. - update_screen_->Show(); + update_screen_->GetShowTimerForTesting()->FireNow(); OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId); update_screen_waiter.set_assert_next_screen(); @@ -222,7 +198,7 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestUpdateAvailable) { update_screen_->set_ignore_update_deadlines_for_testing(true); - update_screen_->StartNetworkCheck(); + update_screen_->Show(); UpdateEngineClient::Status status; status.status = UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE; @@ -231,7 +207,7 @@ fake_update_engine_client_->set_default_status(status); fake_update_engine_client_->NotifyObserversThatStatusChanged(status); - update_screen_->Show(); + update_screen_->GetShowTimerForTesting()->FireNow(); OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId); update_screen_waiter.set_assert_next_screen(); @@ -396,15 +372,17 @@ IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorIssuingUpdateCheck) { fake_update_engine_client_->set_update_check_result( chromeos::UpdateEngineClient::UPDATE_RESULT_FAILED); - update_screen_->StartNetworkCheck(); + update_screen_->Show(); ASSERT_TRUE(last_screen_result_.has_value()); EXPECT_EQ(UpdateScreen::Result::UPDATE_NOT_REQUIRED, last_screen_result_.value()); + + EXPECT_FALSE(update_screen_->GetShowTimerForTesting()->IsRunning()); } IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorCheckingForUpdate) { - update_screen_->StartNetworkCheck(); + update_screen_->Show(); UpdateEngineClient::Status status; status.status = UpdateEngineClient::UPDATE_STATUS_ERROR; @@ -416,10 +394,12 @@ ASSERT_TRUE(last_screen_result_.has_value()); EXPECT_EQ(UpdateScreen::Result::UPDATE_NOT_REQUIRED, last_screen_result_.value()); + + EXPECT_FALSE(update_screen_->GetShowTimerForTesting()->IsRunning()); } IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestErrorUpdating) { - update_screen_->StartNetworkCheck(); + update_screen_->Show(); UpdateEngineClient::Status status; status.status = UpdateEngineClient::UPDATE_STATUS_ERROR; @@ -431,6 +411,8 @@ ASSERT_TRUE(last_screen_result_.has_value()); EXPECT_EQ(UpdateScreen::Result::UPDATE_NOT_REQUIRED, last_screen_result_.value()); + + EXPECT_FALSE(update_screen_->GetShowTimerForTesting()->IsRunning()); } IN_PROC_BROWSER_TEST_F(UpdateScreenTest, TestTemporaryPortalNetwork) { @@ -438,7 +420,7 @@ network_portal_detector_.SimulateDefaultNetworkState( NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL); - update_screen_->StartNetworkCheck(); + update_screen_->Show(); // If the network is a captive portal network, error message is shown with a // delay. @@ -452,11 +434,18 @@ EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning()); UpdateEngineClient::Status status; - status.status = UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE; - + status.status = UpdateEngineClient::UPDATE_STATUS_CHECKING_FOR_UPDATE; fake_update_engine_client_->set_default_status(status); fake_update_engine_client_->NotifyObserversThatStatusChanged(status); + EXPECT_TRUE(update_screen_->GetShowTimerForTesting()->IsRunning()); + + status.status = UpdateEngineClient::UPDATE_STATUS_UPDATE_AVAILABLE; + fake_update_engine_client_->set_default_status(status); + fake_update_engine_client_->NotifyObserversThatStatusChanged(status); + + EXPECT_FALSE(update_screen_->GetShowTimerForTesting()->IsRunning()); + // Verify that update screen is showing checking for update UI. OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId); update_screen_waiter.set_assert_next_screen(); @@ -482,7 +471,7 @@ // Change ethernet state to portal. network_portal_detector_.SimulateDefaultNetworkState( NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL); - update_screen_->StartNetworkCheck(); + update_screen_->Show(); // Update screen will delay error message about portal state because // ethernet is behind captive portal. Simulate the delay timing out. @@ -521,7 +510,7 @@ // First portal detection attempt returns NULL network and undefined // results, so detection is restarted. - update_screen_->StartNetworkCheck(); + update_screen_->Show(); EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning()); @@ -530,6 +519,7 @@ EXPECT_FALSE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning()); ASSERT_EQ(UpdateView::kScreenId.AsId(), error_screen_->GetParentScreen()); + EXPECT_FALSE(update_screen_->GetShowTimerForTesting()->IsRunning()); // Second portal detection also returns NULL network and undefined // results. In this case, offline message should be displayed. @@ -551,12 +541,13 @@ network_portal_detector_.SimulateDefaultNetworkState( NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL); - update_screen_->StartNetworkCheck(); + update_screen_->Show(); // Force timer expiration. EXPECT_TRUE(update_screen_->GetErrorMessageTimerForTesting()->IsRunning()); update_screen_->GetErrorMessageTimerForTesting()->FireNow(); ASSERT_EQ(UpdateView::kScreenId.AsId(), error_screen_->GetParentScreen()); + EXPECT_FALSE(update_screen_->GetShowTimerForTesting()->IsRunning()); OobeScreenWaiter error_screen_waiter(ErrorScreenView::kScreenId); error_screen_waiter.set_assert_next_screen(); @@ -568,6 +559,8 @@ ASSERT_EQ(OobeScreen::SCREEN_UNKNOWN.AsId(), error_screen_->GetParentScreen()); + EXPECT_TRUE(update_screen_->GetShowTimerForTesting()->IsRunning()); + update_screen_->GetShowTimerForTesting()->FireNow(); OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId); update_screen_waiter.set_assert_next_screen(); @@ -583,11 +576,13 @@ status.status = UpdateEngineClient::UPDATE_STATUS_NEED_PERMISSION_TO_UPDATE; status.new_version = "latest and greatest"; - update_screen_->StartNetworkCheck(); + update_screen_->Show(); fake_update_engine_client_->set_default_status(status); fake_update_engine_client_->NotifyObserversThatStatusChanged(status); + EXPECT_FALSE(update_screen_->GetShowTimerForTesting()->IsRunning()); + OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId); update_screen_waiter.set_assert_next_screen(); update_screen_waiter.Wait(); @@ -625,11 +620,13 @@ status.status = UpdateEngineClient::UPDATE_STATUS_NEED_PERMISSION_TO_UPDATE; status.new_version = "latest and greatest"; - update_screen_->StartNetworkCheck(); + update_screen_->Show(); fake_update_engine_client_->set_default_status(status); fake_update_engine_client_->NotifyObserversThatStatusChanged(status); + EXPECT_FALSE(update_screen_->GetShowTimerForTesting()->IsRunning()); + OobeScreenWaiter update_screen_waiter(UpdateView::kScreenId); update_screen_waiter.set_assert_next_screen(); update_screen_waiter.Wait();
diff --git a/chrome/browser/chromeos/login/screens/update_screen_unittest.cc b/chrome/browser/chromeos/login/screens/update_screen_unittest.cc index e4b01e6..8f23ddd 100644 --- a/chrome/browser/chromeos/login/screens/update_screen_unittest.cc +++ b/chrome/browser/chromeos/login/screens/update_screen_unittest.cc
@@ -7,7 +7,6 @@ #include "base/command_line.h" #include "base/optional.h" #include "base/test/scoped_mock_time_message_loop_task_runner.h" -#include "chrome/browser/chromeos/login/screens/mock_base_screen_delegate.h" #include "chrome/browser/chromeos/login/screens/mock_error_screen.h" #include "chrome/browser/chromeos/login/screens/mock_update_screen.h" #include "chrome/browser/chromeos/login/startup_utils.h" @@ -84,7 +83,7 @@ .WillRepeatedly(Return(false)); update_screen_ = std::make_unique<UpdateScreen>( - &mock_base_screen_delegate_, &mock_view_, mock_error_screen_.get(), + &mock_view_, mock_error_screen_.get(), base::BindRepeating(&UpdateScreenUnitTest::HandleScreenExit, base::Unretained(this))); } @@ -103,7 +102,6 @@ std::unique_ptr<UpdateScreen> update_screen_; // Accessory objects needed by UpdateScreen. - MockBaseScreenDelegate mock_base_screen_delegate_; MockUpdateView mock_view_; MockErrorScreenView mock_error_view_; std::unique_ptr<MockErrorScreen> mock_error_screen_; @@ -127,7 +125,7 @@ TEST_F(UpdateScreenUnitTest, HandlesNoUpdate) { // DUT reaches UpdateScreen. - update_screen_->StartNetworkCheck(); + update_screen_->Show(); // Verify that the DUT checks for an update. EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1); @@ -143,7 +141,7 @@ TEST_F(UpdateScreenUnitTest, HandlesNonCriticalUpdate) { // DUT reaches UpdateScreen. - update_screen_->StartNetworkCheck(); + update_screen_->Show(); // Verify that the DUT checks for an update. EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1); @@ -159,7 +157,7 @@ TEST_F(UpdateScreenUnitTest, HandlesCriticalUpdate) { // DUT reaches UpdateScreen. - update_screen_->StartNetworkCheck(); + update_screen_->Show(); // Verify that the DUT checks for an update. EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1); @@ -173,7 +171,7 @@ TEST_F(UpdateScreenUnitTest, HandleCriticalUpdateError) { // DUT reaches UpdateScreen. - update_screen_->StartNetworkCheck(); + update_screen_->Show(); // Verify that the DUT checks for an update. EXPECT_EQ(fake_update_engine_client_->request_update_check_call_count(), 1);
diff --git a/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc b/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc index 73e06de..dd9132e 100644 --- a/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc +++ b/chrome/browser/chromeos/login/screens/welcome_screen_browsertest.cc
@@ -14,6 +14,7 @@ #include "chrome/browser/chromeos/login/wizard_controller.h" #include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h" #include "chrome/browser/ui/webui/chromeos/login/welcome_screen_handler.h" +#include "chromeos/dbus/constants/dbus_switches.h" namespace chromeos { @@ -49,6 +50,7 @@ ~WelcomeScreenBrowserTest() override = default; // InProcessBrowserTest: + void SetUpOnMainThread() override { ShowLoginWizard(OobeScreen::SCREEN_TEST_NO_WINDOW); @@ -89,6 +91,18 @@ base::OnceClosure screen_exit_callback_; }; +class WelcomeScreenSystemDevModeBrowserTest : public WelcomeScreenBrowserTest { + public: + WelcomeScreenSystemDevModeBrowserTest() = default; + ~WelcomeScreenSystemDevModeBrowserTest() override = default; + + // InProcessBrowserTest: + void SetUpCommandLine(base::CommandLine* command_line) override { + WelcomeScreenBrowserTest::SetUpCommandLine(command_line); + command_line->AppendSwitch(chromeos::switches::kSystemDevMode); + } +}; + IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenElements) { welcome_screen_->Show(); OobeScreenWaiter(WelcomeView::kScreenId).Wait(); @@ -103,6 +117,8 @@ {"connect", "welcomeScreen", "languageSelectionButton"}); test::OobeJS().ExpectVisiblePath( {"connect", "welcomeScreen", "accessibilitySettingsButton"}); + test::OobeJS().ExpectVisiblePath( + {"connect", "welcomeScreen", "enableDebuggingLink"}); } IN_PROC_BROWSER_TEST_F(WelcomeScreenBrowserTest, WelcomeScreenNext) { @@ -278,4 +294,17 @@ ASSERT_FALSE(MagnificationManager::Get()->IsMagnifierEnabled()); } +IN_PROC_BROWSER_TEST_F(WelcomeScreenSystemDevModeBrowserTest, + DebuggerModeTest) { + welcome_screen_->Show(); + OobeScreenWaiter(WelcomeView::kScreenId).Wait(); + test::OobeJS().ClickOnPath( + {"connect", "welcomeScreen", "enableDebuggingLink"}); + + test::OobeJS().ExpectVisiblePath({"debugging-remove-protection-button"}); + test::OobeJS().ExpectVisiblePath({"debugging-cancel-button"}); + test::OobeJS().ExpectVisiblePath({"enable-debugging-help-link"}); + test::OobeJS().ClickOnPath({"debugging-cancel-button"}); +} + } // namespace chromeos
diff --git a/chrome/browser/chromeos/login/wizard_controller.cc b/chrome/browser/chromeos/login/wizard_controller.cc index 0ce1a49..c5152d6 100644 --- a/chrome/browser/chromeos/login/wizard_controller.cc +++ b/chrome/browser/chromeos/login/wizard_controller.cc
@@ -164,8 +164,8 @@ using content::BrowserThread; namespace { -// Interval in ms which is used for smooth screen showing. -static int g_show_delay_ms = 400; + +bool g_using_zero_delays = false; // Total timezone resolving process timeout. const unsigned int kResolveTimeZoneTimeoutSeconds = 60; @@ -437,7 +437,7 @@ base::BindRepeating(&WizardController::OnNetworkScreenExit, weak_factory_.GetWeakPtr()))); append(std::make_unique<UpdateScreen>( - this, oobe_ui->GetView<UpdateScreenHandler>(), oobe_ui->GetErrorScreen(), + oobe_ui->GetView<UpdateScreenHandler>(), oobe_ui->GetErrorScreen(), base::BindRepeating(&WizardController::OnUpdateScreenExit, weak_factory_.GetWeakPtr()))); append(std::make_unique<EulaScreen>( @@ -563,7 +563,6 @@ VLOG(1) << "Showing login screen."; UpdateStatusAreaVisibilityForScreen(OobeScreen::SCREEN_SPECIAL_LOGIN); GetLoginDisplayHost()->StartSignInScreen(context); - smooth_show_timer_.Stop(); login_screen_started_ = true; } @@ -1240,8 +1239,7 @@ } void WizardController::StartOOBEUpdate() { - SetCurrentScreenSmooth(GetScreen(UpdateView::kScreenId), true); - UpdateScreen::Get(screen_manager())->StartNetworkCheck(); + SetCurrentScreen(GetScreen(UpdateView::kScreenId)); } void WizardController::StartTimezoneResolve() { @@ -1299,38 +1297,12 @@ } void WizardController::SetCurrentScreen(BaseScreen* new_current) { - SetCurrentScreenSmooth(new_current, false); -} - -void WizardController::ShowCurrentScreen() { - // ShowCurrentScreen may get called by smooth_show_timer_ even after - // flow has been switched to sign in screen (ExistingUserController). - if (!GetOobeUI()) - return; - - // First remember how far have we reached so that we can resume if needed. - if (is_out_of_box_ && !demo_setup_controller_ && - IsResumableScreen(current_screen_->screen_id())) { - StartupUtils::SaveOobePendingScreen(current_screen_->screen_id().name); - } - - smooth_show_timer_.Stop(); - - UpdateStatusAreaVisibilityForScreen(current_screen_->screen_id()); - current_screen_->SetConfiguration(&oobe_configuration_); - current_screen_->Show(); -} - -void WizardController::SetCurrentScreenSmooth(BaseScreen* new_current, - bool use_smoothing) { - VLOG(1) << "SetCurrentScreenSmooth: " << new_current->screen_id(); + VLOG(1) << "SetCurrentScreen: " << new_current->screen_id(); if (current_screen_ == new_current || new_current == nullptr || GetOobeUI() == nullptr) { return; } - smooth_show_timer_.Stop(); - if (current_screen_) { current_screen_->Hide(); current_screen_->SetConfiguration(nullptr); @@ -1343,13 +1315,15 @@ previous_screen_ = current_screen_; current_screen_ = new_current; - if (use_smoothing) { - smooth_show_timer_.Start(FROM_HERE, - base::TimeDelta::FromMilliseconds(g_show_delay_ms), - this, &WizardController::ShowCurrentScreen); - } else { - ShowCurrentScreen(); + // First remember how far have we reached so that we can resume if needed. + if (is_out_of_box_ && !demo_setup_controller_ && + IsResumableScreen(current_screen_->screen_id())) { + StartupUtils::SaveOobePendingScreen(current_screen_->screen_id().name); } + + UpdateStatusAreaVisibilityForScreen(current_screen_->screen_id()); + current_screen_->SetConfiguration(&oobe_configuration_); + current_screen_->Show(); } void WizardController::UpdateStatusAreaVisibilityForScreen( @@ -1504,8 +1478,6 @@ demo_setup_controller_->set_demo_config(*demo_config); } -/////////////////////////////////////////////////////////////////////////////// -// WizardController, BaseScreenDelegate overrides: void WizardController::ShowErrorScreen() { SetCurrentScreen(GetScreen(ErrorScreenView::kScreenId)); } @@ -1569,12 +1541,12 @@ // static void WizardController::SetZeroDelays() { - g_show_delay_ms = 0; + g_using_zero_delays = true; } // static bool WizardController::IsZeroDelayEnabled() { - return g_show_delay_ms == 0; + return g_using_zero_delays; } // static
diff --git a/chrome/browser/chromeos/login/wizard_controller.h b/chrome/browser/chromeos/login/wizard_controller.h index d8392d4..7822193 100644 --- a/chrome/browser/chromeos/login/wizard_controller.h +++ b/chrome/browser/chromeos/login/wizard_controller.h
@@ -23,7 +23,6 @@ #include "chrome/browser/chromeos/login/enrollment/enrollment_screen.h" #include "chrome/browser/chromeos/login/screen_manager.h" #include "chrome/browser/chromeos/login/screens/arc_terms_of_service_screen.h" -#include "chrome/browser/chromeos/login/screens/base_screen_delegate.h" #include "chrome/browser/chromeos/login/screens/demo_preferences_screen.h" #include "chrome/browser/chromeos/login/screens/demo_setup_screen.h" #include "chrome/browser/chromeos/login/screens/enable_debugging_screen.h" @@ -55,10 +54,10 @@ // Class that manages control flow between wizard screens. Wizard controller // interacts with screen controllers to move the user between screens. -class WizardController : public BaseScreenDelegate { +class WizardController { public: WizardController(); - ~WizardController() override; + ~WizardController(); // Returns the default wizard controller if it has been created. This is a // helper for LoginDisplayHost::default_host()->GetWizardController(); @@ -253,8 +252,6 @@ // Actions that should be done right after update stage is finished. void PerformOOBECompletedActions(); - // Overridden from BaseScreenDelegate: - void ShowCurrentScreen() override; ErrorScreen* GetErrorScreen(); void ShowErrorScreen(); @@ -270,10 +267,6 @@ // Switches from one screen to another. void SetCurrentScreen(BaseScreen* screen); - // Switches from one screen to another with delay before showing. Calling - // ShowCurrentScreen directly forces screen to be shown immediately. - void SetCurrentScreenSmooth(BaseScreen* screen, bool use_smoothing); - // Update the status area visibility for |screen|. void UpdateStatusAreaVisibilityForScreen(OobeScreenId screen); @@ -353,8 +346,6 @@ // Value of the screen name that WizardController was started with. OobeScreenId first_screen_ = OobeScreen::SCREEN_UNKNOWN; - base::OneShotTimer smooth_show_timer_; - // If true then update check is cancelled and enrollment is started after // EULA is accepted. bool skip_update_enroll_after_eula_ = false;
diff --git a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc index d6e0b04c..6b317f8 100644 --- a/chrome/browser/chromeos/login/wizard_controller_browsertest.cc +++ b/chrome/browser/chromeos/login/wizard_controller_browsertest.cc
@@ -41,7 +41,6 @@ #include "chrome/browser/chromeos/login/screens/mock_enable_debugging_screen.h" #include "chrome/browser/chromeos/login/screens/mock_eula_screen.h" #include "chrome/browser/chromeos/login/screens/mock_network_screen.h" -#include "chrome/browser/chromeos/login/screens/mock_supervision_transition_screen.h" #include "chrome/browser/chromeos/login/screens/mock_update_screen.h" #include "chrome/browser/chromeos/login/screens/mock_welcome_screen.h" #include "chrome/browser/chromeos/login/screens/mock_wrong_hwid_screen.h" @@ -50,6 +49,7 @@ #include "chrome/browser/chromeos/login/screens/wrong_hwid_screen.h" #include "chrome/browser/chromeos/login/startup_utils.h" #include "chrome/browser/chromeos/login/test/device_state_mixin.h" +#include "chrome/browser/chromeos/login/test/js_checker.h" #include "chrome/browser/chromeos/login/test/oobe_configuration_waiter.h" #include "chrome/browser/chromeos/login/ui/login_display_host.h" #include "chrome/browser/chromeos/login/ui/webui_login_view.h" @@ -486,73 +486,6 @@ cras->GetOutputVolumePercent()); } -class WizardControllerSupervisionTransitionOobeTest - : public WizardControllerTest { - protected: - WizardControllerSupervisionTransitionOobeTest() = default; - - // WizardControllerTest: - void SetUpOnMainThread() override { - WizardControllerTest::SetUpOnMainThread(); - // Setup existing user session and profile. - const AccountId test_account_id_ = - AccountId::FromUserEmailGaiaId("test@gmail.com", "123456"); - session_manager::SessionManager::Get()->CreateSession( - test_account_id_, test_account_id_.GetUserEmail(), - /* is_child= */ false); - ProfileHelper::Get()->GetProfileByUserIdHashForTest( - test_account_id_.GetUserEmail()); - // Pretend OOBE was complete. - StartupUtils::MarkOobeCompleted(); - - official_build_override_ = WizardController::ForceOfficialBuildForTesting(); - - mock_supervision_transition_screen_view_ = - std::make_unique<MockSupervisionTransitionScreenView>(); - ExpectBindUnbind(mock_supervision_transition_screen_view_.get()); - mock_supervision_transition_screen_ = MockScreenExpectLifecycle( - std::make_unique<MockSupervisionTransitionScreen>( - mock_supervision_transition_screen_view_.get(), - base::BindRepeating( - &WizardController::OnSupervisionTransitionScreenExit, - base::Unretained(WizardController::default_controller())))); - } - - void SetUpCommandLine(base::CommandLine* command_line) override { - WizardControllerTest::SetUpCommandLine(command_line); - command_line->AppendSwitch(switches::kLoginManager); - command_line->AppendSwitchASCII(switches::kLoginProfile, - TestingProfile::kTestUserProfileDir); - } - - MockSupervisionTransitionScreen* mock_supervision_transition_screen_; - std::unique_ptr<MockSupervisionTransitionScreenView> - mock_supervision_transition_screen_view_; - std::unique_ptr<base::AutoReset<bool>> official_build_override_; - - private: - DISALLOW_COPY_AND_ASSIGN(WizardControllerSupervisionTransitionOobeTest); -}; - -// Tests that when supervision transition screen finishes, session -// proceeds to ACTIVE state. -IN_PROC_BROWSER_TEST_F(WizardControllerSupervisionTransitionOobeTest, - SupervisionTransitionScreenFinished) { - EXPECT_CALL(*mock_supervision_transition_screen_, Show()).Times(1); - ASSERT_NE(session_manager::SessionManager::Get()->session_state(), - session_manager::SessionState::ACTIVE); - // Start from login screen. - LoginDisplayHost::default_host()->StartSignInScreen(LoginScreenContext()); - // Advance to supervision transition screen. - WizardController::default_controller()->AdvanceToScreen( - SupervisionTransitionScreenView::kScreenId); - CheckCurrentScreen(SupervisionTransitionScreenView::kScreenId); - mock_supervision_transition_screen_->ExitScreen(); - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(session_manager::SessionManager::Get()->session_state(), - session_manager::SessionState::ACTIVE); -} - class TimeZoneTestRunner { public: void OnResolved() { loop_.Quit(); } @@ -621,7 +554,7 @@ mock_update_view_ = std::make_unique<MockUpdateView>(); mock_update_screen_ = MockScreenExpectLifecycle(std::make_unique<MockUpdateScreen>( - wizard_controller, mock_update_view_.get(), GetErrorScreen(), + mock_update_view_.get(), GetErrorScreen(), base::BindRepeating(&WizardController::OnUpdateScreenExit, base::Unretained(wizard_controller)))); @@ -787,7 +720,6 @@ EXPECT_TRUE(shelf_helper.IsLoginShelfShown()); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); // Enable TimeZone resolve InitTimezoneResolver(); @@ -878,7 +810,6 @@ IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowErrorUpdateNonCriticalUpdate) { CheckCurrentScreen(WelcomeView::kScreenId); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0); EXPECT_CALL(*mock_update_screen_, Show()).Times(0); EXPECT_CALL(*mock_network_screen_, Show()).Times(1); EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1); @@ -892,7 +823,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -919,7 +849,6 @@ IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowErrorUpdateCriticalUpdate) { CheckCurrentScreen(WelcomeView::kScreenId); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0); EXPECT_CALL(*mock_update_screen_, Show()).Times(0); EXPECT_CALL(*mock_network_screen_, Show()).Times(1); EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1); @@ -933,7 +862,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -953,7 +881,6 @@ IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowSkipUpdateEnroll) { CheckCurrentScreen(WelcomeView::kScreenId); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0); EXPECT_CALL(*mock_update_screen_, Show()).Times(0); EXPECT_CALL(*mock_network_screen_, Show()).Times(1); EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1); @@ -967,7 +894,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0); EXPECT_CALL(*mock_update_screen_, Show()).Times(0); WizardController::default_controller()->SkipUpdateEnrollAfterEula(); EXPECT_CALL(*mock_enrollment_screen_view_, @@ -1003,7 +929,7 @@ CheckCurrentScreen(NetworkScreenView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Show()).Times(1); EXPECT_CALL(*mock_network_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0); + EXPECT_CALL(*mock_update_screen_, Show()).Times(0); mock_network_screen_->ExitScreen(NetworkScreen::Result::CONNECTED); CheckCurrentScreen(EulaView::kScreenId); @@ -1017,7 +943,7 @@ IN_PROC_BROWSER_TEST_F(WizardControllerFlowTest, ControlFlowEnrollmentCompleted) { CheckCurrentScreen(WelcomeView::kScreenId); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0); + EXPECT_CALL(*mock_update_screen_, Show()).Times(0); EXPECT_CALL(*mock_enrollment_screen_view_, SetEnrollmentConfig( mock_enrollment_screen_, @@ -1075,7 +1001,6 @@ IN_PROC_BROWSER_TEST_P(WizardControllerUpdateAfterCompletedOobeTest, ControlFlowErrorUpdate) { CheckCurrentScreen(WelcomeView::kScreenId); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(0); EXPECT_CALL(*mock_update_screen_, Show()).Times(0); EXPECT_CALL(*mock_network_screen_, Show()).Times(1); EXPECT_CALL(*mock_welcome_screen_, Hide()).Times(1); @@ -1089,7 +1014,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1212,7 +1136,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1258,7 +1181,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1360,7 +1282,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1460,7 +1381,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1606,7 +1526,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1681,7 +1600,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1777,7 +1695,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1822,7 +1739,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1879,7 +1795,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -1936,7 +1851,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -2019,7 +1933,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -2172,7 +2085,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -2221,7 +2133,6 @@ CheckCurrentScreen(EulaView::kScreenId); EXPECT_CALL(*mock_eula_screen_, Hide()).Times(1); - EXPECT_CALL(*mock_update_screen_, StartNetworkCheck()).Times(1); EXPECT_CALL(*mock_update_screen_, Show()).Times(1); mock_eula_screen_->ExitScreen( EulaScreen::Result::ACCEPTED_WITHOUT_USAGE_STATS_REPORTING); @@ -2276,13 +2187,8 @@ // Find the enable debugging link element (in the appropriate shadow root), // and click it. - ASSERT_TRUE( - JSExecute("(function() {" - " var root = ['connect', 'welcomeScreen'].reduce(" - " (root, id) => root.getElementById(id).shadowRoot," - " document);" - " root.getElementById('enableDebuggingLink').click();" - "})();")); + test::OobeJS().ClickOnPath( + {"connect", "welcomeScreen", "enableDebuggingLink"}); content::RunAllPendingInMessageLoop();
diff --git a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc index 98eec5e..ece7fb0 100644 --- a/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc +++ b/chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.cc
@@ -297,8 +297,6 @@ core()->Connect(std::move(client_to_connect)); core()->StartRefreshScheduler(); core()->RefreshSoon(); - core()->StartRemoteCommandsService(std::unique_ptr<RemoteCommandsFactory>( - new DeviceCommandsFactoryChromeOS())); core()->TrackRefreshDelayPref(local_state_, prefs::kDevicePolicyRefreshRate); @@ -319,6 +317,10 @@ machine_certificate_uploader_.get())); } + // Start remote commands services now that we have setup everything they need. + core()->StartRemoteCommandsService( + std::make_unique<DeviceCommandsFactoryChromeOS>(this)); + // Enable device reporting and status monitoring for cloud managed devices. We // want to create these objects even if monitoring is currently inactive, in // case monitoring is turned back on in a future policy fetch - the classes
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_refresh_machine_certificate_job.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_refresh_machine_certificate_job.cc new file mode 100644 index 0000000..a74dd70 --- /dev/null +++ b/chrome/browser/chromeos/policy/remote_commands/device_command_refresh_machine_certificate_job.cc
@@ -0,0 +1,64 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/chromeos/policy/remote_commands/device_command_refresh_machine_certificate_job.h" + +#include <algorithm> + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/single_thread_task_runner.h" +#include "base/syslog_logging.h" +#include "base/system/sys_info.h" +#include "base/threading/thread_task_runner_handle.h" +#include "base/time/time.h" +#include "chrome/browser/chromeos/attestation/machine_certificate_uploader.h" + +namespace policy { + +DeviceCommandRefreshMachineCertificateJob:: + DeviceCommandRefreshMachineCertificateJob( + chromeos::attestation::MachineCertificateUploader* + machine_certificate_uploader) + : machine_certificate_uploader_(machine_certificate_uploader), + weak_ptr_factory_(this) {} + +DeviceCommandRefreshMachineCertificateJob:: + ~DeviceCommandRefreshMachineCertificateJob() = default; + +enterprise_management::RemoteCommand_Type +DeviceCommandRefreshMachineCertificateJob::GetType() const { + return enterprise_management:: + RemoteCommand_Type_DEVICE_REFRESH_ENTERPRISE_MACHINE_CERTIFICATE; +} + +void DeviceCommandRefreshMachineCertificateJob::RunImpl( + CallbackWithResult succeeded_callback, + CallbackWithResult failed_callback) { + if (machine_certificate_uploader_) { + SYSLOG(INFO) << "Refreshing enterprise machine certificate."; + machine_certificate_uploader_->RefreshAndUploadCertificate(base::BindOnce( + &DeviceCommandRefreshMachineCertificateJob::OnCertificateUploaded, + weak_ptr_factory_.GetWeakPtr(), std::move(succeeded_callback), + std::move(failed_callback))); + } else { + SYSLOG(WARNING) << "Machine certificate uploader unavailable," + << " certificate cannot be refreshed."; + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(std::move(failed_callback), nullptr)); + } +} + +void DeviceCommandRefreshMachineCertificateJob::OnCertificateUploaded( + CallbackWithResult succeeded_callback, + CallbackWithResult failed_callback, + bool success) { + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::BindOnce(std::move(success ? succeeded_callback : failed_callback), + nullptr)); +} + +} // namespace policy
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_refresh_machine_certificate_job.h b/chrome/browser/chromeos/policy/remote_commands/device_command_refresh_machine_certificate_job.h new file mode 100644 index 0000000..23412b9 --- /dev/null +++ b/chrome/browser/chromeos/policy/remote_commands/device_command_refresh_machine_certificate_job.h
@@ -0,0 +1,51 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_REFRESH_MACHINE_CERTIFICATE_JOB_H_ +#define CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_REFRESH_MACHINE_CERTIFICATE_JOB_H_ + +#include "base/macros.h" +#include "base/memory/weak_ptr.h" +#include "components/policy/core/common/remote_commands/remote_command_job.h" + +namespace chromeos { +namespace attestation { +class MachineCertificateUploader; +} // namespace attestation +} // namespace chromeos + +namespace policy { + +class DeviceCommandRefreshMachineCertificateJob : public RemoteCommandJob { + public: + explicit DeviceCommandRefreshMachineCertificateJob( + chromeos::attestation::MachineCertificateUploader* + machine_certificate_uploader); + ~DeviceCommandRefreshMachineCertificateJob() override; + + // RemoteCommandJob: + enterprise_management::RemoteCommand_Type GetType() const override; + + private: + chromeos::attestation::MachineCertificateUploader* + machine_certificate_uploader_; + + // RemoteCommandJob: + void RunImpl(CallbackWithResult succeeded_callback, + CallbackWithResult failed_callback) override; + + // Handle the result of a refresh and upload of the machine certificate. + void OnCertificateUploaded(CallbackWithResult succeeded_callback, + CallbackWithResult failed_callback, + bool success); + + base::WeakPtrFactory<DeviceCommandRefreshMachineCertificateJob> + weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(DeviceCommandRefreshMachineCertificateJob); +}; + +} // namespace policy + +#endif // CHROME_BROWSER_CHROMEOS_POLICY_REMOTE_COMMANDS_DEVICE_COMMAND_REFRESH_MACHINE_CERTIFICATE_JOB_H_
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job_unittest.cc b/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job_unittest.cc index 07d624c8..3d3c35f 100644 --- a/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job_unittest.cc +++ b/chrome/browser/chromeos/policy/remote_commands/device_command_wipe_users_job_unittest.cc
@@ -39,8 +39,9 @@ class TestingRemoteCommandsService : public RemoteCommandsService { public: explicit TestingRemoteCommandsService(MockCloudPolicyClient* client) - : RemoteCommandsService(std::make_unique<DeviceCommandsFactoryChromeOS>(), - client) {} + : RemoteCommandsService( + std::make_unique<DeviceCommandsFactoryChromeOS>(nullptr), + client) {} // RemoteCommandsService: void SetOnCommandAckedCallback(base::OnceClosure callback) override { on_command_acked_callback_ = std::move(callback);
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc b/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc index caf9382..6d7750f 100644 --- a/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc +++ b/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.cc
@@ -5,9 +5,11 @@ #include "chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h" #include "base/logging.h" +#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h" #include "chrome/browser/chromeos/policy/remote_commands/crd_host_delegate.h" #include "chrome/browser/chromeos/policy/remote_commands/device_command_fetch_status_job.h" #include "chrome/browser/chromeos/policy/remote_commands/device_command_reboot_job.h" +#include "chrome/browser/chromeos/policy/remote_commands/device_command_refresh_machine_certificate_job.h" #include "chrome/browser/chromeos/policy/remote_commands/device_command_screenshot_job.h" #include "chrome/browser/chromeos/policy/remote_commands/device_command_set_volume_job.h" #include "chrome/browser/chromeos/policy/remote_commands/device_command_start_crd_session_job.h" @@ -21,7 +23,9 @@ namespace policy { -DeviceCommandsFactoryChromeOS::DeviceCommandsFactoryChromeOS() = default; +DeviceCommandsFactoryChromeOS::DeviceCommandsFactoryChromeOS( + DeviceCloudPolicyManagerChromeOS* policy_manager) + : policy_manager_(policy_manager) {} DeviceCommandsFactoryChromeOS::~DeviceCommandsFactoryChromeOS() = default; @@ -44,6 +48,9 @@ return std::make_unique<DeviceCommandFetchStatusJob>(); case em::RemoteCommand_Type_DEVICE_WIPE_USERS: return std::make_unique<DeviceCommandWipeUsersJob>(service); + case em::RemoteCommand_Type_DEVICE_REFRESH_ENTERPRISE_MACHINE_CERTIFICATE: + return std::make_unique<DeviceCommandRefreshMachineCertificateJob>( + policy_manager_->GetMachineCertificateUploader()); default: // Other types of commands should be sent to UserCommandsFactoryChromeOS // instead of here.
diff --git a/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h b/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h index cb99de75..f216e007 100644 --- a/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h +++ b/chrome/browser/chromeos/policy/remote_commands/device_commands_factory_chromeos.h
@@ -13,10 +13,12 @@ namespace policy { class CRDHostDelegate; +class DeviceCloudPolicyManagerChromeOS; class DeviceCommandsFactoryChromeOS : public RemoteCommandsFactory { public: - DeviceCommandsFactoryChromeOS(); + explicit DeviceCommandsFactoryChromeOS( + DeviceCloudPolicyManagerChromeOS* policy_manager); ~DeviceCommandsFactoryChromeOS() override; // RemoteCommandsFactory: @@ -25,6 +27,7 @@ RemoteCommandsService* service) override; private: + DeviceCloudPolicyManagerChromeOS* policy_manager_; std::unique_ptr<CRDHostDelegate> crd_host_delegate_; CRDHostDelegate* GetCRDHostDelegate();
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc index ed266b4f..39a332f 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_manager.cc +++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.cc
@@ -360,11 +360,6 @@ const MediaSinkInternal* sink = media_sink_service_->GetSinkByRoute(route); CHECK(sink); - for (auto& client : activity->connected_clients()) { - client.second->SendMessageToClient( - CreateReceiverActionStopMessage(client.first, *sink, hash_token_)); - } - activity->SendStopSessionMessageToReceiver( base::nullopt, // TODO(jrw): Get the real client ID. hash_token_, std::move(callback));
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_manager.h b/chrome/browser/media/router/providers/cast/cast_activity_manager.h index 8fc7398..4da79f90 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_manager.h +++ b/chrome/browser/media/router/providers/cast/cast_activity_manager.h
@@ -19,7 +19,6 @@ #include "chrome/browser/media/router/providers/cast/cast_session_tracker.h" #include "chrome/common/media_router/mojo/media_router.mojom.h" #include "chrome/common/media_router/providers/cast/cast_media_source.h" -#include "mojo/public/cpp/bindings/binding.h" #include "url/origin.h" namespace cast_channel {
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_record.h b/chrome/browser/media/router/providers/cast/cast_activity_record.h index 80292dd..369a9a8c 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_record.h +++ b/chrome/browser/media/router/providers/cast/cast_activity_record.h
@@ -45,9 +45,11 @@ const MediaRoute& route() const { return route_; } const std::string& app_id() const { return app_id_; } - const ClientMap& connected_clients() const { return connected_clients_; } const base::Optional<std::string>& session_id() const { return session_id_; } + // TODO(jrw): Get rid of this accessor. + const ClientMap& connected_clients() const { return connected_clients_; } + // Sends app message |cast_message|, which came from the SDK client, to the // receiver hosting this session. Returns true if the message is sent // successfully.
diff --git a/chrome/browser/media/router/providers/cast/cast_activity_record_unittest.cc b/chrome/browser/media/router/providers/cast/cast_activity_record_unittest.cc index f8bb4bc..fe1584b 100644 --- a/chrome/browser/media/router/providers/cast/cast_activity_record_unittest.cc +++ b/chrome/browser/media/router/providers/cast/cast_activity_record_unittest.cc
@@ -5,7 +5,6 @@ #include "chrome/browser/media/router/providers/cast/cast_activity_record.h" #include <memory> -#include <sstream> #include <string> #include <tuple> #include <utility>
diff --git a/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc b/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc index 4af4556..189883d 100644 --- a/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc +++ b/chrome/browser/media/router/providers/cast/cast_internal_message_util.cc
@@ -16,12 +16,11 @@ #include "chrome/common/media_router/providers/cast/cast_media_source.h" #include "components/cast_channel/cast_socket.h" #include "components/cast_channel/enum_table.h" -#include "components/cast_channel/proto/cast_channel.pb.h" #include "net/base/escape.h" namespace cast_util { -using namespace media_router; +using media_router::CastInternalMessage; template <> const EnumTable<CastInternalMessage::Type>
diff --git a/chrome/browser/media/router/providers/cast/cast_session_client.cc b/chrome/browser/media/router/providers/cast/cast_session_client.cc index 3b80b5b..3d9397b64 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_client.cc +++ b/chrome/browser/media/router/providers/cast/cast_session_client.cc
@@ -2,10 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// #include "chrome/common/media_router/mojo/media_router.mojom.h" #include "chrome/browser/media/router/providers/cast/cast_session_client.h" #include "base/bind.h" +#include "base/logging.h" #include "chrome/browser/media/router/data_decoder_util.h" #include "chrome/browser/media/router/providers/cast/cast_activity_record.h" #include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h" @@ -23,9 +23,9 @@ void ReportClientMessageParseError(const MediaRoute::Id& route_id, const std::string& error) { - // TODO(crbug.com/808720): Record UMA metric for parse result. - DVLOG(2) << "Failed to parse Cast client message for " << route_id << ": " - << error; + // TODO(crbug.com/905002): Record UMA metric for parse result. + DLOG(ERROR) << "Failed to parse Cast client message for " << route_id << ": " + << error; } } // namespace @@ -143,7 +143,6 @@ if (!cast_message) { ReportClientMessageParseError(activity_->route().media_route_id(), "Not a Cast message"); - DLOG(ERROR) << "Received non-Cast message from client"; return; }
diff --git a/chrome/browser/media/router/providers/cast/cast_session_client_unittest.cc b/chrome/browser/media/router/providers/cast/cast_session_client_unittest.cc index 3f67a4bc..e2f518f 100644 --- a/chrome/browser/media/router/providers/cast/cast_session_client_unittest.cc +++ b/chrome/browser/media/router/providers/cast/cast_session_client_unittest.cc
@@ -27,12 +27,10 @@ #include "components/cast_channel/cast_test_util.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/test/test_browser_thread_bundle.h" -// #include "services/data_decoder/data_decoder_service.h" #include "services/data_decoder/public/cpp/testing_json_parser.h" -// #include "services/data_decoder/public/mojom/constants.mojom.h" #include "services/service_manager/public/cpp/test/test_connector_factory.h" -// #include "testing/gmock/include/gmock/gmock.h" -// #include "testing/gtest/include/gtest/gtest.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" using base::test::IsJson; using base::test::ParseJson; @@ -81,6 +79,15 @@ protected: void RunUntilIdle() { thread_bundle_.RunUntilIdle(); } + template <typename T> + void ExpectErrorLog(const T& matcher) { + if (DLOG_IS_ON(ERROR)) { + EXPECT_CALL(log_, Log(logging::LOG_ERROR, _, _, _, + matcher)) + .WillOnce(Return(true)); // suppress logging + } + } + content::TestBrowserThreadBundle thread_bundle_; data_decoder::TestingJsonParser::ScopedFactoryOverride parser_override_; service_manager::TestConnectorFactory connector_factory_; @@ -107,9 +114,7 @@ TEST_F(CastSessionClientImplTest, OnInvalidJson) { // TODO(crbug.com/905002): Check UMA calls instead of logging (here and // below). - EXPECT_CALL(log_, Log(logging::LOG_ERROR, _, _, _, - HasSubstr("Failed to parse Cast client message"))) - .WillOnce(Return(true)); // suppress logging + ExpectErrorLog(HasSubstr("Failed to parse Cast client message")); log_.StartCapturingLogs(); client_->OnMessage( @@ -117,10 +122,8 @@ } TEST_F(CastSessionClientImplTest, OnInvalidMessage) { - EXPECT_CALL(log_, Log(logging::LOG_ERROR, _, _, _, - AllOf(HasSubstr("Failed to parse Cast client message"), - HasSubstr("Not a Cast message")))) - .WillOnce(Return(true)); // suppress logging + ExpectErrorLog(AllOf(HasSubstr("Failed to parse Cast client message"), + HasSubstr("Not a Cast message"))); log_.StartCapturingLogs(); client_->OnMessage( @@ -128,11 +131,9 @@ } TEST_F(CastSessionClientImplTest, OnMessageWrongClientId) { - EXPECT_CALL( - log_, Log(logging::LOG_ERROR, _, _, _, - AllOf(HasSubstr("Client ID mismatch"), HasSubstr("theClientId"), - HasSubstr("theWrongClientId")))) - .WillOnce(Return(true)); // suppress logging + ExpectErrorLog(AllOf(HasSubstr("Client ID mismatch"), + HasSubstr("theClientId"), + HasSubstr("theWrongClientId"))); log_.StartCapturingLogs(); client_->OnMessage( @@ -147,11 +148,9 @@ } TEST_F(CastSessionClientImplTest, OnMessageWrongSessionId) { - EXPECT_CALL(log_, Log(logging::LOG_ERROR, _, _, _, - AllOf(HasSubstr("Session ID mismatch"), - HasSubstr("theSessionId"), - HasSubstr("theWrongSessionId")))) - .WillOnce(Return(true)); // suppress logging + ExpectErrorLog(AllOf(HasSubstr("Session ID mismatch"), + HasSubstr("theSessionId"), + HasSubstr("theWrongSessionId"))); log_.StartCapturingLogs(); client_->OnMessage( @@ -183,16 +182,21 @@ } TEST_F(CastSessionClientImplTest, OnMediaStatusUpdatedWithPendingRequest) { - EXPECT_CALL(activity_, SendMediaRequestToReceiver(IsCastInternalMessage(R"({ - "type": "v2_message", - "clientId": "theClientId", - "sequenceNumber": 123, - "message": { - "sessionId": "theSessionId", - "type": "MEDIA_GET_STATUS" - } - })"))) - .WillOnce(Return(345)); + EXPECT_CALL(activity_, SendMediaRequestToReceiver) + .WillOnce([](const auto& message) { + // TODO(crbug.com/961081): Use IsCastInternalMessage as argument to + // SendSetVolumeRequestToReceiver when bug is fixed. + EXPECT_THAT(message, IsCastInternalMessage(R"({ + "type": "v2_message", + "clientId": "theClientId", + "sequenceNumber": 123, + "message": { + "sessionId": "theSessionId", + "type": "MEDIA_GET_STATUS" + } + })")); + return 345; + }); client_->OnMessage( blink::mojom::PresentationConnectionMessage::NewMessage(R"({ "type": "v2_message", @@ -215,20 +219,21 @@ } TEST_F(CastSessionClientImplTest, SendSetVolumeCommandToReceiver) { - EXPECT_CALL(activity_, - SendSetVolumeRequestToReceiver(IsCastInternalMessage(R"({ - "type": "v2_message", - "clientId": "theClientId", - "sequenceNumber": 123, - "message": { - "sessionId": "theSessionId", - "type": "SET_VOLUME" - } - })"), - _)) - .WillOnce(WithArg<1>([](auto callback) { + EXPECT_CALL(activity_, SendSetVolumeRequestToReceiver) + .WillOnce([](const auto& message, auto callback) { + // TODO(crbug.com/961081): Use IsCastInternalMessage as argument to + // SendSetVolumeRequestToReceiver when bug is fixed. + EXPECT_THAT(message, IsCastInternalMessage(R"({ + "type": "v2_message", + "clientId": "theClientId", + "sequenceNumber": 123, + "message": { + "sessionId": "theSessionId", + "type": "SET_VOLUME" + } + })")); std::move(callback).Run(cast_channel::Result::kOk); - })); + }); EXPECT_CALL(*mock_connection_, OnMessage(IsCastMessage(R"({ "clientId": "theClientId", "message": null,
diff --git a/chrome/browser/media/router/providers/cast/mock_cast_activity_record.h b/chrome/browser/media/router/providers/cast/mock_cast_activity_record.h index add10966..db0edcc2 100644 --- a/chrome/browser/media/router/providers/cast/mock_cast_activity_record.h +++ b/chrome/browser/media/router/providers/cast/mock_cast_activity_record.h
@@ -5,7 +5,10 @@ #ifndef CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_CAST_MOCK_CAST_ACTIVITY_RECORD_H_ #define CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_CAST_MOCK_CAST_ACTIVITY_RECORD_H_ +#include <string> + #include "chrome/browser/media/router/providers/cast/cast_activity_record.h" +#include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h" #include "chrome/browser/media/router/providers/cast/cast_session_client.h" #include "testing/gmock/include/gmock/gmock.h"
diff --git a/chrome/browser/media/router/providers/cast/test_util.cc b/chrome/browser/media/router/providers/cast/test_util.cc new file mode 100644 index 0000000..500fb2f --- /dev/null +++ b/chrome/browser/media/router/providers/cast/test_util.cc
@@ -0,0 +1,41 @@ +// Copyright 2019 The Chromium 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/media/router/providers/cast/test_util.h" + +#include "components/cast_channel/enum_table.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace media_router { + +std::ostream& operator<<(std::ostream& out, CastInternalMessage::Type type) { + return out << cast_util::EnumToString(type).value_or("<invalid>"); +} + +std::ostream& operator<<(std::ostream& out, + const CastInternalMessage& message) { + out << "{type=" << message.type() << ", client_id=" << message.client_id(); + if (message.sequence_number()) { + out << ", sequence_number=" << *message.sequence_number(); + } + if (message.has_session_id()) { + out << ", session_id=" << message.session_id(); + } + + switch (message.type()) { + case CastInternalMessage::Type::kAppMessage: + out << ", app_message_namespace=" << message.app_message_namespace() + << ", app_message_body=" << message.app_message_body(); + break; + case CastInternalMessage::Type::kV2Message: + out << ", v2_message_type=" << message.v2_message_type() + << ", v2_message_body=" << message.v2_message_body(); + break; + default: + break; + } + return out << "}"; +} + +} // namespace media_router
diff --git a/chrome/browser/media/router/providers/cast/test_util.h b/chrome/browser/media/router/providers/cast/test_util.h new file mode 100644 index 0000000..d9954ca5 --- /dev/null +++ b/chrome/browser/media/router/providers/cast/test_util.h
@@ -0,0 +1,47 @@ +// Copyright 2019 The Chromium 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_MEDIA_ROUTER_PROVIDERS_CAST_TEST_UTIL_H_ +#define CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_CAST_TEST_UTIL_H_ + +#include <iosfwd> + +#include "base/test/values_test_util.h" +#include "chrome/browser/media/router/providers/cast/cast_internal_message_util.h" +#include "testing/gmock/include/gmock/gmock.h" + +namespace media_router { + +std::ostream& operator<<(std::ostream&, CastInternalMessage::Type); +std::ostream& operator<<(std::ostream&, const CastInternalMessage&); + +// Matcher for CastInternalMessage arguments. +MATCHER_P(IsCastInternalMessage, json, "") { + auto message = CastInternalMessage::From(base::test::ParseJson(json)); + DCHECK(message); + if (arg.type() != message->type() || + arg.client_id() != message->client_id() || + arg.sequence_number() != message->sequence_number()) { + return false; + } + + if (arg.has_session_id() && arg.session_id() != message->session_id()) + return false; + + switch (arg.type()) { + case CastInternalMessage::Type::kAppMessage: + return arg.app_message_namespace() == message->app_message_namespace() && + arg.app_message_body() == message->app_message_body(); + case CastInternalMessage::Type::kV2Message: + return arg.v2_message_type() == message->v2_message_type() && + testing::Matches(base::test::IsJson(arg.v2_message_body()))( + message->v2_message_body()); + default: + return true; + } +} + +} // namespace media_router + +#endif // CHROME_BROWSER_MEDIA_ROUTER_PROVIDERS_CAST_TEST_UTIL_H_
diff --git a/chrome/browser/media/router/test/test_helper.h b/chrome/browser/media/router/test/test_helper.h index 7873af0..7b259a5 100644 --- a/chrome/browser/media/router/test/test_helper.h +++ b/chrome/browser/media/router/test/test_helper.h
@@ -5,20 +5,15 @@ #ifndef CHROME_BROWSER_MEDIA_ROUTER_TEST_TEST_HELPER_H_ #define CHROME_BROWSER_MEDIA_ROUTER_TEST_TEST_HELPER_H_ -#include <stddef.h> -#include <stdint.h> - #include <string> #include <vector> #include "base/macros.h" #include "base/test/values_test_util.h" -#include "build/build_config.h" #include "chrome/browser/media/router/issue_manager.h" #include "chrome/browser/media/router/issues_observer.h" #include "chrome/browser/media/router/media_routes_observer.h" #include "chrome/browser/media/router/media_sinks_observer.h" -#include "content/public/browser/presentation_service_delegate.h" #include "testing/gmock/include/gmock/gmock.h" #include "third_party/blink/public/mojom/presentation/presentation.mojom.h" @@ -230,6 +225,8 @@ #endif // !defined(OS_ANDROID) +// Matcher for blink::mojom::PresentationConnectionMessagePtr arguments. +// TODO(jrw): Rename to something like IsPresentationConnectionMessage. MATCHER_P(IsCastMessage, json, "") { return arg->is_message() && base::test::IsJsonMatcher(json).MatchAndExplain( arg->get_message(), result_listener);
diff --git a/chrome/browser/offline_pages/background_loader_offliner.cc b/chrome/browser/offline_pages/background_loader_offliner.cc index 062759f707e..2abdfbac 100644 --- a/chrome/browser/offline_pages/background_loader_offliner.cc +++ b/chrome/browser/offline_pages/background_loader_offliner.cc
@@ -4,7 +4,9 @@ #include "chrome/browser/offline_pages/background_loader_offliner.h" +#include <string> #include <utility> +#include <vector> #include "base/bind.h" #include "base/json/json_writer.h" @@ -19,6 +21,7 @@ #include "chrome/browser/offline_pages/offliner_user_data.h" #include "chrome/browser/previews/previews_ui_tab_helper.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ssl/security_state_tab_helper.h" #include "chrome/common/chrome_isolated_world_ids.h" #include "components/data_reduction_proxy/core/browser/data_reduction_proxy_data.h" #include "components/offline_pages/content/renovations/render_frame_script_injector.h" @@ -30,13 +33,16 @@ #include "components/offline_pages/core/renovations/page_renovation_loader.h" #include "components/offline_pages/core/renovations/page_renovator.h" #include "components/previews/content/previews_user_data.h" +#include "components/security_state/core/security_state.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/mhtml_extra_parts.h" +#include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_handle.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_user_data.h" #include "content/public/common/previews_state.h" +#include "net/cert/cert_status_flags.h" #include "net/http/http_response_headers.h" namespace offline_pages { @@ -228,7 +234,8 @@ loader_.get()->LoadPage(request.url()); snapshot_controller_ = std::make_unique<BackgroundSnapshotController>( - base::ThreadTaskRunnerHandle::Get(), this, (bool)page_renovator_); + base::ThreadTaskRunnerHandle::Get(), this, + static_cast<bool>(page_renovator_)); return true; } @@ -430,6 +437,8 @@ DVLOG(1) << "Pending request was cleared during delay."; return; } + DCHECK(is_low_bar_met_) + << "Minimum quality must have been reached before saving a snapshot"; // Add this signal to signal_data_. AddLoadingSignal("Snapshotting"); @@ -459,10 +468,19 @@ return; } - save_state_ = SAVING; content::WebContents* web_contents( content::WebContentsObserver::web_contents()); + Offliner::RequestStatus loaded_page_error = + CanSavePageInBackground(web_contents); + if (loaded_page_error != Offliner::RequestStatus::UNKNOWN) { + std::move(completion_callback_).Run(request, loaded_page_error); + ResetState(); + return; + } + + save_state_ = SAVING; + // Capture loading signals to UMA. RequestStats& image_stats = stats_[ResourceDataType::IMAGE]; RequestStats& css_stats = stats_[ResourceDataType::TEXT_CSS]; @@ -627,4 +645,46 @@ snapshot_controller_->RenovationsCompleted(); } +Offliner::RequestStatus BackgroundLoaderOffliner::CanSavePageInBackground( + content::WebContents* web_contents) { + DCHECK(is_low_bar_met_) + << "Minimum quality must have been reached before checking loaded page"; + std::unique_ptr<security_state::VisibleSecurityState> visible_security_state = + GetVisibleSecurityState(web_contents); + // Checks for HTTPS certificate errors (HTTP connections are not affected). + if (security_state::HasMajorCertificateError(*visible_security_state)) + return Offliner::RequestStatus::LOADED_PAGE_HAS_CERTIFICATE_ERROR; + + // Checks if the page is blocked by SafeBrowsing. + if (visible_security_state->malicious_content_status != + security_state::MaliciousContentStatus::MALICIOUS_CONTENT_STATUS_NONE) { + return Offliner::RequestStatus::LOADED_PAGE_IS_BLOCKED; + } + + // Don't save Chrome error or interstitial pages. + if (GetPageType(web_contents) != content::PageType::PAGE_TYPE_NORMAL) + return Offliner::RequestStatus::LOADED_PAGE_IS_CHROME_INTERNAL; + + return Offliner::RequestStatus::UNKNOWN; +} + +std::unique_ptr<security_state::VisibleSecurityState> +BackgroundLoaderOffliner::GetVisibleSecurityState( + content::WebContents* web_contents) { + // Note: this tab helper needs to be created here as in the background it is + // not created by default. + SecurityStateTabHelper::CreateForWebContents(web_contents); + SecurityStateTabHelper* helper = + SecurityStateTabHelper::FromWebContents(web_contents); + DCHECK(helper); + return helper->GetVisibleSecurityState(); +} + +content::PageType BackgroundLoaderOffliner::GetPageType( + content::WebContents* web_contents) { + DCHECK(web_contents->GetController().GetVisibleEntry()) + << "An entry must have committed at this WebContents"; + return web_contents->GetController().GetVisibleEntry()->GetPageType(); +} + } // namespace offline_pages
diff --git a/chrome/browser/offline_pages/background_loader_offliner.h b/chrome/browser/offline_pages/background_loader_offliner.h index a05a6b6..bd9aa65 100644 --- a/chrome/browser/offline_pages/background_loader_offliner.h +++ b/chrome/browser/offline_pages/background_loader_offliner.h
@@ -16,16 +16,20 @@ #include "components/offline_pages/core/background_snapshot_controller.h" #include "components/offline_pages/core/offline_page_types.h" #include "content/public/browser/web_contents_observer.h" +#include "content/public/common/page_type.h" namespace content { class BrowserContext; } // namespace content +namespace security_state { +struct VisibleSecurityState; +} // namespace security_state + namespace offline_pages { class OfflinerPolicy; class OfflinePageModel; - class PageRenovationLoader; class PageRenovator; @@ -90,10 +94,6 @@ bool started) override; void OnNetworkBytesChanged(int64_t bytes) override; - protected: - // Called to reset the loader. - virtual void ResetLoader(); - private: friend class TestBackgroundLoaderOffliner; friend class BackgroundLoaderOfflinerTest; @@ -127,9 +127,28 @@ void DeleteOfflinePageCallback(const SavePageRequest& request, DeletePageResult result); + // Checks whether the loaded page can be saved in the background based on its + // security information and other characteristics. Returns the respective + // RequestStatus value for any specific error or RequestStatus::UNKNOWN + // otherwise. + Offliner::RequestStatus CanSavePageInBackground( + content::WebContents* web_contents); + // Testing method to examine resource stats. RequestStats* GetRequestStatsForTest() { return stats_; } + // Called to reset the loader. Overridden in tests. + virtual void ResetLoader(); + + // Returns the VisibleSecurityState for the page currently loaded by the + // provided WebContents. Overridden in tests. + virtual std::unique_ptr<security_state::VisibleSecurityState> + GetVisibleSecurityState(content::WebContents* web_contents); + + // Returns PageType for the page currently loaded by the provided WebContents. + // Overridden in tests. + virtual content::PageType GetPageType(content::WebContents* web_contents); + std::unique_ptr<background_loader::BackgroundLoaderContents> loader_; // Not owned. content::BrowserContext* browser_context_;
diff --git a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc index cdd299a1..149f057 100644 --- a/chrome/browser/offline_pages/background_loader_offliner_unittest.cc +++ b/chrome/browser/offline_pages/background_loader_offliner_unittest.cc
@@ -4,6 +4,9 @@ #include "chrome/browser/offline_pages/background_loader_offliner.h" +#include <utility> +#include <vector> + #include "base/bind.h" #include "base/command_line.h" #include "base/run_loop.h" @@ -26,6 +29,7 @@ #include "components/offline_pages/core/stub_offline_page_model.h" #include "components/prefs/pref_service.h" #include "components/previews/content/previews_user_data.h" +#include "components/security_state/core/security_state.h" #include "content/public/browser/mhtml_extra_parts.h" #include "content/public/browser/web_contents.h" #include "content/public/test/mock_navigation_handle.h" @@ -34,6 +38,8 @@ #include "content/public/test/web_contents_tester.h" #include "net/base/net_errors.h" #include "net/http/http_response_headers.h" +#include "net/test/cert_test_util.h" +#include "net/test/test_data_directory.h" #include "testing/gtest/include/gtest/gtest.h" namespace { @@ -45,8 +51,11 @@ namespace { +using security_state::VisibleSecurityState; + const int64_t kRequestId = 7; const GURL kHttpUrl("http://www.tunafish.com"); +const GURL kHttpsUrl("https://www.yellowtail.com"); const GURL kFileUrl("file://salmon.png"); const ClientId kClientId("async_loading", "88"); const bool kUserRequested = true; @@ -147,11 +156,22 @@ bool is_loading() { return loader_ && stub_->is_loading(); } - protected: - void ResetLoader() override; + void set_custom_visible_security_state( + std::unique_ptr<VisibleSecurityState> visible_security_state) { + custom_visible_security_state_ = std::move(visible_security_state); + } + void set_page_type(content::PageType page_type) { page_type_ = page_type; } private: + // BackgroundLoaderOffliner overrides. + void ResetLoader() override; + std::unique_ptr<VisibleSecurityState> GetVisibleSecurityState( + content::WebContents* web_contents) override; + content::PageType GetPageType(content::WebContents* web_contents) override; + background_loader::BackgroundLoaderContentsStub* stub_; + std::unique_ptr<VisibleSecurityState> custom_visible_security_state_; + content::PageType page_type_ = content::PageType::PAGE_TYPE_NORMAL; }; TestBackgroundLoaderOffliner::TestBackgroundLoaderOffliner( @@ -172,6 +192,19 @@ loader_->SetDelegate(this); } +std::unique_ptr<VisibleSecurityState> +TestBackgroundLoaderOffliner::GetVisibleSecurityState( + content::WebContents* web_contents) { + if (custom_visible_security_state_) + return std::move(custom_visible_security_state_); + return BackgroundLoaderOffliner::GetVisibleSecurityState(web_contents); +} + +content::PageType TestBackgroundLoaderOffliner::GetPageType( + content::WebContents* web_contents) { + return page_type_; +} + class BackgroundLoaderOfflinerTest : public testing::Test { public: BackgroundLoaderOfflinerTest(); @@ -223,6 +256,7 @@ offliner_->SetBackgroundSnapshotControllerForTest( std::move(snapshot_controller)); // Call complete loading. + offliner()->DocumentAvailableInMainFrame(); offliner()->DocumentOnLoadCompletedInMainFrame(); PumpLoop(); } @@ -231,6 +265,17 @@ return offliner_->GetRequestStatsForTest(); } + std::unique_ptr<VisibleSecurityState> BaseVisibleSecurityState() { + auto visible_security_state = std::make_unique<VisibleSecurityState>(); + visible_security_state->connection_info_initialized = true; + visible_security_state->url = kHttpsUrl; + visible_security_state->certificate = + net::ImportCertFromFile(net::GetTestCertsDirectory(), "sha1_2016.pem"); + visible_security_state->cert_status = + net::CERT_STATUS_SHA1_SIGNATURE_PRESENT; + return visible_security_state; + } + private: void OnCompletion(const SavePageRequest& request, Offliner::RequestStatus status); @@ -615,6 +660,144 @@ request_status()); } +TEST_F(BackgroundLoaderOfflinerTest, FailsOnCertificateError) { + base::Time creation_time = base::Time::Now(); + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, + kUserRequested); + EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(), + progress_callback())); + + // Sets the certificate status as having been revoked. + std::unique_ptr<VisibleSecurityState> visible_security_state = + BaseVisibleSecurityState(); + visible_security_state->cert_status |= net::CERT_STATUS_REVOKED; + offliner()->set_custom_visible_security_state( + std::move(visible_security_state)); + + // Called after calling LoadAndSave so we have web_contents to work with. + content::MockNavigationHandle handle( + kHttpUrl, offliner()->web_contents()->GetMainFrame()); + handle.set_has_committed(true); + offliner()->DidFinishNavigation(&handle); + + CompleteLoading(); + PumpLoop(); + + EXPECT_FALSE(SaveInProgress()); + EXPECT_TRUE(completion_callback_called()); + EXPECT_EQ(Offliner::RequestStatus::LOADED_PAGE_HAS_CERTIFICATE_ERROR, + request_status()); +} + +TEST_F(BackgroundLoaderOfflinerTest, SucceedsOnMinorCertificateError) { + base::Time creation_time = base::Time::Now(); + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, + kUserRequested); + EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(), + progress_callback())); + + // Sets a minor certificate error that should be acceptable. + std::unique_ptr<VisibleSecurityState> visible_security_state = + BaseVisibleSecurityState(); + visible_security_state->cert_status |= + net::CERT_STATUS_NO_REVOCATION_MECHANISM; + offliner()->set_custom_visible_security_state( + std::move(visible_security_state)); + + // Called after calling LoadAndSave so we have web_contents to work with. + content::MockNavigationHandle handle( + kHttpUrl, offliner()->web_contents()->GetMainFrame()); + handle.set_has_committed(true); + offliner()->DidFinishNavigation(&handle); + + CompleteLoading(); + PumpLoop(); + + EXPECT_TRUE(SaveInProgress()); + EXPECT_FALSE(completion_callback_called()); +} + +TEST_F(BackgroundLoaderOfflinerTest, SucceedsOnHttp) { + base::Time creation_time = base::Time::Now(); + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, + kUserRequested); + EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(), + progress_callback())); + + // Sets the URL to HTTP while still setting a major certificate error (should + // be ignored). + std::unique_ptr<VisibleSecurityState> visible_security_state = + BaseVisibleSecurityState(); + visible_security_state->url = kHttpUrl; + visible_security_state->cert_status |= net::CERT_STATUS_REVOKED; + offliner()->set_custom_visible_security_state( + std::move(visible_security_state)); + + // Called after calling LoadAndSave so we have web_contents to work with. + content::MockNavigationHandle handle( + kHttpUrl, offliner()->web_contents()->GetMainFrame()); + handle.set_has_committed(true); + offliner()->DidFinishNavigation(&handle); + + CompleteLoading(); + PumpLoop(); + + EXPECT_TRUE(SaveInProgress()); + EXPECT_FALSE(completion_callback_called()); +} + +TEST_F(BackgroundLoaderOfflinerTest, FailsOnUnwantedContent) { + base::Time creation_time = base::Time::Now(); + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, + kUserRequested); + EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(), + progress_callback())); + + // Sets the page as containing SafeBrowsing unwanted content. + std::unique_ptr<VisibleSecurityState> visible_security_state = + BaseVisibleSecurityState(); + visible_security_state->malicious_content_status = security_state:: + MaliciousContentStatus::MALICIOUS_CONTENT_STATUS_SOCIAL_ENGINEERING; + offliner()->set_custom_visible_security_state( + std::move(visible_security_state)); + // Called after calling LoadAndSave so we have web_contents to work with. + content::MockNavigationHandle handle( + kHttpUrl, offliner()->web_contents()->GetMainFrame()); + handle.set_has_committed(true); + offliner()->DidFinishNavigation(&handle); + + CompleteLoading(); + PumpLoop(); + + EXPECT_FALSE(SaveInProgress()); + EXPECT_TRUE(completion_callback_called()); + EXPECT_EQ(Offliner::RequestStatus::LOADED_PAGE_IS_BLOCKED, request_status()); +} + +TEST_F(BackgroundLoaderOfflinerTest, FailsOnInterstitialPage) { + base::Time creation_time = base::Time::Now(); + SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time, + kUserRequested); + EXPECT_TRUE(offliner()->LoadAndSave(request, completion_callback(), + progress_callback())); + + // Sets the page as being an interstitial. + offliner()->set_page_type(content::PageType::PAGE_TYPE_INTERSTITIAL); + // Called after calling LoadAndSave so we have web_contents to work with. + content::MockNavigationHandle handle( + kHttpUrl, offliner()->web_contents()->GetMainFrame()); + handle.set_has_committed(true); + offliner()->DidFinishNavigation(&handle); + + CompleteLoading(); + PumpLoop(); + + EXPECT_FALSE(SaveInProgress()); + EXPECT_TRUE(completion_callback_called()); + EXPECT_EQ(Offliner::RequestStatus::LOADED_PAGE_IS_CHROME_INTERNAL, + request_status()); +} + TEST_F(BackgroundLoaderOfflinerTest, FailsOnInternetDisconnected) { base::Time creation_time = base::Time::Now(); SavePageRequest request(kRequestId, kHttpUrl, kClientId, creation_time,
diff --git a/chrome/browser/offline_pages/offline_page_mhtml_archiver.cc b/chrome/browser/offline_pages/offline_page_mhtml_archiver.cc index 4077f4fd..d91d9ad 100644 --- a/chrome/browser/offline_pages/offline_page_mhtml_archiver.cc +++ b/chrome/browser/offline_pages/offline_page_mhtml_archiver.cc
@@ -18,14 +18,11 @@ #include "base/task/post_task.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/offline_pages/offline_page_utils.h" -#include "chrome/browser/ssl/security_state_tab_helper.h" #include "components/offline_pages/core/archive_validator.h" #include "components/offline_pages/core/model/offline_page_model_utils.h" #include "components/offline_pages/core/offline_clock.h" #include "components/offline_pages/core/offline_page_feature.h" -#include "components/security_state/core/security_state.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/navigation_entry.h" #include "content/public/browser/web_contents.h" #include "content/public/common/mhtml_generation_params.h" #include "net/base/filename_util.h" @@ -70,26 +67,6 @@ DCHECK(!callback.is_null()); callback_ = std::move(callback); - // TODO(chili): crbug/710248 These checks should probably be done inside - // the offliner. - if (HasConnectionSecurityError(web_contents)) { - ReportFailure(ArchiverResult::ERROR_SECURITY_CERTIFICATE); - return; - } - - // Don't save chrome error pages. - if (GetPageType(web_contents) == content::PageType::PAGE_TYPE_ERROR) { - ReportFailure(ArchiverResult::ERROR_ERROR_PAGE); - return; - } - - // Don't save chrome-injected interstitial info pages - // i.e. "This site may be dangerous. Are you sure you want to continue?" - if (GetPageType(web_contents) == content::PageType::PAGE_TYPE_INTERSTITIAL) { - ReportFailure(ArchiverResult::ERROR_INTERSTITIAL_PAGE); - return; - } - GenerateMHTML(archives_dir, web_contents, create_archive_params); } @@ -184,20 +161,6 @@ url, file_path, title, file_size, digest)); } -bool OfflinePageMHTMLArchiver::HasConnectionSecurityError( - content::WebContents* web_contents) { - SecurityStateTabHelper::CreateForWebContents(web_contents); - SecurityStateTabHelper* helper = - SecurityStateTabHelper::FromWebContents(web_contents); - DCHECK(helper); - return security_state::SecurityLevel::DANGEROUS == helper->GetSecurityLevel(); -} - -content::PageType OfflinePageMHTMLArchiver::GetPageType( - content::WebContents* web_contents) { - return web_contents->GetController().GetVisibleEntry()->GetPageType(); -} - void OfflinePageMHTMLArchiver::DeleteFileAndReportFailure( const base::FilePath& file_path, ArchiverResult result) {
diff --git a/chrome/browser/offline_pages/offline_page_mhtml_archiver.h b/chrome/browser/offline_pages/offline_page_mhtml_archiver.h index e4ddabe..3afe6bf0 100644 --- a/chrome/browser/offline_pages/offline_page_mhtml_archiver.h +++ b/chrome/browser/offline_pages/offline_page_mhtml_archiver.h
@@ -16,7 +16,6 @@ #include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "components/offline_pages/core/offline_page_archiver.h" -#include "content/public/common/page_type.h" namespace base { class FilePath; @@ -77,14 +76,6 @@ int64_t file_size, const std::string& digest); - // Checks whether the page to be saved has security error when loaded over - // HTTPS. Saving a page will fail if that is the case. HTTP connections are - // not affected. - virtual bool HasConnectionSecurityError(content::WebContents* web_contents); - - // Returns the page type of the page being saved. - virtual content::PageType GetPageType(content::WebContents* web_contents); - // Reports failure to create archive a page to the client that requested it. void ReportFailure(ArchiverResult result);
diff --git a/chrome/browser/offline_pages/offline_page_mhtml_archiver_unittest.cc b/chrome/browser/offline_pages/offline_page_mhtml_archiver_unittest.cc index ca63cce5..b9c0de2 100644 --- a/chrome/browser/offline_pages/offline_page_mhtml_archiver_unittest.cc +++ b/chrome/browser/offline_pages/offline_page_mhtml_archiver_unittest.cc
@@ -53,9 +53,6 @@ SUCCESS, NOT_ABLE_TO_ARCHIVE, WEB_CONTENTS_MISSING, - CONNECTION_SECURITY_ERROR, - ERROR_PAGE, - INTERSTITIAL_PAGE, }; TestMHTMLArchiver(const GURL& url, @@ -67,8 +64,6 @@ void GenerateMHTML(const base::FilePath& archives_dir, content::WebContents* web_contents, const CreateArchiveParams& create_archive_params) override; - bool HasConnectionSecurityError(content::WebContents* web_contents) override; - content::PageType GetPageType(content::WebContents* web_contents) override; const GURL url_; const TestScenario test_scenario_; @@ -112,20 +107,6 @@ clock_->Advance(kTimeToSaveMhtml); } -bool TestMHTMLArchiver::HasConnectionSecurityError( - content::WebContents* web_contents) { - return test_scenario_ == TestScenario::CONNECTION_SECURITY_ERROR; -} - -content::PageType TestMHTMLArchiver::GetPageType( - content::WebContents* web_contents) { - if (test_scenario_ == TestScenario::ERROR_PAGE) - return content::PageType::PAGE_TYPE_ERROR; - if (test_scenario_ == TestScenario::INTERSTITIAL_PAGE) - return content::PageType::PAGE_TYPE_INTERSTITIAL; - return content::PageType::PAGE_TYPE_NORMAL; -} - } // namespace class OfflinePageMHTMLArchiverTest : public testing::Test { @@ -279,45 +260,6 @@ histogram_tester()->ExpectTotalCount(kComputeDigestTimeHistogram, 0); } -// Tests for archiver handling of non-secure connection. -TEST_F(OfflinePageMHTMLArchiverTest, ConnectionNotSecure) { - GURL page_url = GURL(kTestURL); - CreateArchive(page_url, - TestMHTMLArchiver::TestScenario::CONNECTION_SECURITY_ERROR); - - EXPECT_EQ(OfflinePageArchiver::ArchiverResult::ERROR_SECURITY_CERTIFICATE, - last_result()); - EXPECT_EQ(base::FilePath(), last_file_path()); - EXPECT_EQ(0LL, last_file_size()); - histogram_tester()->ExpectTotalCount(kCreateArchiveTimeHistogram, 0); - histogram_tester()->ExpectTotalCount(kComputeDigestTimeHistogram, 0); -} - -// Tests for archiver handling of an error page. -TEST_F(OfflinePageMHTMLArchiverTest, PageError) { - GURL page_url = GURL(kTestURL); - CreateArchive(page_url, TestMHTMLArchiver::TestScenario::ERROR_PAGE); - - EXPECT_EQ(OfflinePageArchiver::ArchiverResult::ERROR_ERROR_PAGE, - last_result()); - EXPECT_EQ(base::FilePath(), last_file_path()); - EXPECT_EQ(0LL, last_file_size()); - histogram_tester()->ExpectTotalCount(kCreateArchiveTimeHistogram, 0); - histogram_tester()->ExpectTotalCount(kComputeDigestTimeHistogram, 0); -} - -// Tests for archiver handling of an interstitial page. -TEST_F(OfflinePageMHTMLArchiverTest, InterstitialPage) { - GURL page_url = GURL(kTestURL); - CreateArchive(page_url, TestMHTMLArchiver::TestScenario::INTERSTITIAL_PAGE); - EXPECT_EQ(OfflinePageArchiver::ArchiverResult::ERROR_INTERSTITIAL_PAGE, - last_result()); - EXPECT_EQ(base::FilePath(), last_file_path()); - EXPECT_EQ(0LL, last_file_size()); - histogram_tester()->ExpectTotalCount(kCreateArchiveTimeHistogram, 0); - histogram_tester()->ExpectTotalCount(kComputeDigestTimeHistogram, 0); -} - // Tests for failing to compute digest for archive file. TEST_F(OfflinePageMHTMLArchiverTest, DigestError) { GURL page_url = GURL(kNonExistentURL);
diff --git a/chrome/browser/policy/policy_network_browsertest.cc b/chrome/browser/policy/policy_network_browsertest.cc index e62c6b5..14945e8a 100644 --- a/chrome/browser/policy/policy_network_browsertest.cc +++ b/chrome/browser/policy/policy_network_browsertest.cc
@@ -285,7 +285,8 @@ DISALLOW_COPY_AND_ASSIGN(QuicAllowedPolicyIsNotSet); }; -IN_PROC_BROWSER_TEST_F(QuicAllowedPolicyIsNotSet, NoQuicRegulations) { +// Flaky test on Win7. https://crbug.com/961049 +IN_PROC_BROWSER_TEST_F(QuicAllowedPolicyIsNotSet, DISABLED_NoQuicRegulations) { EXPECT_TRUE(IsQuicEnabledForSystem()); EXPECT_TRUE(IsQuicEnabledForSafeBrowsing()); EXPECT_TRUE(IsQuicEnabled(browser()->profile()));
diff --git a/chrome/browser/previews/previews_content_util.cc b/chrome/browser/previews/previews_content_util.cc index 869e425..abdd661 100644 --- a/chrome/browser/previews/previews_content_util.cc +++ b/chrome/browser/previews/previews_content_util.cc
@@ -246,33 +246,26 @@ navigation_handle->GetWebContents()->GetBrowserContext())) : nullptr; - // Offline previews state should not be updated if previews triggering - // logic has already been run. The Offline Previews URLLoader will not receive - // an updated PreviewsState, so the state should stay consistent throughout - // the navigation. if (previews_triggering_logic_already_ran) { // Record that the navigation was redirected. previews_data->set_is_redirect(true); - // Keep the same OFFLINE previews bit as the original URL. - previews_state |= - (previews_data->allowed_previews_state() & content::OFFLINE_PAGE_ON); - } else { - bool allow_offline = true; - // If |previews_service| is null, skip the previews offline helper check. - // This only happens in testing. - if (previews_service) { - allow_offline = previews_service->previews_offline_helper() - ->ShouldAttemptOfflinePreview(url); - } - allow_offline = - allow_offline && - previews_decider->ShouldAllowPreviewAtNavigationStart( - previews_data, url, is_reload, previews::PreviewsType::OFFLINE); - - if (allow_offline) - previews_state |= content::OFFLINE_PAGE_ON; } + bool allow_offline = true; + // If |previews_service| is null, skip the previews offline helper check. + // This only happens in testing. + if (previews_service) { + allow_offline = previews_service->previews_offline_helper() + ->ShouldAttemptOfflinePreview(url); + } + allow_offline = + allow_offline && + previews_decider->ShouldAllowPreviewAtNavigationStart( + previews_data, url, is_reload, previews::PreviewsType::OFFLINE); + + if (allow_offline) + previews_state |= content::OFFLINE_PAGE_ON; + // Check PageHint preview types first. bool should_load_page_hints = false; if (previews_decider->ShouldAllowPreviewAtNavigationStart(
diff --git a/chrome/browser/previews/previews_content_util_unittest.cc b/chrome/browser/previews/previews_content_util_unittest.cc index 2618c546..29244a5 100644 --- a/chrome/browser/previews/previews_content_util_unittest.cc +++ b/chrome/browser/previews/previews_content_util_unittest.cc
@@ -183,6 +183,7 @@ bool is_reload = false; bool previews_triggering_logic_already_ran = false; bool is_data_saver_user = true; + EXPECT_EQ(content::OFFLINE_PAGE_ON, previews::CallDetermineAllowedClientPreviewsState( &user_data, GURL("http://www.google.com"), is_reload, @@ -190,6 +191,7 @@ enabled_previews_decider(), nullptr)); EXPECT_FALSE(user_data.is_redirect()); user_data.set_allowed_previews_state(content::OFFLINE_PAGE_ON); + previews_triggering_logic_already_ran = true; EXPECT_EQ(content::OFFLINE_PAGE_ON, previews::CallDetermineAllowedClientPreviewsState( @@ -197,12 +199,14 @@ previews_triggering_logic_already_ran, is_data_saver_user, enabled_previews_decider(), nullptr)); EXPECT_TRUE(user_data.is_redirect()); + user_data.set_allowed_previews_state(content::PREVIEWS_OFF); - EXPECT_EQ(content::PREVIEWS_UNSPECIFIED, + EXPECT_EQ(content::OFFLINE_PAGE_ON, previews::CallDetermineAllowedClientPreviewsState( &user_data, GURL("http://www.google.com"), is_reload, previews_triggering_logic_already_ran, is_data_saver_user, enabled_previews_decider(), nullptr)); + previews_triggering_logic_already_ran = false; EXPECT_EQ(content::OFFLINE_PAGE_ON, previews::CallDetermineAllowedClientPreviewsState(
diff --git a/chrome/browser/profiles/off_the_record_profile_io_data.cc b/chrome/browser/profiles/off_the_record_profile_io_data.cc index d077469..44520d14 100644 --- a/chrome/browser/profiles/off_the_record_profile_io_data.cc +++ b/chrome/browser/profiles/off_the_record_profile_io_data.cc
@@ -39,8 +39,6 @@ #include "net/http/http_network_session.h" #include "net/http/http_server_properties_impl.h" #include "net/net_buildflags.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/default_channel_id_store.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_job_factory_impl.h" @@ -204,11 +202,6 @@ ProfileParams* profile_params, content::ProtocolHandlerMap* protocol_handlers, content::URLRequestInterceptorScopedVector request_interceptors) const { - // For incognito, we use a non-persistent channel ID store. - std::unique_ptr<net::ChannelIDService> channel_id_service( - std::make_unique<net::ChannelIDService>( - new net::DefaultChannelIDStore(nullptr))); - AddProtocolHandlersToBuilder(builder, protocol_handlers); SetUpJobFactoryDefaultsForBuilder( builder, std::move(request_interceptors),
diff --git a/chrome/browser/profiles/profile_impl_io_data.cc b/chrome/browser/profiles/profile_impl_io_data.cc index 92703ba..ee511117 100644 --- a/chrome/browser/profiles/profile_impl_io_data.cc +++ b/chrome/browser/profiles/profile_impl_io_data.cc
@@ -72,7 +72,6 @@ #include "net/http/http_server_properties.h" #include "net/http/http_server_properties_manager.h" #include "net/net_buildflags.h" -#include "net/ssl/channel_id_service.h" #include "net/url_request/url_request_context_builder.h" #include "net/url_request/url_request_intercepting_job_factory.h" #include "net/url_request/url_request_job_factory_impl.h"
diff --git a/chrome/browser/profiles/profile_io_data.cc b/chrome/browser/profiles/profile_io_data.cc index c439cb50..7d9197c 100644 --- a/chrome/browser/profiles/profile_io_data.cc +++ b/chrome/browser/profiles/profile_io_data.cc
@@ -89,7 +89,6 @@ #include "net/http/transport_security_persister.h" #include "net/net_buildflags.h" #include "net/nqe/network_quality_estimator.h" -#include "net/ssl/channel_id_service.h" #include "net/ssl/client_cert_store.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/data_protocol_handler.h" @@ -523,12 +522,6 @@ set_cookie_store(cookie_store_.get()); } -void ProfileIOData::AppRequestContext::SetChannelIDService( - std::unique_ptr<net::ChannelIDService> channel_id_service) { - channel_id_service_ = std::move(channel_id_service); - set_channel_id_service(channel_id_service_.get()); -} - void ProfileIOData::AppRequestContext::SetHttpNetworkSession( std::unique_ptr<net::HttpNetworkSession> http_network_session) { http_network_session_ = std::move(http_network_session);
diff --git a/chrome/browser/profiles/profile_io_data.h b/chrome/browser/profiles/profile_io_data.h index ca50a41..78a6561 100644 --- a/chrome/browser/profiles/profile_io_data.h +++ b/chrome/browser/profiles/profile_io_data.h
@@ -62,7 +62,6 @@ namespace net { class CertNetFetcherImpl; class CertVerifier; -class ChannelIDService; class ClientCertStore; class CookieStore; class HttpTransactionFactory; @@ -279,8 +278,6 @@ AppRequestContext(); void SetCookieStore(std::unique_ptr<net::CookieStore> cookie_store); - void SetChannelIDService( - std::unique_ptr<net::ChannelIDService> channel_id_service); void SetHttpNetworkSession( std::unique_ptr<net::HttpNetworkSession> http_network_session); void SetHttpTransactionFactory( @@ -291,7 +288,6 @@ ~AppRequestContext() override; std::unique_ptr<net::CookieStore> cookie_store_; - std::unique_ptr<net::ChannelIDService> channel_id_service_; std::unique_ptr<net::HttpNetworkSession> http_network_session_; std::unique_ptr<net::HttpTransactionFactory> http_factory_; std::unique_ptr<net::URLRequestJobFactory> job_factory_;
diff --git a/chrome/browser/resources/app_management/metadata_view.html b/chrome/browser/resources/app_management/metadata_view.html index 543f983..aad0dd4f 100644 --- a/chrome/browser/resources/app_management/metadata_view.html +++ b/chrome/browser/resources/app_management/metadata_view.html
@@ -20,7 +20,7 @@ } cr-toggle { - padding-inline-start: 12px; + margin-inline-start: 12px; } #metadata-overview {
diff --git a/chrome/browser/resources/chromeos/login/oobe_supervision_transition.html b/chrome/browser/resources/chromeos/login/oobe_supervision_transition.html index 1633670..088c2ad 100644 --- a/chrome/browser/resources/chromeos/login/oobe_supervision_transition.html +++ b/chrome/browser/resources/chromeos/login/oobe_supervision_transition.html
@@ -34,7 +34,8 @@ <h1 slot="title">$i18n{supervisionTransitionErrorTitle}</h1> <div slot="subtitle">$i18n{supervisionTransitionErrorMessage}</div> <div slot="bottom-buttons" class="layout horizontal end-justified"> - <oobe-text-button on-tap="onAcceptAndContinue_" inverse> + <oobe-text-button id="accept-button" on-tap="onAcceptAndContinue_" + inverse> <div>$i18n{supervisionTransitionButton}</div> </oobe-text-button> </div>
diff --git a/chrome/browser/resources/local_ntp/BUILD.gn b/chrome/browser/resources/local_ntp/BUILD.gn index f7d4bd9..22531ae 100644 --- a/chrome/browser/resources/local_ntp/BUILD.gn +++ b/chrome/browser/resources/local_ntp/BUILD.gn
@@ -16,7 +16,6 @@ "custom_backgrounds.js", "custom_links_edit.js", "doodles.js", - "instant_iframe_validation.js", "local_ntp.js", "most_visited_single.js", "most_visited_title.js",
diff --git a/chrome/browser/resources/local_ntp/custom_backgrounds.js b/chrome/browser/resources/local_ntp/custom_backgrounds.js index 256fe84c..4bcf716b 100644 --- a/chrome/browser/resources/local_ntp/custom_backgrounds.js +++ b/chrome/browser/resources/local_ntp/custom_backgrounds.js
@@ -5,6 +5,8 @@ 'use strict'; +// TODO(crbug.com/937570): After the RP launches this should be renamed to +// customizationMenu along with the file, and large parts can be refactored/removed. const customBackgrounds = {}; /**
diff --git a/chrome/browser/resources/local_ntp/instant_iframe_validation.js b/chrome/browser/resources/local_ntp/instant_iframe_validation.js deleted file mode 100644 index e0a684d..0000000 --- a/chrome/browser/resources/local_ntp/instant_iframe_validation.js +++ /dev/null
@@ -1,55 +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. - - -/** - * @fileoverview Helpers for validating parameters to chrome-search:// iframes. - */ - - -/** - * Converts an RGB color number to a hex color string if valid. - * @param {number} color A 6-digit hex RGB color code as a number. - * @return {?string} A CSS representation of the color or null if invalid. - */ -function convertToHexColor(color) { - // Color must be a number, finite, with no fractional part, in the correct - // range for an RGB hex color. - if (isFinite(color) && Math.floor(color) == color && color >= 0 && - color <= 0xffffff) { - const hexColor = color.toString(16); - // Pads with initial zeros and # (e.g. for 'ff' yields '#0000ff'). - return '#000000'.substr(0, 7 - hexColor.length) + hexColor; - } - return null; -} - - -/** - * Validates a RGBA color component. It must be a number between 0 and 255. - * @param {number} component An RGBA component. - * @return {boolean} True if the component is valid. - */ -function isValidRBGAComponent(component) { - return isFinite(component) && component >= 0 && component <= 255; -} - - -/** - * Converts an Array of color components into RGBA format "rgba(R,G,B,A)". - * @param {Array<number>} rgbaColor Array of rgba color components. - * @return {?string} CSS color in RGBA format or null if invalid. - */ -function convertArrayToRGBAColor(rgbaColor) { - // Array must contain 4 valid components. - if (rgbaColor instanceof Array && rgbaColor.length === 4 && - isValidRBGAComponent(rgbaColor[0]) && - isValidRBGAComponent(rgbaColor[1]) && - isValidRBGAComponent(rgbaColor[2]) && - isValidRBGAComponent(rgbaColor[3])) { - return 'rgba(' + rgbaColor[0] + ',' + rgbaColor[1] + ',' + rgbaColor[2] + - ',' + rgbaColor[3] / 255 + ')'; - } - return null; -}
diff --git a/chrome/browser/resources/local_ntp/local_ntp_resources.grd b/chrome/browser/resources/local_ntp/local_ntp_resources.grd index 68609e7..edb2d731 100644 --- a/chrome/browser/resources/local_ntp/local_ntp_resources.grd +++ b/chrome/browser/resources/local_ntp/local_ntp_resources.grd
@@ -8,7 +8,6 @@ </outputs> <release seq="1"> <includes> - <include name="IDR_INSTANT_IFRAME_VALIDATION_JS" file="instant_iframe_validation.js" type="BINDATA" /> <include name="IDR_CUSTOM_LINKS_ADD_SVG" file="icons\add_link.svg" type="BINDATA" /> <include name="IDR_CUSTOM_LINKS_ADD_WHITE_SVG" file="icons\add_link_white.svg" type="BINDATA" /> <include name="IDR_CUSTOM_LINKS_EDIT_HTML" file="custom_links_edit.html" type="BINDATA" />
diff --git a/chrome/browser/resources/local_ntp/most_visited_util.js b/chrome/browser/resources/local_ntp/most_visited_util.js index 13b583c..db47443 100644 --- a/chrome/browser/resources/local_ntp/most_visited_util.js +++ b/chrome/browser/resources/local_ntp/most_visited_util.js
@@ -7,9 +7,6 @@ * @fileoverview Utilities for rendering most visited thumbnails and titles. */ -// Don't remove; see crbug.com/678778. -// <include src="instant_iframe_validation.js"> - /** * The origin of this request. @@ -17,6 +14,54 @@ */ const MV_DOMAIN_ORIGIN = '{{ORIGIN}}'; + +/** + * Converts an RGB color number to a hex color string if valid. + * @param {number} color A 6-digit hex RGB color code as a number. + * @return {?string} A CSS representation of the color or null if invalid. + */ +function convertToHexColor(color) { + // Color must be a number, finite, with no fractional part, in the correct + // range for an RGB hex color. + if (isFinite(color) && Math.floor(color) == color && color >= 0 && + color <= 0xffffff) { + const hexColor = color.toString(16); + // Pads with initial zeros and # (e.g. for 'ff' yields '#0000ff'). + return '#000000'.substr(0, 7 - hexColor.length) + hexColor; + } + return null; +} + + +/** + * Validates a RGBA color component. It must be a number between 0 and 255. + * @param {number} component An RGBA component. + * @return {boolean} True if the component is valid. + */ +function isValidRBGAComponent(component) { + return isFinite(component) && component >= 0 && component <= 255; +} + + +/** + * Converts an Array of color components into RGBA format "rgba(R,G,B,A)". + * @param {Array<number>} rgbaColor Array of rgba color components. + * @return {?string} CSS color in RGBA format or null if invalid. + */ +function convertArrayToRGBAColor(rgbaColor) { + // Array must contain 4 valid components. + if (rgbaColor instanceof Array && rgbaColor.length === 4 && + isValidRBGAComponent(rgbaColor[0]) && + isValidRBGAComponent(rgbaColor[1]) && + isValidRBGAComponent(rgbaColor[2]) && + isValidRBGAComponent(rgbaColor[3])) { + return 'rgba(' + rgbaColor[0] + ',' + rgbaColor[1] + ',' + rgbaColor[2] + + ',' + rgbaColor[3] / 255 + ')'; + } + return null; +} + + /** * Parses query parameters from Location. * @param {!Location} location The URL to generate the CSS url for.
diff --git a/chrome/browser/resources/safe_browsing/download_file_types.asciipb b/chrome/browser/resources/safe_browsing/download_file_types.asciipb index ec9b10be0..3bc8ad0 100644 --- a/chrome/browser/resources/safe_browsing/download_file_types.asciipb +++ b/chrome/browser/resources/safe_browsing/download_file_types.asciipb
@@ -8,7 +8,7 @@ ## ## Top level settings ## -version_id: 35 +version_id: 36 sampled_ping_probability: 0.01 max_archived_binaries_to_report: 10 default_file_type { @@ -3385,3 +3385,120 @@ auto_open_hint: DISALLOW_AUTO_OPEN } } + +# Other file types supported by Web Share API on Android +file_types { + extension: "bmp" + uma_value: 365 + ping_setting: SAMPLED_PING +} +file_types { + extension: "css" + uma_value: 366 + ping_setting: SAMPLED_PING +} +file_types { + extension: "ehtml" + uma_value: 367 + ping_setting: SAMPLED_PING +} +file_types { + extension: "flac" + uma_value: 368 + ping_setting: SAMPLED_PING +} +file_types { + extension: "ico" + uma_value: 369 + ping_setting: SAMPLED_PING +} +file_types { + extension: "jfif" + uma_value: 370 + ping_setting: SAMPLED_PING +} +file_types { + extension: "m4a" + uma_value: 371 + ping_setting: SAMPLED_PING +} +file_types { + extension: "m4v" + uma_value: 372 + ping_setting: SAMPLED_PING +} +file_types { + extension: "mpeg" + uma_value: 373 + ping_setting: SAMPLED_PING +} +file_types { + extension: "mpg" + uma_value: 374 + ping_setting: SAMPLED_PING +} +file_types { + extension: "oga" + uma_value: 375 + ping_setting: SAMPLED_PING +} +file_types { + extension: "ogg" + uma_value: 376 + ping_setting: SAMPLED_PING +} +file_types { + extension: "ogm" + uma_value: 377 + ping_setting: SAMPLED_PING +} +file_types { + extension: "ogv" + uma_value: 378 + ping_setting: SAMPLED_PING +} +file_types { + extension: "opus" + uma_value: 379 + ping_setting: SAMPLED_PING +} +file_types { + extension: "pjp" + uma_value: 380 + ping_setting: SAMPLED_PING +} +file_types { + extension: "pjpeg" + uma_value: 381 + ping_setting: SAMPLED_PING +} +file_types { + extension: "svgz" + uma_value: 382 + ping_setting: SAMPLED_PING +} +file_types { + extension: "text" + uma_value: 383 + ping_setting: SAMPLED_PING +} +file_types { + extension: "tiff" + uma_value: 384 + ping_setting: SAMPLED_PING +} +file_types { + extension: "weba" + uma_value: 385 + ping_setting: SAMPLED_PING +} +file_types { + extension: "webm" + uma_value: 386 + ping_setting: SAMPLED_PING +} +file_types { + extension: "xbm" + uma_value: 387 + ping_setting: SAMPLED_PING +}
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_export_import.html b/chrome/browser/resources/settings/crostini_page/crostini_export_import.html index cc24850..930c0d8d 100644 --- a/chrome/browser/resources/settings/crostini_page/crostini_export_import.html +++ b/chrome/browser/resources/settings/crostini_page/crostini_export_import.html
@@ -11,14 +11,20 @@ <style include="settings-shared"></style> <div class="list-frame vertical-list"> <div id="export" class="list-item"> - <div class="start secondary">$i18n{crostiniExportLabel}</div> - <paper-button on-click="onExportClick_"> + <div id="exportCrostiniLabel" class="start secondary"> + $i18n{crostiniExportLabel} + </div> + <paper-button on-click="onExportClick_" + aria-labelledby="exportCrostiniLabel"> $i18n{crostiniExport} </paper-button> </div> <div id="import" class="list-item"> - <div class="start secondary">$i18n{crostiniImportLabel}</div> - <paper-button on-click="onImportClick_"> + <div id="importCrostiniLabel" class="start secondary"> + $i18n{crostiniImportLabel} + </div> + <paper-button on-click="onImportClick_" + aria-labelledby="importCrostiniLabel"> $i18n{crostiniImport} </paper-button> </div>
diff --git a/chrome/browser/resources/settings/crostini_page/crostini_subpage.html b/chrome/browser/resources/settings/crostini_page/crostini_subpage.html index 27d1620..5cc3458 100644 --- a/chrome/browser/resources/settings/crostini_page/crostini_subpage.html +++ b/chrome/browser/resources/settings/crostini_page/crostini_subpage.html
@@ -35,8 +35,9 @@ </template> <template is="dom-if" if="[[!hideCrostiniUninstall_]]"> <div id="remove" class="settings-box"> - <div class="start">$i18n{crostiniRemove}</div> - <paper-button on-click="onRemoveClick_"> + <div id="removeCrostiniLabel" class="start">$i18n{crostiniRemove}</div> + <paper-button on-click="onRemoveClick_" + aria-labelledby="removeCrostiniLabel"> $i18n{crostiniRemoveButton} </paper-button> </div>
diff --git a/chrome/browser/safe_browsing/BUILD.gn b/chrome/browser/safe_browsing/BUILD.gn index 23d61ae..e817d3d 100644 --- a/chrome/browser/safe_browsing/BUILD.gn +++ b/chrome/browser/safe_browsing/BUILD.gn
@@ -260,22 +260,30 @@ sources += [ "../loader/safe_browsing_resource_throttle.cc", "../loader/safe_browsing_resource_throttle.h", + "android/file_type_policies.cc", "android/services_delegate_android.cc", "android/services_delegate_android.h", "telemetry/android/android_telemetry_service.cc", "telemetry/android/android_telemetry_service.h", ] - deps += [ "//components/safe_browsing/android:safe_browsing_mobile" ] + deps += [ + "//chrome/android:jni_headers", + "//components/safe_browsing/android:safe_browsing_mobile", + ] } else if (safe_browsing_mode == 3) { sources += [ "../loader/safe_browsing_resource_throttle.cc", "../loader/safe_browsing_resource_throttle.h", + "android/file_type_policies.cc", "android/services_delegate_android.cc", "android/services_delegate_android.h", "telemetry/android/android_telemetry_service.cc", "telemetry/android/android_telemetry_service.h", ] - deps += [ "//components/safe_browsing/db:db" ] + deps += [ + "//chrome/android:jni_headers", + "//components/safe_browsing/db:db", + ] } } }
diff --git a/chrome/browser/safe_browsing/android/file_type_policies.cc b/chrome/browser/safe_browsing/android/file_type_policies.cc new file mode 100644 index 0000000..7c773a0 --- /dev/null +++ b/chrome/browser/safe_browsing/android/file_type_policies.cc
@@ -0,0 +1,21 @@ +// Copyright 2019 The Chromium 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/common/safe_browsing/file_type_policies.h" + +#include "base/android/jni_string.h" +#include "base/files/file_path.h" +#include "jni/FileTypePolicies_jni.h" + +namespace safe_browsing { + +static jint JNI_FileTypePolicies_UmaValueForFile( + JNIEnv* env, + const base::android::JavaParamRef<jstring>& path) { + base::FilePath file_path(ConvertJavaStringToUTF8(env, path)); + return safe_browsing::FileTypePolicies::GetInstance()->UmaValueForFile( + file_path); +} + +} // namespace safe_browsing
diff --git a/chrome/browser/tracing/background_tracing_field_trial_unittest.cc b/chrome/browser/tracing/background_tracing_field_trial_unittest.cc index c935d54..fb759138 100644 --- a/chrome/browser/tracing/background_tracing_field_trial_unittest.cc +++ b/chrome/browser/tracing/background_tracing_field_trial_unittest.cc
@@ -21,7 +21,7 @@ BackgroundTracingTest() = default; void TearDown() override { - content::BackgroundTracingManager::GetInstance()->AbortScenario(); + content::BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); } private:
diff --git a/chrome/browser/tracing/background_tracing_metrics_provider_unittest.cc b/chrome/browser/tracing/background_tracing_metrics_provider_unittest.cc index 7ef8bc5..efd39f1 100644 --- a/chrome/browser/tracing/background_tracing_metrics_provider_unittest.cc +++ b/chrome/browser/tracing/background_tracing_metrics_provider_unittest.cc
@@ -34,7 +34,7 @@ EXPECT_FALSE(provider.HasIndependentMetrics()); content::BackgroundTracingManager::GetInstance()->SetTraceToUploadForTesting( - kDummyTrace); + std::make_unique<std::string>(kDummyTrace)); EXPECT_TRUE(provider.HasIndependentMetrics()); metrics::ChromeUserMetricsExtension uma_proto; @@ -57,11 +57,11 @@ EXPECT_FALSE(provider.HasIndependentMetrics()); content::BackgroundTracingManager::GetInstance()->SetTraceToUploadForTesting( - kDummyTrace); + std::make_unique<std::string>(kDummyTrace)); EXPECT_TRUE(provider.HasIndependentMetrics()); content::BackgroundTracingManager::GetInstance()->SetTraceToUploadForTesting( - ""); + nullptr); metrics::ChromeUserMetricsExtension uma_proto; uma_proto.set_client_id(100); uma_proto.set_session_id(15);
diff --git a/chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc b/chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc index 4c56c23..507d18f 100644 --- a/chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc +++ b/chrome/browser/tracing/chrome_tracing_delegate_browsertest.cc
@@ -148,7 +148,7 @@ local_state->GetInt64(prefs::kBackgroundTracingLastUpload)); EXPECT_FALSE(last_upload_time.is_null()); - content::BackgroundTracingManager::GetInstance()->AbortScenario(); + content::BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); base::RunLoop wait_for_abort; content::BackgroundTracingManager::GetInstance()->WhenIdle( wait_for_abort.QuitClosure()); @@ -188,7 +188,7 @@ local_state->GetInt64(prefs::kBackgroundTracingLastUpload)); EXPECT_FALSE(last_upload_time.is_null()); - content::BackgroundTracingManager::GetInstance()->AbortScenario(); + content::BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); base::RunLoop wait_for_abort; content::BackgroundTracingManager::GetInstance()->WhenIdle( wait_for_abort.QuitClosure());
diff --git a/chrome/browser/ui/ash/split_view_interactive_uitest.cc b/chrome/browser/ui/ash/split_view_interactive_uitest.cc index 311581b..69e9791 100644 --- a/chrome/browser/ui/ash/split_view_interactive_uitest.cc +++ b/chrome/browser/ui/ash/split_view_interactive_uitest.cc
@@ -3,8 +3,8 @@ // found in the LICENSE file. #include "ash/public/cpp/ash_switches.h" -#include "ash/shell.h" // mash-ok -#include "ash/wm/splitview/split_view_controller.h" // mash-ok +#include "ash/shell.h" +#include "ash/wm/splitview/split_view_controller.h" #include "base/macros.h" #include "base/run_loop.h" #include "base/system/sys_info.h" @@ -17,11 +17,8 @@ #include "chrome/browser/ui/views/frame/browser_view.h" #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/perf/performance_test.h" -#include "content/public/common/service_names.mojom.h" -#include "ui/aura/mus/window_mus.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" -#include "ui/base/ui_base_features.h" #include "ui/compositor/compositor.h" #include "ui/compositor/compositor_switches.h" #include "ui/display/display.h" @@ -32,12 +29,6 @@ namespace { -ws::Id GetBrowserWindowServerId(Browser* browser) { - return aura::WindowMus::Get( - browser->window()->GetNativeWindow()->GetRootWindow()) - ->server_id(); -} - class SplitViewTest : public UIPerformanceTest { public: SplitViewTest() = default; @@ -133,33 +124,11 @@ BrowserView::GetBrowserViewForBrowser(browser())->GetWidget(); views::Widget* browser2_widget = BrowserView::GetBrowserViewForBrowser(browser2)->GetWidget(); - if (features::IsUsingWindowService()) { - ash::mojom::ShellTestApiPtr shell_test_api = test::GetShellTestApi(); - - { - base::RunLoop run_loop; - shell_test_api->SnapWindowInSplitView(content::mojom::kBrowserServiceName, - GetBrowserWindowServerId(browser2), - true, run_loop.QuitClosure()); - run_loop.Run(); - } - - { - base::RunLoop run_loop; - shell_test_api->SnapWindowInSplitView(content::mojom::kBrowserServiceName, - GetBrowserWindowServerId(browser()), - false, run_loop.QuitClosure()); - run_loop.Run(); - } - } else { - ash::Shell* shell = ash::Shell::Get(); - shell->split_view_controller()->SnapWindow( - browser2_widget->GetNativeWindow(), ash::SplitViewController::LEFT); - shell->split_view_controller()->FlushForTesting(); - shell->split_view_controller()->SnapWindow( - browser_widget->GetNativeWindow(), ash::SplitViewController::RIGHT); - shell->split_view_controller()->FlushForTesting(); - } + ash::Shell* shell = ash::Shell::Get(); + shell->split_view_controller()->SnapWindow(browser2_widget->GetNativeWindow(), + ash::SplitViewController::LEFT); + shell->split_view_controller()->SnapWindow(browser_widget->GetNativeWindow(), + ash::SplitViewController::RIGHT); test::WaitForNoPointerHoldLock();
diff --git a/chrome/browser/ui/uma_browsing_activity_observer.cc b/chrome/browser/ui/uma_browsing_activity_observer.cc index a2b94fc..0424931 100644 --- a/chrome/browser/ui/uma_browsing_activity_observer.cc +++ b/chrome/browser/ui/uma_browsing_activity_observer.cc
@@ -6,6 +6,7 @@ #include "base/metrics/histogram_macros.h" #include "base/metrics/user_metrics.h" +#include "base/time/time.h" #include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/search_engines/template_url_service_factory.h" @@ -14,6 +15,7 @@ #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/browser/upgrade_detector/upgrade_detector.h" #include "components/search_engines/template_url_service.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/navigation_details.h" @@ -76,11 +78,24 @@ LogRenderProcessHostCount(); LogBrowserTabCount(); } else if (type == chrome::NOTIFICATION_APP_TERMINATING) { + LogTimeBeforeUpdate(); delete g_uma_browsing_activity_observer_instance; g_uma_browsing_activity_observer_instance = NULL; } } +void UMABrowsingActivityObserver::LogTimeBeforeUpdate() const { + const base::Time upgrade_detected_time = + UpgradeDetector::GetInstance()->upgrade_detected_time(); + if (upgrade_detected_time.is_null()) + return; + const base::Time now = base::Time::Now(); + UMA_HISTOGRAM_CUSTOM_TIMES("UpgradeDetector.TimeBeforeUpgrade", + base::TimeDelta(now - upgrade_detected_time), + base::TimeDelta::FromHours(1), + base::TimeDelta::FromDays(20), 50); +} + void UMABrowsingActivityObserver::LogRenderProcessHostCount() const { int hosts_count = 0; for (content::RenderProcessHost::iterator i(
diff --git a/chrome/browser/ui/uma_browsing_activity_observer.h b/chrome/browser/ui/uma_browsing_activity_observer.h index 95ec981..9dfed9e 100644 --- a/chrome/browser/ui/uma_browsing_activity_observer.h +++ b/chrome/browser/ui/uma_browsing_activity_observer.h
@@ -28,6 +28,10 @@ const content::NotificationSource& source, const content::NotificationDetails& details) override; + // Calculates the time from an update being visible to the browser and + // the browser restarting or quitting and logs it. + void LogTimeBeforeUpdate() const; + // Counts the number of active RenderProcessHosts and logs them. void LogRenderProcessHostCount() const;
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc index 3e040f33..962e7936 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.cc
@@ -16,7 +16,6 @@ #include "ash/public/cpp/touch_uma.h" #include "ash/public/cpp/window_properties.h" #include "ash/public/interfaces/constants.mojom.h" -#include "ash/public/interfaces/split_view.mojom.h" #include "ash/public/interfaces/window_state_type.mojom.h" #include "ash/wm/window_util.h" #include "base/command_line.h" @@ -85,24 +84,24 @@ } // Returns true if |window| is currently snapped in split view mode. -bool IsSnappedInSplitView(const aura::Window* window, - ash::mojom::SplitViewState state) { +bool IsSnappedInSplitView(const aura::Window* window) { + ash::SplitViewState state = ash::SplitViewNotifier::Get()->GetCurrentState(); ash::mojom::WindowStateType type = window->GetProperty(ash::kWindowStateTypeKey); switch (state) { - case ash::mojom::SplitViewState::NO_SNAP: + case ash::SplitViewState::kNoSnap: return false; - case ash::mojom::SplitViewState::LEFT_SNAPPED: + case ash::SplitViewState::kLeftSnapped: return type == ash::mojom::WindowStateType::LEFT_SNAPPED; - case ash::mojom::SplitViewState::RIGHT_SNAPPED: + case ash::SplitViewState::kRightSnapped: return type == ash::mojom::WindowStateType::RIGHT_SNAPPED; - case ash::mojom::SplitViewState::BOTH_SNAPPED: + case ash::SplitViewState::kBothSnapped: return type == ash::mojom::WindowStateType::LEFT_SNAPPED || type == ash::mojom::WindowStateType::RIGHT_SNAPPED; - default: - NOTREACHED(); - return false; } + + NOTREACHED(); + return false; } const views::WindowManagerFrameValues& frame_values() { @@ -127,16 +126,6 @@ BrowserView* browser_view) : BrowserNonClientFrameView(frame, browser_view) { ash::wm::InstallResizeHandleWindowTargeterForWindow(frame->GetNativeWindow()); - - // The ServiceManagerConnection may be nullptr in tests. - if (content::ServiceManagerConnection::GetForProcess()) { - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &split_view_controller_); - ash::mojom::SplitViewObserverPtr observer; - observer_binding_.Bind(mojo::MakeRequest(&observer)); - split_view_controller_->AddObserver(std::move(observer)); - } } BrowserNonClientFrameViewAsh::~BrowserNonClientFrameViewAsh() { @@ -146,6 +135,8 @@ if (TabletModeClient::Get()) TabletModeClient::Get()->RemoveObserver(this); + ash::SplitViewNotifier::Get()->RemoveObserver(this); + ImmersiveModeController* immersive_controller = browser_view()->immersive_mode_controller(); if (immersive_controller) @@ -199,19 +190,11 @@ SetUpForHostedApp(); browser_view()->immersive_mode_controller()->AddObserver(this); + ash::SplitViewNotifier::Get()->AddObserver(this); UpdateFrameColors(); } -ash::mojom::SplitViewObserverPtr -BrowserNonClientFrameViewAsh::CreateInterfacePtrForTesting() { - if (observer_binding_.is_bound()) - observer_binding_.Unbind(); - ash::mojom::SplitViewObserverPtr ptr; - observer_binding_.Bind(mojo::MakeRequest(&ptr)); - return ptr; -} - /////////////////////////////////////////////////////////////////////////////// // BrowserNonClientFrameView: @@ -557,8 +540,8 @@ } void BrowserNonClientFrameViewAsh::OnSplitViewStateChanged( - ash::mojom::SplitViewState current_state) { - split_view_state_ = current_state; + ash::SplitViewState previous_state, + ash::SplitViewState new_state) { OnOverviewOrSplitviewModeChanged(); } @@ -644,8 +627,7 @@ return false; } - return !IsInOverviewMode() || - IsSnappedInSplitView(GetFrameWindow(), split_view_state_); + return !IsInOverviewMode() || IsSnappedInSplitView(GetFrameWindow()); } int BrowserNonClientFrameViewAsh::GetTabStripLeftInset() const {
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h index a97c27c..5eb09d8 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash.h
@@ -7,7 +7,7 @@ #include <memory> -#include "ash/public/interfaces/split_view.mojom.h" +#include "ash/public/cpp/split_view.h" #include "base/gtest_prod_util.h" #include "base/macros.h" #include "base/memory/weak_ptr.h" @@ -43,7 +43,7 @@ public TabletModeClientObserver, public TabIconViewModel, public CommandObserver, - public ash::mojom::SplitViewObserver, + public ash::SplitViewObserver, public aura::WindowObserver, public ImmersiveModeController::Observer { public: @@ -52,8 +52,6 @@ void Init(); - ash::mojom::SplitViewObserverPtr CreateInterfacePtrForTesting(); - // BrowserNonClientFrameView: gfx::Rect GetBoundsForTabStripRegion( const views::View* tabstrip) const override; @@ -102,9 +100,9 @@ // CommandObserver: void EnabledStateChangedForCommand(int id, bool enabled) override; - // ash::mojom::SplitViewObserver: - void OnSplitViewStateChanged( - ash::mojom::SplitViewState current_state) override; + // ash::SplitViewObserver: + void OnSplitViewStateChanged(ash::SplitViewState previous_state, + ash::SplitViewState new_state) override; // aura::WindowObserver: void OnWindowDestroying(aura::Window* window) override; @@ -213,18 +211,8 @@ // Helper class for painting the header. std::unique_ptr<ash::FrameHeader> frame_header_; - // Ash's mojom::SplitViewController. - ash::mojom::SplitViewControllerPtr split_view_controller_; - - // The binding this instance uses to implement mojom::SplitViewObserver. - mojo::Binding<ash::mojom::SplitViewObserver> observer_binding_{this}; - ScopedObserver<aura::Window, aura::WindowObserver> window_observer_{this}; - // Maintains the current split view state. - ash::mojom::SplitViewState split_view_state_ = - ash::mojom::SplitViewState::NO_SNAP; - base::WeakPtrFactory<BrowserNonClientFrameViewAsh> weak_ptr_factory_{this}; DISALLOW_COPY_AND_ASSIGN(BrowserNonClientFrameViewAsh);
diff --git a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc index ee456d9a..6583755 100644 --- a/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc +++ b/chrome/browser/ui/views/frame/browser_non_client_frame_view_ash_browsertest.cc
@@ -1295,48 +1295,32 @@ ws::mojom::kResizeBehaviorCanMaximize | ws::mojom::kResizeBehaviorCanResize); - // Test that when one browser window is snapped, the header is visible for - // the snapped browser window, but invisible for the browser window still in - // overview mode. - ash::Shell* shell = ash::Shell::Get(); - ash::SplitViewController* split_view_controller = - shell->split_view_controller(); - split_view_controller->BindRequest( - mojo::MakeRequest(&frame_view->split_view_controller_)); - split_view_controller->BindRequest( - mojo::MakeRequest(&frame_view2->split_view_controller_)); - split_view_controller->AddObserver( - frame_view->CreateInterfacePtrForTesting()); - split_view_controller->AddObserver( - frame_view2->CreateInterfacePtrForTesting()); - frame_view->split_view_controller_.FlushForTesting(); - frame_view2->split_view_controller_.FlushForTesting(); + // Test that when one browser window is snapped, the header is visible for + // the snapped browser window, but invisible for the browser window still in + // overview mode. + ash::Shell* shell = ash::Shell::Get(); + ash::SplitViewController* split_view_controller = + shell->split_view_controller(); - ToggleOverview(); - split_view_controller->SnapWindow(widget->GetNativeWindow(), - ash::SplitViewController::LEFT); - frame_view->split_view_controller_.FlushForTesting(); - frame_view2->split_view_controller_.FlushForTesting(); - EXPECT_TRUE(frame_view->caption_button_container_->visible()); - EXPECT_FALSE(frame_view2->caption_button_container_->visible()); + ToggleOverview(); + split_view_controller->SnapWindow(widget->GetNativeWindow(), + ash::SplitViewController::LEFT); + EXPECT_TRUE(frame_view->caption_button_container_->visible()); + EXPECT_FALSE(frame_view2->caption_button_container_->visible()); - // When both browser windows are snapped, the headers are both visible. - split_view_controller->SnapWindow(widget2->GetNativeWindow(), - ash::SplitViewController::RIGHT); - frame_view->split_view_controller_.FlushForTesting(); - frame_view2->split_view_controller_.FlushForTesting(); - EXPECT_TRUE(frame_view->caption_button_container_->visible()); - EXPECT_TRUE(frame_view2->caption_button_container_->visible()); + // When both browser windows are snapped, the headers are both visible. + split_view_controller->SnapWindow(widget2->GetNativeWindow(), + ash::SplitViewController::RIGHT); + EXPECT_TRUE(frame_view->caption_button_container_->visible()); + EXPECT_TRUE(frame_view2->caption_button_container_->visible()); - // Toggle overview mode while splitview mode is active. Test that the header - // is visible for the snapped browser window but not for the other browser - // window in overview mode. - ToggleOverview(); - frame_view->split_view_controller_.FlushForTesting(); - frame_view2->split_view_controller_.FlushForTesting(); + // Toggle overview mode while splitview mode is active. Test that the header + // is visible for the snapped browser window but not for the other browser + // window in overview mode. + ToggleOverview(); - EXPECT_TRUE(frame_view->caption_button_container_->visible()); - EXPECT_FALSE(frame_view2->caption_button_container_->visible()); + EXPECT_TRUE(frame_view->caption_button_container_->visible()); + EXPECT_FALSE(frame_view2->caption_button_container_->visible()); } // Regression test for https://crbug.com/879851.
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc index 2cc05ec..6ef3e425 100644 --- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc +++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.cc
@@ -211,9 +211,13 @@ return details_->should_do_learning; } -void RemoteTextInputClient::SetCompositionFromExistingText( +bool RemoteTextInputClient::SetCompositionFromExistingText( const gfx::Range& range, - const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {} + const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { + // TODO(https://crbug.com/952757): Implement this method. + NOTIMPLEMENTED_LOG_ONCE(); + return false; +} ui::EventDispatchDetails RemoteTextInputClient::DispatchKeyEventPostIME( ui::KeyEvent* event,
diff --git a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h index 7d851e0a..9076a9b 100644 --- a/chrome/browser/ui/views/ime_driver/remote_text_input_client.h +++ b/chrome/browser/ui/views/ime_driver/remote_text_input_client.h
@@ -66,7 +66,7 @@ void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override; ukm::SourceId GetClientSourceForMetrics() const override; bool ShouldDoLearning() override; - void SetCompositionFromExistingText( + bool SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
diff --git a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc index 8d025b3b9..d6af447 100644 --- a/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc +++ b/chrome/browser/ui/views/tabs/tab_drag_controller_interactive_uitest.cc
@@ -1788,20 +1788,8 @@ // Right snap the browser window. aura::Window* window = browser()->window()->GetNativeWindow(); - if (features::IsUsingWindowService()) { - ash::mojom::ShellTestApiPtr shell_test_api; - content::ServiceManagerConnection::GetForProcess() - ->GetConnector() - ->BindInterface(ash::mojom::kServiceName, &shell_test_api); - ash::mojom::ShellTestApiAsyncWaiter shell_waiter(shell_test_api.get()); - shell_waiter.SnapWindowInSplitView( - content::mojom::kBrowserServiceName, - aura::WindowMus::Get(window->GetRootWindow())->server_id(), false); - } else { - ash::Shell* shell = ash::Shell::Get(); - shell->split_view_controller()->SnapWindow(window, - ash::SplitViewController::RIGHT); - } + ash::Shell::Get()->split_view_controller()->SnapWindow( + window, ash::SplitViewController::RIGHT); EXPECT_NE(gfx::Point(), window->GetBoundsInScreen().origin()); DragWindowAndVerifyOffset(this, GetTabStripForBrowser(browser()), 0);
diff --git a/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.cc b/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.cc index bf07b1d5..01aed9f 100644 --- a/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.cc +++ b/chrome/browser/ui/webui/chromeos/login/screenlock_icon_source.cc
@@ -43,10 +43,8 @@ } GURL url(chrome::kChromeUIScreenlockIconURL + path); - std::string username = net::UnescapeURLComponent( - url.path().substr(1), - net::UnescapeRule::URL_SPECIAL_CHARS_EXCEPT_PATH_SEPARATORS | - net::UnescapeRule::PATH_SEPARATORS | net::UnescapeRule::SPACES); + std::string username = + net::UnescapeBinaryURLComponent(url.path_piece().substr(1)); gfx::Image image = icon_provider_->GetIcon(username); if (image.IsEmpty()) {
diff --git a/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.cc b/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.cc index e12cdea..c1e7f2e 100644 --- a/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.cc +++ b/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.cc
@@ -112,6 +112,10 @@ void SupervisionTransitionScreenHandler::Hide() {} +base::OneShotTimer* SupervisionTransitionScreenHandler::GetTimerForTesting() { + return &timer_; +} + void SupervisionTransitionScreenHandler::Initialize() { profile_ = ProfileManager::GetPrimaryUserProfile();
diff --git a/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h b/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h index 3dca4ba..5785e0e6 100644 --- a/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h +++ b/chrome/browser/ui/webui/chromeos/login/supervision_transition_screen_handler.h
@@ -60,6 +60,8 @@ void Show() override; void Hide() override; + base::OneShotTimer* GetTimerForTesting(); + private: // BaseScreenHandler: void Initialize() override;
diff --git a/chrome/browser/vr/test/webxr_vr_browser_test.h b/chrome/browser/vr/test/webxr_vr_browser_test.h index d3f19a2..8b3dfb2 100644 --- a/chrome/browser/vr/test/webxr_vr_browser_test.h +++ b/chrome/browser/vr/test/webxr_vr_browser_test.h
@@ -83,6 +83,14 @@ } }; +class WebXrVrBrowserTestWMR : public WebXrVrBrowserTestBase { + public: + WebXrVrBrowserTestWMR() { + // WMR already enabled by default. + enable_features_.push_back(features::kWebXr); + } +}; + // Test class with WebXR disabled. class WebXrVrBrowserTestWebXrDisabled : public WebXrVrBrowserTestBase { public:
diff --git a/chrome/browser/vr/webxr_vr_input_browser_test.cc b/chrome/browser/vr/webxr_vr_input_browser_test.cc index d3405e96..ea8f48cd6 100644 --- a/chrome/browser/vr/webxr_vr_input_browser_test.cc +++ b/chrome/browser/vr/webxr_vr_input_browser_test.cc
@@ -422,30 +422,40 @@ return array_string; } -// Test that head pose changes in OpenVR are properly reflected in the viewer -// pose provided by WebXR. -IN_PROC_BROWSER_TEST_F(WebXrVrBrowserTestStandard, TestHeadPosesUpdate) { +void TestHeadPosesUpdateImpl(WebXrVrBrowserTestBase* t) { WebXrHeadPoseMock my_mock; - this->LoadUrlAndAwaitInitialization( - this->GetFileUrlForHtmlTestFile("webxr_test_head_poses")); - this->EnterSessionWithUserGestureOrFail(); + t->LoadUrlAndAwaitInitialization( + t->GetFileUrlForHtmlTestFile("webxr_test_head_poses")); + t->EnterSessionWithUserGestureOrFail(); auto pose = gfx::Transform(); my_mock.SetHeadPose(pose); - this->RunJavaScriptOrFail("stepWaitForMatchingPose(" + - TransformToColMajorString(pose) + ")"); - this->WaitOnJavaScriptStep(); + t->RunJavaScriptOrFail("stepWaitForMatchingPose(" + + TransformToColMajorString(pose) + ")"); + t->WaitOnJavaScriptStep(); // No significance to this new transform other than that it's easy to tell // whether the correct pose got piped through to WebXR or not. pose.RotateAboutXAxis(90); pose.Translate3d(2, 3, 4); my_mock.SetHeadPose(pose); - this->RunJavaScriptOrFail("stepWaitForMatchingPose(" + - TransformToColMajorString(pose) + ")"); - this->WaitOnJavaScriptStep(); - this->AssertNoJavaScriptErrors(); + t->RunJavaScriptOrFail("stepWaitForMatchingPose(" + + TransformToColMajorString(pose) + ")"); + t->WaitOnJavaScriptStep(); + t->AssertNoJavaScriptErrors(); +} + +// Test that head pose changes in OpenVR are properly reflected in the viewer +// pose provided by WebXR. +IN_PROC_BROWSER_TEST_F(WebXrVrBrowserTestStandard, TestHeadPosesUpdate) { + TestHeadPosesUpdateImpl(this); +} + +// Tests that head pose changes in WMR are properly reflected in the viewer pose +// provided by WebXR. +IN_PROC_BROWSER_TEST_F(WebXrVrBrowserTestWMR, TestHeadPosesUpdate) { + TestHeadPosesUpdateImpl(this); } } // namespace vr
diff --git a/chrome/services/isolated_xr_device/xr_service_test_hook.cc b/chrome/services/isolated_xr_device/xr_service_test_hook.cc index 03320cab8..7ebe7ac4 100644 --- a/chrome/services/isolated_xr_device/xr_service_test_hook.cc +++ b/chrome/services/isolated_xr_device/xr_service_test_hook.cc
@@ -7,6 +7,7 @@ #include "base/process/process.h" #include "chrome/services/isolated_xr_device/xr_test_hook_wrapper.h" #include "device/vr/openvr/openvr_api_wrapper.h" +#include "device/vr/windows_mixed_reality/mixed_reality_statics.h" namespace device { @@ -18,8 +19,9 @@ hook ? std::make_unique<XRTestHookWrapper>(hook.PassInterface()) : nullptr; - // Register the wrapper testhook with OpenVR. + // Register the wrapper testhook with OpenVR and WMR. OpenVRWrapper::SetTestHook(wrapper.get()); + MixedRealityDeviceStatics::SetTestHook(wrapper.get()); // Store the new wrapper, so we keep it alive. wrapper_ = std::move(wrapper); @@ -43,7 +45,7 @@ // Unset the testhook wrapper with OpenVR, so any // future calls to OpenVR don't use it. OpenVRWrapper::SetTestHook(nullptr); - + MixedRealityDeviceStatics::SetTestHook(nullptr); // Destroy the test hook wrapper on this thread. }, std::move(wrapper_)));
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn index 858160c6..545e8597 100644 --- a/chrome/test/BUILD.gn +++ b/chrome/test/BUILD.gn
@@ -1896,6 +1896,7 @@ "../browser/chromeos/login/screens/recommend_apps/scoped_test_recommend_apps_fetcher_factory.h", "../browser/chromeos/login/screens/recommend_apps_screen_browsertest.cc", "../browser/chromeos/login/screens/supervision_onboarding_screen_browsertest.cc", + "../browser/chromeos/login/screens/supervision_transition_screen_browsertest.cc", "../browser/chromeos/login/screens/update_screen_browsertest.cc", "../browser/chromeos/login/screens/user_selection_screen_browsertest.cc", "../browser/chromeos/login/screens/welcome_screen_browsertest.cc", @@ -3628,10 +3629,13 @@ "../browser/media/router/providers/cast/cast_internal_message_util_unittest.cc", "../browser/media/router/providers/cast/cast_media_route_provider_metrics_unittest.cc", "../browser/media/router/providers/cast/cast_media_route_provider_unittest.cc", + "../browser/media/router/providers/cast/cast_session_client_unittest.cc", "../browser/media/router/providers/cast/cast_session_tracker_unittest.cc", "../browser/media/router/providers/cast/dual_media_sink_service_unittest.cc", "../browser/media/router/providers/cast/mock_cast_activity_record.cc", "../browser/media/router/providers/cast/mock_cast_activity_record.h", + "../browser/media/router/providers/cast/test_util.cc", + "../browser/media/router/providers/cast/test_util.h", "../browser/media/router/providers/dial/dial_activity_manager_unittest.cc", "../browser/media/router/providers/dial/dial_internal_message_util_unittest.cc", "../browser/media/router/providers/dial/dial_media_route_provider_unittest.cc",
diff --git a/chrome/test/base/web_ui_browser_test.cc b/chrome/test/base/web_ui_browser_test.cc index 4d711723..0f649b1 100644 --- a/chrome/test/base/web_ui_browser_test.cc +++ b/chrome/test/base/web_ui_browser_test.cc
@@ -42,6 +42,12 @@ #include "printing/buildflags/buildflags.h" #include "ui/base/resource/resource_handle.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/crostini/crostini_pref_names.h" +#include "chrome/common/chrome_features.h" +#include "components/prefs/pref_service.h" +#endif + #if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/printing/print_preview_dialog_controller.h" #endif @@ -464,6 +470,12 @@ mock_provider_.Pointer()); test_factory_->AddFactoryOverride(content::kChromeUIResourcesHost, mock_provider_.Pointer()); + +#if defined(OS_CHROMEOS) + scoped_feature_list_.InitAndEnableFeature(features::kCrostini); + browser()->profile()->GetPrefs()->SetBoolean( + crostini::prefs::kCrostiniEnabled, true); +#endif } void BaseWebUIBrowserTest::TearDownOnMainThread() {
diff --git a/chrome/test/base/web_ui_browser_test.h b/chrome/test/base/web_ui_browser_test.h index af987c7..5de7b0b 100644 --- a/chrome/test/base/web_ui_browser_test.h +++ b/chrome/test/base/web_ui_browser_test.h
@@ -13,6 +13,10 @@ #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/javascript_browser_test.h" +#if defined(OS_CHROMEOS) +#include "base/test/scoped_feature_list.h" +#endif + namespace { class WebUITestMessageHandler; } @@ -174,6 +178,9 @@ content::WebUI* override_selected_web_ui_; std::unique_ptr<TestChromeWebUIControllerFactory> test_factory_; +#if defined(OS_CHROMEOS) + base::test::ScopedFeatureList scoped_feature_list_; +#endif }; class WebUIBrowserTest : public BaseWebUIBrowserTest {
diff --git a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js index 2417079..cb0bd8c 100644 --- a/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js +++ b/chrome/test/data/extensions/api_test/file_browser/mount_test/test.js
@@ -9,7 +9,7 @@ sourcePath: 'device_path1', volumeType: 'removable', deviceType: 'usb', - devicePath: 'system_path_prefix1', + devicePath: 'storage_device_path1', isParentDevice: false, isReadOnly: false, isReadOnlyRemovableDevice: false, @@ -29,7 +29,7 @@ sourcePath: 'device_path2', volumeType: 'removable', deviceType: 'mobile', - devicePath: 'system_path_prefix2', + devicePath: 'storage_device_path2', isParentDevice: true, isReadOnly: true, isReadOnlyRemovableDevice: true, @@ -51,7 +51,7 @@ sourcePath: 'device_path3', volumeType: 'removable', deviceType: 'optical', - devicePath: 'system_path_prefix3', + devicePath: 'storage_device_path3', isParentDevice: true, isReadOnly: true, isReadOnlyRemovableDevice: false,
diff --git a/chrome/test/data/extensions/api_test/input_method/basic/background.js b/chrome/test/data/extensions/api_test/input_method/basic/background.js index 1f22a507..acc277c1 100644 --- a/chrome/test/data/extensions/api_test/input_method/basic/background.js +++ b/chrome/test/data/extensions/api_test/input_method/basic/background.js
@@ -2,198 +2,164 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var kNewInputMethodTemplate = '_comp_ime_{EXT_ID}xkb:fr::fra'; -var kInitialInputMethodRegex = /_comp_ime_([a-z]{32})xkb:us::eng/; -var kInvalidInputMethod = 'xx::xxx'; - -var testParams = { +const testParams = { initialInputMethod: '', newInputMethod: '', dictionaryLoaded: null, }; -// The tests needs to be executed in order. - -function initTests() { - console.log('initTest: Getting initial inputMethod'); - chrome.inputMethodPrivate.getCurrentInputMethod(function(inputMethod) { - testParams.initialInputMethod = inputMethod; - - var match = inputMethod.match(kInitialInputMethodRegex); - chrome.test.assertTrue(!!match); - chrome.test.assertEq(2, match.length); - var extensionId = match[1]; - testParams.newInputMethod = - kNewInputMethodTemplate.replace('{EXT_ID}', extensionId); - chrome.test.succeed(); - }); -} - -function setTest() { - chrome.test.assertTrue(!!testParams.newInputMethod); - console.log( - 'setTest: Changing input method to: ' + testParams.newInputMethod); - chrome.inputMethodPrivate.setCurrentInputMethod(testParams.newInputMethod, - function() { - chrome.test.assertTrue( - !chrome.runtime.lastError, - chrome.runtime.lastError ? chrome.runtime.lastError.message : ''); - chrome.test.succeed(); +// Wrap inputMethodPrivate in a promise-based API to simplify test code. +function wrapAsync(apiFunction) { + return (...args) => { + return new Promise((resolve, reject) => { + apiFunction(...args, (...result) => { + if (!!chrome.runtime.lastError) { + reject(Error(chrome.runtime.lastError)); + } else { + resolve(...result); + } + }); }); + } } -function getTest() { - chrome.test.assertTrue(!!testParams.newInputMethod); - console.log('getTest: Getting current input method.'); - chrome.inputMethodPrivate.getCurrentInputMethod(function(inputMethod) { +const asyncInputMethodPrivate = { + getCurrentInputMethod: + wrapAsync(chrome.inputMethodPrivate.getCurrentInputMethod), + setCurrentInputMethod: + wrapAsync(chrome.inputMethodPrivate.setCurrentInputMethod), + getInputMethods: + wrapAsync(chrome.inputMethodPrivate.getInputMethods), + fetchAllDictionaryWords: + wrapAsync(chrome.inputMethodPrivate.fetchAllDictionaryWords), + addWordToDictionary: + wrapAsync(chrome.inputMethodPrivate.addWordToDictionary) +}; + +chrome.test.sendMessage('ready'); + +chrome.test.runTests([ + // Queries the system for basic information needed for tests. + // Needs to run first. + async function initTests() { + console.log('initTest: Getting initial inputMethod'); + + const initialInputMethod = + await asyncInputMethodPrivate.getCurrentInputMethod(); + const match = initialInputMethod.match(/_comp_ime_([a-z]{32})xkb:us::eng/); + chrome.test.assertTrue(!!match); + + const extensionId = match[1]; + testParams.initialInputMethod = initialInputMethod; + testParams.newInputMethod = `_comp_ime_${extensionId}xkb:fr::fra`; + chrome.test.succeed(); + }, + + async function setTest() { + console.log( + 'setTest: Changing input method to: ' + testParams.newInputMethod); + await asyncInputMethodPrivate.setCurrentInputMethod( + testParams.newInputMethod); + chrome.test.succeed(); + }, + + async function getTest() { + console.log('getTest: Getting current input method.'); + const inputMethod = await asyncInputMethodPrivate.getCurrentInputMethod(); chrome.test.assertEq(testParams.newInputMethod, inputMethod); chrome.test.succeed(); - }); -} + }, -function observeTest() { - chrome.test.assertTrue(!!testParams.initialInputMethod); - console.log('observeTest: Adding input method event listener.'); + async function observeTest() { + console.log('observeTest: Adding input method event listener.'); - var listener = function(inputMethod) { - chrome.inputMethodPrivate.onChanged.removeListener(listener); - chrome.test.assertEq(testParams.initialInputMethod, inputMethod); - chrome.test.succeed(); - }; - chrome.inputMethodPrivate.onChanged.addListener(listener); + chrome.inputMethodPrivate.onChanged.addListener( + function listener (inputMethod) { + chrome.inputMethodPrivate.onChanged.removeListener(listener); + chrome.test.assertEq(testParams.initialInputMethod, inputMethod); + chrome.test.succeed(); + }); - console.log('observeTest: Changing input method to: ' + - testParams.initialInputMethod); - chrome.inputMethodPrivate.setCurrentInputMethod( - testParams.initialInputMethod); -} + console.log('observeTest: Changing input method to: ' + + testParams.initialInputMethod); + await asyncInputMethodPrivate.setCurrentInputMethod( + testParams.initialInputMethod); + }, + async function setInvalidTest() { + const kInvalidInputMethod = 'xx::xxx'; + console.log( + 'setInvalidTest: Changing input method to: ' + kInvalidInputMethod); + asyncInputMethodPrivate.setCurrentInputMethod(kInvalidInputMethod) + .catch(chrome.test.succeed); + }, -function setInvalidTest() { - console.log( - 'setInvalidTest: Changing input method to: ' + kInvalidInputMethod); - chrome.inputMethodPrivate.setCurrentInputMethod(kInvalidInputMethod, - function() { - chrome.test.assertTrue(!!chrome.runtime.lastError); - chrome.test.succeed(); - }); -} + async function getListTest() { + console.log('getListTest: Getting input method list.'); -function getListTest() { - chrome.test.assertTrue(!!testParams.initialInputMethod); - chrome.test.assertTrue(!!testParams.newInputMethod); - console.log('getListTest: Getting input method list.'); - - chrome.inputMethodPrivate.getInputMethods(function(inputMethods) { + const inputMethods = await asyncInputMethodPrivate.getInputMethods(); chrome.test.assertEq(7, inputMethods.length); - var foundInitialInputMethod = false; - var foundNewInputMethod = false; - for (var i = 0; i < inputMethods.length; ++i) { - if (inputMethods[i].id == testParams.initialInputMethod) - foundInitialInputMethod = true; - if (inputMethods[i].id == testParams.newInputMethod) - foundNewInputMethod = true; - } - chrome.test.assertTrue(foundInitialInputMethod); - chrome.test.assertTrue(foundNewInputMethod); + + chrome.test.assertTrue( + inputMethods.some((im) => im.id == testParams.initialInputMethod)); + chrome.test.assertTrue( + inputMethods.some((im) => im.id == testParams.newInputMethod)); chrome.test.succeed(); - }); -} + }, -// Helper function -function getFetchPromise() { - return new Promise(function(resolve, reject) { - chrome.inputMethodPrivate.fetchAllDictionaryWords(function(words) { - if (!!chrome.runtime.lastError) { - reject(Error(chrome.runtime.lastError)); - } else { - resolve(words); - } - }); - }); -} + async function loadDictionaryAsyncTest() { + console.log('loadDictionaryAsyncTest: '); -// Helper function -function getAddPromise(word) { - return new Promise(function(resolve, reject) { - chrome.inputMethodPrivate.addWordToDictionary(word, function() { - if (!!chrome.runtime.lastError) { - reject(Error(chrome.runtime.lastError)); - } else { - resolve(); - } - }); - }); -} - -function loadDictionaryAsyncTest() { - testParams.dictionaryLoaded = new Promise(function(resolve, reject) { - var message = 'before'; - chrome.inputMethodPrivate.onDictionaryLoaded.addListener( - function listener() { + testParams.dictionaryLoaded = new Promise((resolve, reject) => { + var message = 'before'; + chrome.inputMethodPrivate.onDictionaryLoaded.addListener( + function listener () { chrome.inputMethodPrivate.onDictionaryLoaded.removeListener(listener); chrome.test.assertEq(message, 'after'); resolve(); }); - message = 'after'; - }); - // We don't need to wait for the promise to resolve before continuing since - // promises are async wrappers. - chrome.test.succeed(); -} + message = 'after'; + }); + // We don't need to wait for the promise to resolve before continuing since + // promises are async wrappers. + chrome.test.succeed(); + }, -function fetchDictionaryTest() { - testParams.dictionaryLoaded - .then(function () { - return getFetchPromise(); - }) - .then(function confirmFetch(words) { - chrome.test.assertTrue(words !== undefined); - chrome.test.assertTrue(words.length === 0); + async function fetchDictionaryTest() { + await testParams.dictionaryLoaded; + const words = await asyncInputMethodPrivate.fetchAllDictionaryWords(); + chrome.test.assertTrue(words !== undefined); + chrome.test.assertEq(0, words.length); + chrome.test.succeed(); + }, + + async function addWordToDictionaryTest() { + const wordToAdd = 'helloworld'; + await testParams.dictionaryLoaded; + await asyncInputMethodPrivate.addWordToDictionary(wordToAdd); + const words = await asyncInputMethodPrivate.fetchAllDictionaryWords(); + chrome.test.assertEq(1, words.length); + chrome.test.assertEq(words[0], wordToAdd); + chrome.test.succeed(); + }, + + async function addDuplicateWordToDictionaryTest() { + await testParams.dictionaryLoaded; + asyncInputMethodPrivate.addWordToDictionary('helloworld') + .catch(chrome.test.succeed); + }, + + async function dictionaryChangedTest() { + const wordToAdd = 'helloworld2'; + await testParams.dictionaryLoaded; + chrome.inputMethodPrivate.onDictionaryChanged.addListener( + function listener(added, removed) { + chrome.inputMethodPrivate.onDictionaryChanged.removeListener(listener); + chrome.test.assertEq(1, added.length); + chrome.test.assertEq(0, removed.length); + chrome.test.assertEq(added[0], wordToAdd); chrome.test.succeed(); }); -} - -function addWordToDictionaryTest() { - var wordToAdd = 'helloworld'; - testParams.dictionaryLoaded - .then(function() { - return getAddPromise(wordToAdd); - }) - // Adding the same word results in an error. - .then(function() { - return getAddPromise(wordToAdd); - }) - .catch(function(error) { - chrome.test.assertTrue(!!error.message); - return getFetchPromise(); - }) - .then(function(words) { - chrome.test.assertTrue(words.length === 1); - chrome.test.assertEq(words[0], wordToAdd); - chrome.test.succeed(); - }); -} - -function dictionaryChangedTest() { - var wordToAdd = 'helloworld2'; - testParams.dictionaryLoaded - .then(function() { - chrome.inputMethodPrivate.onDictionaryChanged.addListener( - function(added, removed) { - chrome.test.assertTrue(added.length === 1); - chrome.test.assertTrue(removed.length === 0); - chrome.test.assertEq(added[0], wordToAdd); - chrome.test.succeed(); - }); - }) - .then(function() { - return getAddPromise(wordToAdd); - }); -} - -chrome.test.sendMessage('ready'); -chrome.test.runTests( - [initTests, setTest, getTest, observeTest, setInvalidTest, getListTest, - loadDictionaryAsyncTest, fetchDictionaryTest, addWordToDictionaryTest, - dictionaryChangedTest]); + await asyncInputMethodPrivate.addWordToDictionary(wordToAdd); + } +]);
diff --git a/chrome/test/data/webui/BUILD.gn b/chrome/test/data/webui/BUILD.gn index efedeb6..6771b592 100644 --- a/chrome/test/data/webui/BUILD.gn +++ b/chrome/test/data/webui/BUILD.gn
@@ -97,6 +97,11 @@ "../chromeos/oobe_webui_browsertest.js", "certificate_viewer_dialog_test.js", "set_time_dialog_browsertest.js", + "settings/a11y/crostini_settings_details_a11y_test.js", + "settings/a11y/crostini_settings_export_import_a11y_test.js", + "settings/a11y/crostini_settings_shared_paths_a11y_test.js", + "settings/a11y/crostini_settings_shared_usb_devices_a11y_test.js", + "settings/a11y/crostini_settings_subpage_a11y_test.js", "settings/a11y/manage_accessibility_a11y_test.js", "settings/a11y/multidevice_a11y_test.js", "settings/a11y/multidevice_features_a11y_test.js",
diff --git a/chrome/test/data/webui/app_management/app_test.js b/chrome/test/data/webui/app_management/app_test.js index 9be0685..07cad44 100644 --- a/chrome/test/data/webui/app_management/app_test.js +++ b/chrome/test/data/webui/app_management/app_test.js
@@ -56,32 +56,37 @@ assert(app.$$('app-management-search-view')); }); - test('App list renders on page change', async (done) => { + test('App list renders on page change', (done) => { const appList = getAppList(); + let numApps = 0; - await fakeHandler.addApp(); - let numApps = 1; + fakeHandler.addApp() + .then(() => { + numApps = 1; + expectEquals(numApps, appList.numChildrenForTesting_); - expectEquals(numApps, appList.numChildrenForTesting_); + // Click app to go to detail page. + appList.querySelector('app-management-app-item').click(); + return PolymerTest.flushTasks(); + }) + .then(() => { + return fakeHandler.addApp(); + }) + .then(() => { + numApps++; - // Click app to go to detail page. - appList.querySelector('app-management-app-item').click(); - await PolymerTest.flushTasks(); + appList.addEventListener('num-children-for-testing_-changed', () => { + expectEquals(numApps, appList.numChildrenForTesting_); + done(); + }); - await fakeHandler.addApp(); - numApps++; - - appList.addEventListener('num-children-for-testing_-changed', () => { - expectEquals(numApps, appList.numChildrenForTesting_); - done(); - }); - - // Click back button to go to main page. - app.$$('app-management-pwa-permission-view') - .$$('app-management-permission-view-header') - .$$('#backButton') - .click(); - await PolymerTest.flushTasks(); + // Click back button to go to main page. + app.$$('app-management-pwa-permission-view') + .$$('app-management-permission-view-header') + .$$('#backButton') + .click(); + PolymerTest.flushTasks(); + }); }); test('Search from main page', async () => {
diff --git a/chrome/test/data/webui/history/history_synced_tabs_test.js b/chrome/test/data/webui/history/history_synced_tabs_test.js index 3296ea4..f615b36 100644 --- a/chrome/test/data/webui/history/history_synced_tabs_test.js +++ b/chrome/test/data/webui/history/history_synced_tabs_test.js
@@ -177,7 +177,7 @@ setForeignSessions(sessionList); - return PolymerTest.flushTasks() + PolymerTest.flushTasks() .then(function() { const cards = getCards(element); assertEquals(2, cards.length);
diff --git a/chrome/test/data/webui/settings/a11y/crostini_settings_details_a11y_test.js b/chrome/test/data/webui/settings/a11y/crostini_settings_details_a11y_test.js new file mode 100644 index 0000000..6888f0c --- /dev/null +++ b/chrome/test/data/webui/settings/a11y/crostini_settings_details_a11y_test.js
@@ -0,0 +1,29 @@ +// Copyright 2019 The Chromium 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 Define accessibility tests for the CROSTINI_DETAILS route. + * Chrome OS only. + */ + +// SettingsAccessibilityTest fixture. +GEN_INCLUDE([ + 'settings_accessibility_test.js', +]); + +AccessibilityTest.define('SettingsAccessibilityTest', { + /** @override */ + name: 'CROSTINI_DETAILS', + /** @override */ + axeOptions: SettingsAccessibilityTest.axeOptions, + /** @override */ + setup: function() { + settings.navigateTo(settings.routes.CROSTINI_DETAILS); + Polymer.dom.flush(); + }, + /** @override */ + tests: {'Accessible with No Changes': function() {}}, + /** @override */ + violationFilter: SettingsAccessibilityTest.violationFilter, +});
diff --git a/chrome/test/data/webui/settings/a11y/crostini_settings_export_import_a11y_test.js b/chrome/test/data/webui/settings/a11y/crostini_settings_export_import_a11y_test.js new file mode 100644 index 0000000..7210acc --- /dev/null +++ b/chrome/test/data/webui/settings/a11y/crostini_settings_export_import_a11y_test.js
@@ -0,0 +1,30 @@ +// Copyright 2019 The Chromium 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 Define accessibility tests for the CROSTINI_EXPORT_IMPORT + * route. + * Chrome OS only. + */ + +// SettingsAccessibilityTest fixture. +GEN_INCLUDE([ + 'settings_accessibility_test.js', +]); + +AccessibilityTest.define('SettingsAccessibilityTest', { + /** @override */ + name: 'CROSTINI_EXPORT_IMPORT', + /** @override */ + axeOptions: SettingsAccessibilityTest.axeOptions, + /** @override */ + setup: function() { + settings.router.navigateTo(settings.routes.CROSTINI_EXPORT_IMPORT); + Polymer.dom.flush(); + }, + /** @override */ + tests: {'Accessible with No Changes': function() {}}, + /** @override */ + violationFilter: SettingsAccessibilityTest.violationFilter, +});
diff --git a/chrome/test/data/webui/settings/a11y/crostini_settings_shared_paths_a11y_test.js b/chrome/test/data/webui/settings/a11y/crostini_settings_shared_paths_a11y_test.js new file mode 100644 index 0000000..bcfe268f --- /dev/null +++ b/chrome/test/data/webui/settings/a11y/crostini_settings_shared_paths_a11y_test.js
@@ -0,0 +1,29 @@ +// Copyright 2019 The Chromium 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 Define accessibility tests for the CROSTINI_SHARED_PATHS route. + * Chrome OS only. + */ + +// SettingsAccessibilityTest fixture. +GEN_INCLUDE([ + 'settings_accessibility_test.js', +]); + +AccessibilityTest.define('SettingsAccessibilityTest', { + /** @override */ + name: 'CROSTINI_SHARED_PATHS', + /** @override */ + axeOptions: SettingsAccessibilityTest.axeOptions, + /** @override */ + setup: function() { + settings.router.navigateTo(settings.routes.CROSTINI_SHARED_PATHS); + Polymer.dom.flush(); + }, + /** @override */ + tests: {'Accessible with No Changes': function() {}}, + /** @override */ + violationFilter: SettingsAccessibilityTest.violationFilter, +});
diff --git a/chrome/test/data/webui/settings/a11y/crostini_settings_shared_usb_devices_a11y_test.js b/chrome/test/data/webui/settings/a11y/crostini_settings_shared_usb_devices_a11y_test.js new file mode 100644 index 0000000..a8fe791 --- /dev/null +++ b/chrome/test/data/webui/settings/a11y/crostini_settings_shared_usb_devices_a11y_test.js
@@ -0,0 +1,30 @@ +// Copyright 2019 The Chromium 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 Define accessibility tests for the CROSTINI_SHARED_USB_DEVICES + * route. + * Chrome OS only. + */ + +// SettingsAccessibilityTest fixture. +GEN_INCLUDE([ + 'settings_accessibility_test.js', +]); + +AccessibilityTest.define('SettingsAccessibilityTest', { + /** @override */ + name: 'CROSTINI_SHARED_USB_DEVICES', + /** @override */ + axeOptions: SettingsAccessibilityTest.axeOptions, + /** @override */ + setup: function() { + settings.router.navigateTo(settings.routes.CROSTINI_SHARED_USB_DEVICES); + Polymer.dom.flush(); + }, + /** @override */ + tests: {'Accessible with No Changes': function() {}}, + /** @override */ + violationFilter: SettingsAccessibilityTest.violationFilter, +});
diff --git a/chrome/test/data/webui/settings/a11y/crostini_settings_subpage_a11y_test.js b/chrome/test/data/webui/settings/a11y/crostini_settings_subpage_a11y_test.js new file mode 100644 index 0000000..9307c23 --- /dev/null +++ b/chrome/test/data/webui/settings/a11y/crostini_settings_subpage_a11y_test.js
@@ -0,0 +1,29 @@ +// Copyright 2019 The Chromium 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 Define accessibility tests for the CROSTINI route. + * Chrome OS only. + */ + +// SettingsAccessibilityTest fixture. +GEN_INCLUDE([ + 'settings_accessibility_test.js', +]); + +AccessibilityTest.define('SettingsAccessibilityTest', { + /** @override */ + name: 'CROSTINI', + /** @override */ + axeOptions: SettingsAccessibilityTest.axeOptions, + /** @override */ + setup: function() { + settings.router.navigateTo(settings.routes.CROSTINI); + Polymer.dom.flush(); + }, + /** @override */ + tests: {'Accessible with No Changes': function() {}}, + /** @override */ + violationFilter: SettingsAccessibilityTest.violationFilter, +});
diff --git a/chrome/test/data/webui/settings/payments_section_test.js b/chrome/test/data/webui/settings/payments_section_test.js index 14a49a7..1de01370 100644 --- a/chrome/test/data/webui/settings/payments_section_test.js +++ b/chrome/test/data/webui/settings/payments_section_test.js
@@ -303,7 +303,7 @@ const creditCard = FakeDataMaker.emptyCreditCardEntry(); const creditCardDialog = createCreditCardDialog(creditCard); - return test_util.whenAttributeIs(creditCardDialog.$.dialog, 'open', '') + test_util.whenAttributeIs(creditCardDialog.$.dialog, 'open', '') .then(function() { test_util.eventToPromise('save-credit-card', creditCardDialog) .then(function() {
diff --git a/chromecast/browser/url_request_context_factory.cc b/chromecast/browser/url_request_context_factory.cc index 692efc0..ed3e3c8 100644 --- a/chromecast/browser/url_request_context_factory.cc +++ b/chromecast/browser/url_request_context_factory.cc
@@ -38,8 +38,6 @@ #include "net/http/http_server_properties_impl.h" #include "net/http/http_stream_factory.h" #include "net/proxy_resolution/proxy_resolution_service.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/default_channel_id_store.h" #include "net/ssl/ssl_config_service_defaults.h" #include "net/url_request/data_protocol_handler.h" #include "net/url_request/file_protocol_handler.h" @@ -433,7 +431,6 @@ const std::unique_ptr<CastNetworkDelegate>& network_delegate, const std::unique_ptr<net::HostResolver>& host_resolver) { // common settings - context->set_channel_id_service(channel_id_service_.get()); context->set_cert_verifier(cert_verifier_.get()); context->set_cert_transparency_verifier(cert_transparency_verifier_.get()); context->set_ct_policy_enforcer(ct_policy_enforcer_.get());
diff --git a/chromecast/browser/url_request_context_factory.h b/chromecast/browser/url_request_context_factory.h index 3337110..92d7bcf5 100644 --- a/chromecast/browser/url_request_context_factory.h +++ b/chromecast/browser/url_request_context_factory.h
@@ -18,7 +18,6 @@ } namespace net { -class ChannelIDService; class CookieStore; class HostResolver; class HostResolverManager; @@ -115,7 +114,6 @@ // instance of URLRequestContext only. bool system_dependencies_initialized_; std::unique_ptr<net::HostResolverManager> host_resolver_manager_; - std::unique_ptr<net::ChannelIDService> channel_id_service_; std::unique_ptr<net::CertVerifier> cert_verifier_; std::unique_ptr<net::SSLConfigService> ssl_config_service_; std::unique_ptr<net::TransportSecurityState> transport_security_state_;
diff --git a/chromeos/disks/disk.cc b/chromeos/disks/disk.cc index 20f55f7..801795a83 100644 --- a/chromeos/disks/disk.cc +++ b/chromeos/disks/disk.cc
@@ -30,7 +30,7 @@ product_id_(disk_info.product_id()), product_name_(disk_info.product_name()), fs_uuid_(disk_info.uuid()), - system_path_prefix_(disk_info.storage_device_path()), + storage_device_path_(disk_info.storage_device_path()), device_type_(disk_info.device_type()), total_size_in_bytes_(disk_info.total_size_in_bytes()), is_parent_(disk_info.is_drive()), @@ -123,9 +123,9 @@ return *this; } -Disk::Builder& Disk::Builder::SetSystemPathPrefix( - const std::string& system_path_prefix) { - disk_->system_path_prefix_ = system_path_prefix; +Disk::Builder& Disk::Builder::SetStorageDevicePath( + const std::string& storage_device_path) { + disk_->storage_device_path_ = storage_device_path; return *this; }
diff --git a/chromeos/disks/disk.h b/chromeos/disks/disk.h index c72585b..ca65f002 100644 --- a/chromeos/disks/disk.h +++ b/chromeos/disks/disk.h
@@ -75,9 +75,11 @@ // Returns the file system uuid string. const std::string& fs_uuid() const { return fs_uuid_; } - // Path of the system device this device's block is a part of. + // Path of the storage device this device's block is a part of. // (e.g. /sys/devices/pci0000:00/.../8:0:0:0/) - const std::string& system_path_prefix() const { return system_path_prefix_; } + const std::string& storage_device_path() const { + return storage_device_path_; + } // Device type. DeviceType device_type() const { return device_type_; } @@ -150,7 +152,7 @@ std::string product_id_; std::string product_name_; std::string fs_uuid_; - std::string system_path_prefix_; + std::string storage_device_path_; DeviceType device_type_ = DEVICE_TYPE_UNKNOWN; uint64_t total_size_in_bytes_ = 0; bool is_parent_ = false; @@ -182,7 +184,7 @@ Builder& SetProductId(const std::string& product_id); Builder& SetProductName(const std::string& product_name); Builder& SetFileSystemUUID(const std::string& fs_uuid); - Builder& SetSystemPathPrefix(const std::string& system_path_prefix); + Builder& SetStorageDevicePath(const std::string& storage_device_path_); Builder& SetDeviceType(DeviceType device_type); Builder& SetSizeInBytes(uint64_t total_size_in_bytes); Builder& SetIsParent(bool is_parent);
diff --git a/chromeos/disks/disk_mount_manager_unittest.cc b/chromeos/disks/disk_mount_manager_unittest.cc index 54d03a8..e69243fe 100644 --- a/chromeos/disks/disk_mount_manager_unittest.cc +++ b/chromeos/disks/disk_mount_manager_unittest.cc
@@ -51,7 +51,7 @@ const char* product_id; const char* product_name; const char* fs_uuid; - const char* system_path_prefix; + const char* storage_device_path; chromeos::DeviceType device_type; uint64_t size_in_bytes; bool is_read_only; @@ -546,7 +546,7 @@ .SetProductId(disk.product_id) .SetProductName(disk.product_name) .SetFileSystemUUID(disk.fs_uuid) - .SetSystemPathPrefix(disk.system_path_prefix) + .SetStorageDevicePath(disk.storage_device_path) .SetDeviceType(disk.device_type) .SetSizeInBytes(disk.size_in_bytes) .SetIsReadOnlyHardware(disk.is_read_only)
diff --git a/chromeos/disks/disk_unittest.cc b/chromeos/disks/disk_unittest.cc index 833d125..cc80986b 100644 --- a/chromeos/disks/disk_unittest.cc +++ b/chromeos/disks/disk_unittest.cc
@@ -133,7 +133,7 @@ EXPECT_EQ(kIdUuid, disk.fs_uuid()); EXPECT_EQ(kDeviceSize, disk.total_size_in_bytes()); EXPECT_EQ(DEVICE_TYPE_SD, disk.device_type()); - EXPECT_EQ(kStorageDevicePath, disk.system_path_prefix()); + EXPECT_EQ(kStorageDevicePath, disk.storage_device_path()); EXPECT_EQ(kBaseMountpath, disk.base_mount_path()); EXPECT_FALSE(disk.is_parent()); EXPECT_FALSE(disk.is_read_only());
diff --git a/chromeos/disks/mock_disk_mount_manager.cc b/chromeos/disks/mock_disk_mount_manager.cc index 1f5fc86d..5e8151c 100644 --- a/chromeos/disks/mock_disk_mount_manager.cc +++ b/chromeos/disks/mock_disk_mount_manager.cc
@@ -23,7 +23,7 @@ namespace { const char kTestSystemPath[] = "/this/system/path"; -const char kTestSystemPathPrefix[] = "/this/system"; +const char kTestStorageDevicePath[] = "/this/system"; const char kTestDevicePath[] = "/this/device/path"; const char kTestMountPath[] = "/media/foofoo"; const char kTestFilePath[] = "/this/file/path"; @@ -47,7 +47,7 @@ .SetProductId(kTestProductId) .SetProductName(kTestProductName) .SetFileSystemUUID(kTestUuid) - .SetSystemPathPrefix(kTestSystemPathPrefix) + .SetStorageDevicePath(kTestStorageDevicePath) .SetHasMedia(true) .SetOnRemovableDevice(true) .SetFileSystemType(kTestFileSystemType);
diff --git a/components/arc/ime/arc_ime_service.cc b/components/arc/ime/arc_ime_service.cc index 31b509d..4d1d1dd 100644 --- a/components/arc/ime/arc_ime_service.cc +++ b/components/arc/ime/arc_ime_service.cc
@@ -520,9 +520,13 @@ return is_personalized_learning_allowed_; } -void ArcImeService::SetCompositionFromExistingText( +bool ArcImeService::SetCompositionFromExistingText( const gfx::Range& range, - const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {} + const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { + // TODO(https://crbug.com/952757): Implement this method. + NOTIMPLEMENTED_LOG_ONCE(); + return false; +} // static void ArcImeService::SetOverrideDefaultDeviceScaleFactorForTesting(
diff --git a/components/arc/ime/arc_ime_service.h b/components/arc/ime/arc_ime_service.h index b3a3cba..ac5cade 100644 --- a/components/arc/ime/arc_ime_service.h +++ b/components/arc/ime/arc_ime_service.h
@@ -141,7 +141,7 @@ } ukm::SourceId GetClientSourceForMetrics() const override; bool ShouldDoLearning() override; - void SetCompositionFromExistingText( + bool SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
diff --git a/components/cronet/android/cronet_url_request_context_adapter.cc b/components/cronet/android/cronet_url_request_context_adapter.cc index 8bba2a9..083de9c2 100644 --- a/components/cronet/android/cronet_url_request_context_adapter.cc +++ b/components/cronet/android/cronet_url_request_context_adapter.cc
@@ -54,7 +54,6 @@ #include "net/nqe/network_quality_estimator_params.h" #include "net/proxy_resolution/proxy_config_service_android.h" #include "net/proxy_resolution/proxy_resolution_service.h" -#include "net/ssl/channel_id_service.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h"
diff --git a/components/cronet/cronet_url_request_context.cc b/components/cronet/cronet_url_request_context.cc index 3212188d..54e410e 100644 --- a/components/cronet/cronet_url_request_context.cc +++ b/components/cronet/cronet_url_request_context.cc
@@ -51,7 +51,6 @@ #include "net/net_buildflags.h" #include "net/nqe/network_quality_estimator_params.h" #include "net/proxy_resolution/proxy_resolution_service.h" -#include "net/ssl/channel_id_service.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h"
diff --git a/components/cronet/ios/cronet_environment.mm b/components/cronet/ios/cronet_environment.mm index 63213e3..b659dbdf 100644 --- a/components/cronet/ios/cronet_environment.mm +++ b/components/cronet/ios/cronet_environment.mm
@@ -46,7 +46,6 @@ #include "net/log/net_log_util.h" #include "net/proxy_resolution/proxy_resolution_service.h" #include "net/socket/ssl_client_socket.h" -#include "net/ssl/channel_id_service.h" #include "net/ssl/ssl_key_logger_impl.h" #include "net/third_party/quiche/src/quic/core/quic_versions.h" #include "net/url_request/url_request_context.h"
diff --git a/components/download/internal/common/download_stats.cc b/components/download/internal/common/download_stats.cc index b7367a0..84af453 100644 --- a/components/download/internal/common/download_stats.cc +++ b/components/download/internal/common/download_stats.cc
@@ -447,6 +447,29 @@ FILE_PATH_LITERAL(".configprofile"), // 362 FILE_PATH_LITERAL(".internetconnect"), // 363 FILE_PATH_LITERAL(".networkconnect"), // 364 + FILE_PATH_LITERAL(".bmp"), // 365 + FILE_PATH_LITERAL(".css"), // 366 + FILE_PATH_LITERAL(".ehtml"), // 367 + FILE_PATH_LITERAL(".flac"), // 368 + FILE_PATH_LITERAL(".ico"), // 369 + FILE_PATH_LITERAL(".jfif"), // 370 + FILE_PATH_LITERAL(".m4a"), // 371 + FILE_PATH_LITERAL(".m4v"), // 372 + FILE_PATH_LITERAL(".mpeg"), // 373 + FILE_PATH_LITERAL(".mpg"), // 374 + FILE_PATH_LITERAL(".oga"), // 375 + FILE_PATH_LITERAL(".ogg"), // 376 + FILE_PATH_LITERAL(".ogm"), // 377 + FILE_PATH_LITERAL(".ogv"), // 378 + FILE_PATH_LITERAL(".opus"), // 379 + FILE_PATH_LITERAL(".pjp"), // 380 + FILE_PATH_LITERAL(".pjpeg"), // 381 + FILE_PATH_LITERAL(".svgz"), // 382 + FILE_PATH_LITERAL(".text"), // 383 + FILE_PATH_LITERAL(".tiff"), // 384 + FILE_PATH_LITERAL(".weba"), // 385 + FILE_PATH_LITERAL(".webm"), // 386 + FILE_PATH_LITERAL(".xbm"), // 387 // NOTE! When you add a type here, please add the UMA value as a comment. // These must all match DownloadItem.DangerousFileType in // enums.xml. From 263 onward, they should also match
diff --git a/components/exo/client_controlled_shell_surface.cc b/components/exo/client_controlled_shell_surface.cc index 3a5e0604..2f11aace 100644 --- a/components/exo/client_controlled_shell_surface.cc +++ b/components/exo/client_controlled_shell_surface.cc
@@ -22,6 +22,7 @@ #include "ash/shell.h" #include "ash/wm/client_controlled_state.h" #include "ash/wm/drag_details.h" +#include "ash/wm/splitview/split_view_controller.h" #include "ash/wm/toplevel_window_event_handler.h" #include "ash/wm/window_positioning_utils.h" #include "ash/wm/window_properties.h"
diff --git a/components/exo/client_controlled_shell_surface_unittest.cc b/components/exo/client_controlled_shell_surface_unittest.cc index f07ba69..da9e0c57 100644 --- a/components/exo/client_controlled_shell_surface_unittest.cc +++ b/components/exo/client_controlled_shell_surface_unittest.cc
@@ -1229,14 +1229,14 @@ // again. SendGestureEvents(window, gfx::Point(0, 10)); EXPECT_TRUE(ash::wm::GetWindowState(window)->IsMaximized()); - EXPECT_FALSE(shell->overview_controller()->IsSelecting()); + EXPECT_FALSE(shell->overview_controller()->InOverviewSession()); // FLING the window not inisde preview area with large enough y veloicty // (larger than kFlingToOverviewThreshold) will drop the window into overview. SendGestureEvents( window, gfx::Point(400, 10), /*fling=*/true, ash::TabletModeWindowDragDelegate::kFlingToOverviewThreshold + 10.f); - ASSERT_TRUE(shell->overview_controller()->IsSelecting()); + ASSERT_TRUE(shell->overview_controller()->InOverviewSession()); EXPECT_TRUE( shell->overview_controller()->overview_session()->IsWindowInOverview( window));
diff --git a/components/exo/text_input.cc b/components/exo/text_input.cc index 5f037bc..22ff6db 100644 --- a/components/exo/text_input.cc +++ b/components/exo/text_input.cc
@@ -311,9 +311,13 @@ return should_do_learning_; } -void TextInput::SetCompositionFromExistingText( +bool TextInput::SetCompositionFromExistingText( const gfx::Range& range, - const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {} + const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { + // TODO(https://crbug.com/952757): Implement this method. + NOTIMPLEMENTED_LOG_ONCE(); + return false; +} void TextInput::OnKeyboardVisibilityStateChanged(bool is_visible) { delegate_->OnVirtualKeyboardVisibilityChanged(is_visible);
diff --git a/components/exo/text_input.h b/components/exo/text_input.h index 9672953d..ad19f87 100644 --- a/components/exo/text_input.h +++ b/components/exo/text_input.h
@@ -134,7 +134,7 @@ void SetTextEditCommandForNextKeyEvent(ui::TextEditCommand command) override; ukm::SourceId GetClientSourceForMetrics() const override; bool ShouldDoLearning() override; - void SetCompositionFromExistingText( + bool SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override;
diff --git a/components/gwp_asan/client/BUILD.gn b/components/gwp_asan/client/BUILD.gn index 2fb6098b..28647ade 100644 --- a/components/gwp_asan/client/BUILD.gn +++ b/components/gwp_asan/client/BUILD.gn
@@ -48,6 +48,7 @@ testonly = true sources = [ "guarded_page_allocator_unittest.cc", + "gwp_asan_unittest.cc", ] if (use_allocator_shim) { @@ -64,6 +65,7 @@ "//base/test:test_support", "//components/crash/core/common:crash_key", "//components/gwp_asan/common", + "//testing/gmock", "//testing/gtest", ] }
diff --git a/components/gwp_asan/client/gwp_asan.cc b/components/gwp_asan/client/gwp_asan.cc index 85dc815..41e3571 100644 --- a/components/gwp_asan/client/gwp_asan.cc +++ b/components/gwp_asan/client/gwp_asan.cc
@@ -15,6 +15,7 @@ #include "base/macros.h" #include "base/metrics/field_trial_params.h" #include "base/numerics/safe_math.h" +#include "base/optional.h" #include "base/rand_util.h" #include "base/strings/stringprintf.h" #include "build/build_config.h" @@ -29,7 +30,6 @@ namespace internal { namespace { -#if BUILDFLAG(USE_ALLOCATOR_SHIM) constexpr int kDefaultMaxAllocations = 35; constexpr int kDefaultMaxMetadata = 150; @@ -41,46 +41,28 @@ constexpr int kDefaultTotalPages = kDefaultMaxMetadata * 2; #endif -constexpr int kDefaultAllocationSamplingMultiplier = 1000; -constexpr int kDefaultAllocationSamplingRange = 64; -constexpr double kDefaultProcessSamplingProbability = 0.2; -constexpr int kDefaultProcessSamplingBoost = 4; - -const base::Feature kGwpAsan{"GwpAsanMalloc", base::FEATURE_ENABLED_BY_DEFAULT}; - -const base::FeatureParam<int> kMaxAllocationsParam{&kGwpAsan, "MaxAllocations", - kDefaultMaxAllocations}; - -const base::FeatureParam<int> kMaxMetadataParam{&kGwpAsan, "MaxMetadata", - kDefaultMaxMetadata}; - -const base::FeatureParam<int> kTotalPagesParam{&kGwpAsan, "TotalPages", - kDefaultTotalPages}; - // The allocation sampling frequency is calculated using the formula: // multiplier * range**rand // where rand is a random real number in the range [0,1). -const base::FeatureParam<int> kAllocationSamplingMultiplierParam{ - &kGwpAsan, "AllocationSamplingMultiplier", - kDefaultAllocationSamplingMultiplier}; +constexpr int kDefaultAllocationSamplingMultiplier = 1000; +constexpr int kDefaultAllocationSamplingRange = 64; -const base::FeatureParam<int> kAllocationSamplingRangeParam{ - &kGwpAsan, "AllocationSamplingRange", kDefaultAllocationSamplingRange}; - -const base::FeatureParam<double> kProcessSamplingParam{ - &kGwpAsan, "ProcessSamplingProbability", - kDefaultProcessSamplingProbability}; - +constexpr double kDefaultProcessSamplingProbability = 0.2; // The multiplier to increase the ProcessSamplingProbability in scenarios where // we want to perform additional testing (e.g. on canary/dev builds or in the // browser process.) The multiplier increase is cumulative when multiple // conditions apply. -const base::FeatureParam<int> kProcessSamplingBoostParam{ - &kGwpAsan, "ProcessSamplingBoost", kDefaultProcessSamplingBoost}; +constexpr int kDefaultProcessSamplingBoost = 4; + +const base::Feature kGwpAsan{"GwpAsanMalloc", base::FEATURE_ENABLED_BY_DEFAULT}; // Returns whether this process should be sampled to enable GWP-ASan. -bool SampleProcess(bool is_canary_dev, bool is_browser_process) { - double process_sampling_probability = kProcessSamplingParam.Get(); +bool SampleProcess(const base::Feature& feature, + bool is_canary_dev, + bool is_browser_process) { + double process_sampling_probability = + GetFieldTrialParamByFeatureAsDouble(feature, "ProcessSamplingProbability", + kDefaultProcessSamplingProbability); if (process_sampling_probability < 0.0 || process_sampling_probability > 1.0) { DLOG(ERROR) << "GWP-ASan ProcessSamplingProbability is out-of-range: " @@ -88,11 +70,13 @@ return false; } + int process_sampling_boost = GetFieldTrialParamByFeatureAsInt( + feature, "ProcessSamplingBoost", kDefaultProcessSamplingBoost); base::CheckedNumeric<int> multiplier = 1; if (is_canary_dev) - multiplier += kProcessSamplingBoostParam.Get(); + multiplier += process_sampling_boost; if (is_browser_process) - multiplier += kProcessSamplingBoostParam.Get(); + multiplier += process_sampling_boost; if (!multiplier.IsValid() || multiplier.ValueOrDie() < 1) { DLOG(ERROR) << "GWP-ASan ProcessSampling multiplier is out-of-range"; @@ -113,15 +97,18 @@ } // Returns the allocation sampling frequency, or 0 on error. -size_t AllocationSamplingFrequency() { - int multiplier = kAllocationSamplingMultiplierParam.Get(); +size_t AllocationSamplingFrequency(const base::Feature& feature) { + int multiplier = + GetFieldTrialParamByFeatureAsInt(feature, "AllocationSamplingMultiplier", + kDefaultAllocationSamplingMultiplier); if (multiplier < 1) { DLOG(ERROR) << "GWP-ASan AllocationSamplingMultiplier is out-of-range: " << multiplier; return 0; } - int range = kAllocationSamplingRangeParam.Get(); + int range = GetFieldTrialParamByFeatureAsInt( + feature, "AllocationSamplingRange", kDefaultAllocationSamplingRange); if (range < 1) { DLOG(ERROR) << "GWP-ASan AllocationSamplingRange is out-of-range: " << range; @@ -138,9 +125,15 @@ return frequency.ValueOrDie(); } -bool EnableForMalloc(bool is_canary_dev, bool is_browser_process) { - if (!base::FeatureList::IsEnabled(kGwpAsan)) - return false; +} // namespace + +// Exported for testing. +GWP_ASAN_EXPORT base::Optional<AllocatorSettings> GetAllocatorSettings( + const base::Feature& feature, + bool is_canary_dev, + bool is_browser_process) { + if (!base::FeatureList::IsEnabled(feature)) + return base::nullopt; static_assert(AllocatorState::kMaxSlots <= std::numeric_limits<int>::max(), "kMaxSlots out of range"); @@ -150,48 +143,58 @@ "kMaxMetadata out of range"); constexpr int kMaxMetadata = static_cast<int>(AllocatorState::kMaxMetadata); - int total_pages = kTotalPagesParam.Get(); + int total_pages = GetFieldTrialParamByFeatureAsInt(feature, "TotalPages", + kDefaultTotalPages); if (total_pages < 1 || total_pages > kMaxSlots) { DLOG(ERROR) << "GWP-ASan TotalPages is out-of-range: " << total_pages; - return false; + return base::nullopt; } - int max_metadata = kMaxMetadataParam.Get(); + int max_metadata = GetFieldTrialParamByFeatureAsInt(feature, "MaxMetadata", + kDefaultMaxMetadata); if (max_metadata < 1 || max_metadata > std::min(total_pages, kMaxMetadata)) { DLOG(ERROR) << "GWP-ASan MaxMetadata is out-of-range: " << max_metadata << " with TotalPages = " << total_pages; - return false; + return base::nullopt; } - int max_allocations = kMaxAllocationsParam.Get(); + int max_allocations = GetFieldTrialParamByFeatureAsInt( + feature, "MaxAllocations", kDefaultMaxAllocations); if (max_allocations < 1 || max_allocations > max_metadata) { DLOG(ERROR) << "GWP-ASan MaxAllocations is out-of-range: " << max_allocations << " with MaxMetadata = " << max_metadata; - return false; + return base::nullopt; } - size_t alloc_sampling_freq = AllocationSamplingFrequency(); + size_t alloc_sampling_freq = AllocationSamplingFrequency(feature); if (!alloc_sampling_freq) - return false; + return base::nullopt; - if (!SampleProcess(is_canary_dev, is_browser_process)) - return false; + if (!SampleProcess(feature, is_canary_dev, is_browser_process)) + return base::nullopt; - InstallMallocHooks(max_allocations, max_metadata, total_pages, - alloc_sampling_freq); - return true; + return AllocatorSettings{max_allocations, max_metadata, total_pages, + alloc_sampling_freq}; } -#endif // BUILDFLAG(USE_ALLOCATOR_SHIM) -} // namespace } // namespace internal void EnableForMalloc(bool is_canary_dev, bool is_browser_process) { #if BUILDFLAG(USE_ALLOCATOR_SHIM) - static bool init_once = - internal::EnableForMalloc(is_canary_dev, is_browser_process); + static bool init_once = [&]() -> bool { + auto settings = internal::GetAllocatorSettings( + internal::kGwpAsan, is_canary_dev, is_browser_process); + if (!settings) + return false; + + internal::InstallMallocHooks(settings->max_allocated_pages, + settings->num_metadata, settings->total_pages, + settings->sampling_frequency); + return true; + }(); ignore_result(init_once); #else + ignore_result(internal::kGwpAsan); DLOG(WARNING) << "base::allocator shims are unavailable for GWP-ASan."; #endif // BUILDFLAG(USE_ALLOCATOR_SHIM) }
diff --git a/components/gwp_asan/client/gwp_asan.h b/components/gwp_asan/client/gwp_asan.h index 5f3698c..e2a09c2 100644 --- a/components/gwp_asan/client/gwp_asan.h +++ b/components/gwp_asan/client/gwp_asan.h
@@ -5,10 +5,22 @@ #ifndef COMPONENTS_GWP_ASAN_CLIENT_GWP_ASAN_H_ #define COMPONENTS_GWP_ASAN_CLIENT_GWP_ASAN_H_ +#include <stddef.h> // for size_t #include "components/gwp_asan/client/export.h" namespace gwp_asan { +namespace internal { + +struct AllocatorSettings { + size_t max_allocated_pages; + size_t num_metadata; + size_t total_pages; + size_t sampling_frequency; +}; + +} // namespace internal + // Enable GWP-ASan for the current process. This should only be called once per // process. This can not be disabled once it has been enabled. The caller should // indicate whether this build is a canary or dev build or if the current
diff --git a/components/gwp_asan/client/gwp_asan_unittest.cc b/components/gwp_asan/client/gwp_asan_unittest.cc new file mode 100644 index 0000000..180a651 --- /dev/null +++ b/components/gwp_asan/client/gwp_asan_unittest.cc
@@ -0,0 +1,109 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/gwp_asan/client/gwp_asan.h" + +#include <map> +#include <set> +#include <string> +#include <utility> + +#include "base/metrics/field_trial_params.h" +#include "base/optional.h" +#include "base/test/gtest_util.h" +#include "base/test/scoped_feature_list.h" +#include "build/build_config.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace gwp_asan { +namespace internal { + +base::Optional<AllocatorSettings> GetAllocatorSettings( + const base::Feature& feature, + bool is_canary_dev, + bool is_browser_process); + +namespace { + +constexpr size_t kLoopIterations = 100; +const base::Feature kTestFeature1{"GwpAsanTestFeature1", + base::FEATURE_ENABLED_BY_DEFAULT}; +const base::Feature kTestFeature2{"GwpAsanTestFeature2", + base::FEATURE_ENABLED_BY_DEFAULT}; + +// Tries to enable hooking with the given process sampling parameters +// kLoopIterations times and return the number of times hooking was enabled. +size_t processSamplingTest(const char* process_sampling, + const char* process_sampling_boost) { + std::map<std::string, std::string> parameters; + parameters["ProcessSamplingProbability"] = process_sampling; + if (process_sampling_boost) + parameters["ProcessSamplingBoost"] = process_sampling_boost; + + base::test::ScopedFeatureList scoped_feature; + scoped_feature.InitAndEnableFeatureWithParameters(kTestFeature1, parameters); + + size_t enabled = 0; + for (size_t i = 0; i < kLoopIterations; i++) { + if (GetAllocatorSettings(kTestFeature1, process_sampling_boost != nullptr, + false)) + enabled++; + } + + return enabled; +} + +// Enables hooking kLoopIterations times with the given allocation sampling +// parameters and returns the allocation sampling frequencies hooking was +// enabled with. +std::set<size_t> allocationSamplingTest( + const char* allocation_sampling_multiplier, + const char* allocation_sampling_range) { + std::map<std::string, std::string> parameters; + parameters["ProcessSamplingProbability"] = "1.0"; + parameters["AllocationSamplingMultiplier"] = allocation_sampling_multiplier; + parameters["AllocationSamplingRange"] = allocation_sampling_range; + + base::test::ScopedFeatureList scoped_feature; + scoped_feature.InitAndEnableFeatureWithParameters(kTestFeature2, parameters); + + std::set<size_t> frequencies; + for (size_t i = 0; i < kLoopIterations; i++) { + if (auto settings = GetAllocatorSettings(kTestFeature2, false, false)) + frequencies.insert(settings->sampling_frequency); + } + + return frequencies; +} + +} // namespace + +TEST(GwpAsanTest, ProcessSamplingWorks) { + EXPECT_EQ(processSamplingTest("1.0", nullptr), kLoopIterations); + EXPECT_EQ(processSamplingTest("1.0", "99999"), kLoopIterations); + EXPECT_EQ(processSamplingTest("0.01", "99"), kLoopIterations); + + EXPECT_EQ(processSamplingTest("0.0", nullptr), 0U); + EXPECT_EQ(processSamplingTest("0.0", "99999"), 0U); + + size_t num_enabled = processSamplingTest("0.5", nullptr); + EXPECT_GT(num_enabled, 0U); + EXPECT_LT(num_enabled, kLoopIterations); +} + +TEST(GwpAsanTest, AllocationSamplingWorks) { + std::set<size_t> frequencies = allocationSamplingTest("1000", "1"); + EXPECT_THAT(frequencies, testing::ElementsAre(1000)); + + frequencies = allocationSamplingTest("1000", "64"); + EXPECT_GT(frequencies.size(), 1U); + for (const size_t freq : frequencies) { + EXPECT_GE(freq, 1000U); + EXPECT_LE(freq, 64000U); + } +} + +} // namespace internal +} // namespace gwp_asan
diff --git a/components/offline_pages/core/background/BUILD.gn b/components/offline_pages/core/background/BUILD.gn index 96927eb..1232e791 100644 --- a/components/offline_pages/core/background/BUILD.gn +++ b/components/offline_pages/core/background/BUILD.gn
@@ -30,6 +30,7 @@ "mark_attempt_deferred_task.h", "mark_attempt_started_task.cc", "mark_attempt_started_task.h", + "offliner.cc", "offliner.h", "offliner_client.cc", "offliner_client.h",
diff --git a/components/offline_pages/core/background/offliner.cc b/components/offline_pages/core/background/offliner.cc new file mode 100644 index 0000000..b608e24b --- /dev/null +++ b/components/offline_pages/core/background/offliner.cc
@@ -0,0 +1,69 @@ +// Copyright 2019 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include <string> + +#include "components/offline_pages/core/background/offliner.h" + +namespace offline_pages { + +// static +std::string Offliner::RequestStatusToString(RequestStatus request_status) { + switch (request_status) { + case Offliner::RequestStatus::UNKNOWN: + return "UNKNOWN"; + case Offliner::RequestStatus::LOADED: + return "LOADED"; + case Offliner::RequestStatus::SAVED: + return "SAVED"; + case Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED: + return "REQUEST_COORDINATOR_CANCELED"; + case Offliner::RequestStatus::LOADING_CANCELED: + return "LOADING_CANCELED"; + case Offliner::RequestStatus::LOADING_FAILED: + return "LOADING_FAILED"; + case Offliner::RequestStatus::SAVE_FAILED: + return "SAVE_FAILED"; + case Offliner::RequestStatus::FOREGROUND_CANCELED: + return "FOREGROUND_CANCELED"; + case Offliner::RequestStatus::REQUEST_COORDINATOR_TIMED_OUT: + return "REQUEST_COORDINATOR_TIMED_OUT"; + case Offliner::RequestStatus::DEPRECATED_LOADING_NOT_STARTED: + NOTREACHED(); + return "DEPRECATED_LOADING_NOT_STARTED"; + case Offliner::RequestStatus::LOADING_FAILED_NO_RETRY: + return "LOADING_FAILED_NO_RETRY"; + case Offliner::RequestStatus::LOADING_FAILED_NO_NEXT: + return "LOADING_FAILED_NO_NEXT"; + case Offliner::RequestStatus::LOADING_NOT_ACCEPTED: + return "LOADING_NOT_ACCEPTED"; + case Offliner::RequestStatus::QUEUE_UPDATE_FAILED: + return "QUEUE_UPDATE_FAILED"; + case Offliner::RequestStatus::BACKGROUND_SCHEDULER_CANCELED: + return "BACKGROUND_SCHEDULER_CANCELED"; + case Offliner::RequestStatus::SAVED_ON_LAST_RETRY: + return "SAVED_ON_LAST_RETRY"; + case Offliner::RequestStatus::BROWSER_KILLED: + return "BROWSER_KILLED"; + case Offliner::RequestStatus::LOADING_FAILED_DOWNLOAD: + return "LOADING_FAILED_DOWNLOAD"; + case Offliner::RequestStatus::DOWNLOAD_THROTTLED: + return "DOWNLOAD_THROTTLED"; + case Offliner::RequestStatus::LOADING_FAILED_NET_ERROR: + return "LOADING_FAILED_NET_ERROR"; + case Offliner::RequestStatus::LOADING_FAILED_HTTP_ERROR: + return "LOADING_FAILED_HTTP_ERROR"; + case Offliner::RequestStatus::LOADING_DEFERRED: + return "LOADING_DEFERRED"; + case Offliner::RequestStatus::LOADED_PAGE_HAS_CERTIFICATE_ERROR: + return "LOADED_PAGE_HAS_CERTIFICATE_ERROR"; + case Offliner::RequestStatus::LOADED_PAGE_IS_BLOCKED: + return "LOADED_PAGE_IS_BLOCKED"; + case Offliner::RequestStatus::LOADED_PAGE_IS_CHROME_INTERNAL: + return "LOADED_PAGE_IS_CHROME_INTERNAL"; + } + return "UNKNOWN"; +} + +} // namespace offline_pages
diff --git a/components/offline_pages/core/background/offliner.h b/components/offline_pages/core/background/offliner.h index 87e8d1c8..0a80fdb 100644 --- a/components/offline_pages/core/background/offliner.h +++ b/components/offline_pages/core/background/offliner.h
@@ -77,8 +77,14 @@ LOADING_FAILED_HTTP_ERROR = 20, // Loading was deferred because the active tab URL matches. LOADING_DEFERRED = 21, + // The loaded page has a HTTPS certificate error. + LOADED_PAGE_HAS_CERTIFICATE_ERROR = 22, + // The loaded page is blocked by SafeBrowsing. + LOADED_PAGE_IS_BLOCKED = 23, + // The loaded page is an interstitial or an error page. + LOADED_PAGE_IS_CHROME_INTERNAL = 24, - kMaxValue = LOADING_DEFERRED, + kMaxValue = LOADED_PAGE_IS_CHROME_INTERNAL, }; // Reports the load progress of a request. @@ -120,8 +126,15 @@ virtual bool HandleTimeout(int64_t request_id) = 0; // TODO(dougarnett): add policy support methods. + + static std::string RequestStatusToString(RequestStatus request_status); }; +// This operator is for testing only, implemented in ./test_util.cc. +// This is provided here to avoid ODR problems. +std::ostream& operator<<(std::ostream& out, + const Offliner::RequestStatus& value); + } // namespace offline_pages #endif // COMPONENTS_OFFLINE_PAGES_CORE_BACKGROUND_OFFLINER_H_
diff --git a/components/offline_pages/core/background/request_coordinator.cc b/components/offline_pages/core/background/request_coordinator.cc index 23f30be..2985693 100644 --- a/components/offline_pages/core/background/request_coordinator.cc +++ b/components/offline_pages/core/background/request_coordinator.cc
@@ -228,6 +228,9 @@ // Other failure status values. case Offliner::RequestStatus::LOADING_FAILED_NO_RETRY: case Offliner::RequestStatus::LOADING_FAILED_DOWNLOAD: + case Offliner::RequestStatus::LOADED_PAGE_HAS_CERTIFICATE_ERROR: + case Offliner::RequestStatus::LOADED_PAGE_IS_BLOCKED: + case Offliner::RequestStatus::LOADED_PAGE_IS_CHROME_INTERNAL: return RequestNotifier::BackgroundSavePageResult::LOADING_FAILURE; case Offliner::RequestStatus::DOWNLOAD_THROTTLED: return RequestNotifier::BackgroundSavePageResult::DOWNLOAD_THROTTLED; @@ -1017,6 +1020,7 @@ RecordNetworkQualityAtRequestStartForFailedRequest( request.client_id(), network_quality_at_request_start_); } + if (IsCanceledOrInternalFailure(status)) { UpdateRequestForAbortedAttempt(request); } else if (attempt_result) { @@ -1071,6 +1075,9 @@ case Offliner::RequestStatus::LOADING_FAILED_NO_RETRY: case Offliner::RequestStatus::LOADING_FAILED_DOWNLOAD: case Offliner::RequestStatus::DOWNLOAD_THROTTLED: + case Offliner::RequestStatus::LOADED_PAGE_HAS_CERTIFICATE_ERROR: + case Offliner::RequestStatus::LOADED_PAGE_IS_BLOCKED: + case Offliner::RequestStatus::LOADED_PAGE_IS_CHROME_INTERNAL: return true; case Offliner::RequestStatus::FOREGROUND_CANCELED: case Offliner::RequestStatus::LOADING_CANCELED:
diff --git a/components/offline_pages/core/background/request_coordinator_event_logger.cc b/components/offline_pages/core/background/request_coordinator_event_logger.cc index 88554d9..ef2a136 100644 --- a/components/offline_pages/core/background/request_coordinator_event_logger.cc +++ b/components/offline_pages/core/background/request_coordinator_event_logger.cc
@@ -8,58 +8,6 @@ namespace { -static std::string OfflinerRequestStatusToString( - Offliner::RequestStatus request_status) { - switch (request_status) { - case Offliner::RequestStatus::UNKNOWN: - return "UNKNOWN"; - case Offliner::RequestStatus::LOADED: - return "LOADED"; - case Offliner::RequestStatus::SAVED: - return "SAVED"; - case Offliner::RequestStatus::REQUEST_COORDINATOR_CANCELED: - return "REQUEST_COORDINATOR_CANCELED"; - case Offliner::RequestStatus::LOADING_CANCELED: - return "LOADING_CANCELED"; - case Offliner::RequestStatus::LOADING_FAILED: - return "LOADING_FAILED"; - case Offliner::RequestStatus::SAVE_FAILED: - return "SAVE_FAILED"; - case Offliner::RequestStatus::FOREGROUND_CANCELED: - return "FOREGROUND_CANCELED"; - case Offliner::RequestStatus::REQUEST_COORDINATOR_TIMED_OUT: - return "REQUEST_COORDINATOR_TIMED_OUT"; - case Offliner::RequestStatus::DEPRECATED_LOADING_NOT_STARTED: - NOTREACHED(); - return "DEPRECATED_LOADING_NOT_STARTED"; - case Offliner::RequestStatus::LOADING_FAILED_NO_RETRY: - return "LOADING_FAILED_NO_RETRY"; - case Offliner::RequestStatus::LOADING_FAILED_NO_NEXT: - return "LOADING_FAILED_NO_NEXT"; - case Offliner::RequestStatus::LOADING_NOT_ACCEPTED: - return "LOADING_NOT_ACCEPTED"; - case Offliner::RequestStatus::QUEUE_UPDATE_FAILED: - return "QUEUE_UPDATE_FAILED"; - case Offliner::RequestStatus::BACKGROUND_SCHEDULER_CANCELED: - return "BACKGROUND_SCHEDULER_CANCELED"; - case Offliner::RequestStatus::SAVED_ON_LAST_RETRY: - return "SAVED_ON_LAST_RETRY"; - case Offliner::RequestStatus::BROWSER_KILLED: - return "BROWSER_KILLED"; - case Offliner::RequestStatus::LOADING_FAILED_DOWNLOAD: - return "LOADING_FAILED_DOWNLOAD"; - case Offliner::RequestStatus::DOWNLOAD_THROTTLED: - return "DOWNLOAD_THROTTLED"; - case Offliner::RequestStatus::LOADING_FAILED_NET_ERROR: - return "LOADING_FAILED_NET_ERROR"; - case Offliner::RequestStatus::LOADING_FAILED_HTTP_ERROR: - return "LOADING_FAILED_HTTP_ERROR"; - case Offliner::RequestStatus::LOADING_DEFERRED: - return "LOADING_DEFERRED"; - } - return "UNKNOWN"; -} - static std::string BackgroundSavePageResultToString( RequestNotifier::BackgroundSavePageResult result) { switch (result) { @@ -112,7 +60,7 @@ std::string request_id_str = std::to_string(request_id); RecordActivity("Background save attempt for " + name_space + ":" + request_id_str + " - " + - OfflinerRequestStatusToString(new_status)); + Offliner::RequestStatusToString(new_status)); } void RequestCoordinatorEventLogger::RecordDroppedSavePageRequest(
diff --git a/components/offline_pages/core/background/test_util.cc b/components/offline_pages/core/background/test_util.cc index 7f03fc9..0a7e263 100644 --- a/components/offline_pages/core/background/test_util.cc +++ b/components/offline_pages/core/background/test_util.cc
@@ -4,6 +4,7 @@ #include "base/json/json_writer.h" #include "base/values.h" +#include "components/offline_pages/core/background/offliner.h" #include "components/offline_pages/core/background/save_page_request.h" namespace offline_pages { @@ -50,4 +51,9 @@ return out << EnumString(value); } +std::ostream& operator<<(std::ostream& out, + const Offliner::RequestStatus& value) { + return out << Offliner::RequestStatusToString(value); +} + } // namespace offline_pages
diff --git a/components/offline_pages/core/model/offline_page_model_taskified.cc b/components/offline_pages/core/model/offline_page_model_taskified.cc index 51dd135..26c477e 100644 --- a/components/offline_pages/core/model/offline_page_model_taskified.cc +++ b/components/offline_pages/core/model/offline_page_model_taskified.cc
@@ -65,12 +65,6 @@ return SavePageResult::ARCHIVE_CREATION_FAILED; case ArchiverResult::ERROR_CANCELED: return SavePageResult::CANCELLED; - case ArchiverResult::ERROR_SECURITY_CERTIFICATE: - return SavePageResult::SECURITY_CERTIFICATE_ERROR; - case ArchiverResult::ERROR_ERROR_PAGE: - return SavePageResult::ERROR_PAGE; - case ArchiverResult::ERROR_INTERSTITIAL_PAGE: - return SavePageResult::INTERSTITIAL_PAGE; case ArchiverResult::ERROR_SKIPPED: return SavePageResult::SKIPPED; case ArchiverResult::ERROR_DIGEST_CALCULATION_FAILED:
diff --git a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc index 9093ff6..bd22bcc0 100644 --- a/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc +++ b/components/offline_pages/core/model/offline_page_model_taskified_unittest.cc
@@ -1199,40 +1199,6 @@ PumpLoop(); } -// This test is disabled since it's lacking the ability of mocking store failure -// in store_test_utils. https://crbug.com/781023 -// TODO(romax): reenable the test once the above issue is resolved. -TEST_F(OfflinePageModelTaskifiedTest, - DISABLED_ClearCachedPagesTriggeredWhenSaveFailed) { - // After a save failed, only PostClearCachedPagesTask will be triggered. - page_generator()->SetArchiveDirectory(temporary_dir_path()); - page_generator()->SetNamespace(kDefaultNamespace); - page_generator()->SetUrl(kTestUrl); - OfflinePageItem page1 = page_generator()->CreateItemWithTempFile(); - OfflinePageItem page2 = page_generator()->CreateItemWithTempFile(); - InsertPageIntoStore(page1); - InsertPageIntoStore(page2); - - ResetResults(); - - base::MockCallback<SavePageCallback> callback; - EXPECT_CALL(callback, Run(Eq(SavePageResult::ERROR_PAGE), A<int64_t>())); - - std::unique_ptr<OfflinePageTestArchiver> archiver( - BuildArchiver(kTestUrl, ArchiverResult::SUCCESSFULLY_CREATED)); - OfflinePageTestArchiver* archiver_ptr = archiver.get(); - - SavePageWithCallback(kTestUrl, kTestClientId1, kTestUrl2, kEmptyRequestOrigin, - std::move(archiver), callback.Get()); - // The archiver will not be erased before PumpLoop(). - ASSERT_TRUE(archiver_ptr); - EXPECT_TRUE(archiver_ptr->create_archive_called()); - - PumpLoop(); - EXPECT_FALSE(observer_add_page_called()); - EXPECT_FALSE(observer_delete_page_called()); -} - TEST_F(OfflinePageModelTaskifiedTest, ExtraActionTriggeredWhenSaveSuccess) { // After a save successfully saved, both RemovePagesWithSameUrlInSameNamespace // and PostClearCachedPagesTask will be triggered.
diff --git a/components/offline_pages/core/offline_page_archiver.h b/components/offline_pages/core/offline_page_archiver.h index b314fb21..13b2502 100644 --- a/components/offline_pages/core/offline_page_archiver.h +++ b/components/offline_pages/core/offline_page_archiver.h
@@ -69,10 +69,6 @@ ERROR_CANCELED, // Caller canceled the request. ERROR_CONTENT_UNAVAILABLE, // Content to archive is not available. ERROR_ARCHIVE_CREATION_FAILED, // Creation of archive failed. - ERROR_SECURITY_CERTIFICATE, // Page was loaded on secure connection, but - // there was a security error. - ERROR_ERROR_PAGE, // We detected an error page. - ERROR_INTERSTITIAL_PAGE, // We detected an interstitial page. ERROR_SKIPPED, // Page shouldn't be archived like NTP or // file urls. ERROR_DIGEST_CALCULATION_FAILED, // Failed to compute digest.
diff --git a/components/offline_pages/core/offline_page_types.h b/components/offline_pages/core/offline_page_types.h index f82c57cc..72f8d96 100644 --- a/components/offline_pages/core/offline_page_types.h +++ b/components/offline_pages/core/offline_page_types.h
@@ -25,29 +25,27 @@ // A Java counterpart will be generated for this enum. // GENERATED_JAVA_ENUM_PACKAGE: org.chromium.components.offlinepages enum class SavePageResult { - SUCCESS, - CANCELLED, - DEVICE_FULL, - CONTENT_UNAVAILABLE, - ARCHIVE_CREATION_FAILED, - STORE_FAILURE, - ALREADY_EXISTS, + SUCCESS = 0, + CANCELLED = 1, + DEVICE_FULL = 2, + CONTENT_UNAVAILABLE = 3, + ARCHIVE_CREATION_FAILED = 4, + STORE_FAILURE = 5, + ALREADY_EXISTS = 6, // Certain pages, i.e. file URL or NTP, will not be saved because these // are already locally accessible. - SKIPPED, - SECURITY_CERTIFICATE_ERROR, - // Returned when we detect trying to save a chrome error page. - ERROR_PAGE, - // Returned when we detect trying to save a chrome interstitial page. - INTERSTITIAL_PAGE, + SKIPPED = 7, + DEPRECATED_SECURITY_CERTIFICATE_ERROR = 8, + DEPRECATED_ERROR_PAGE = 9, + DEPRECATED_INTERSTITIAL_PAGE = 10, // Failed to compute digest for the archive file. - DIGEST_CALCULATION_FAILED, + DIGEST_CALCULATION_FAILED = 11, // Unable to move the file into a public directory. - FILE_MOVE_FAILED, + FILE_MOVE_FAILED = 12, // Unable to add the file to the system download manager. - ADD_TO_DOWNLOAD_MANAGER_FAILED, + ADD_TO_DOWNLOAD_MANAGER_FAILED = 13, // Unable to get write permission on public directory. - PERMISSION_DENIED, + PERMISSION_DENIED = 14, kMaxValue = PERMISSION_DENIED, };
diff --git a/components/offline_pages/core/prefetch/prefetch_types.h b/components/offline_pages/core/prefetch/prefetch_types.h index 57ec032..1e0545f1 100644 --- a/components/offline_pages/core/prefetch/prefetch_types.h +++ b/components/offline_pages/core/prefetch/prefetch_types.h
@@ -55,7 +55,7 @@ // Request failed with error indicating that the client is forbidden. The // caller will prevent network requests for the period of 1 day. kShouldSuspendForbidden = 4, - // The request was blocked by a URL blacklist configured by the domain + // The request failed because the service URL was blocked by the domain // administrator. kShouldSuspendBlockedByAdministrator = 5, // The request was answered with a 403 Forbidden response including a message
diff --git a/components/omnibox/browser/contextual_suggestions_service.cc b/components/omnibox/browser/contextual_suggestions_service.cc index 590ea99..1ba9b118 100644 --- a/components/omnibox/browser/contextual_suggestions_service.cc +++ b/components/omnibox/browser/contextual_suggestions_service.cc
@@ -32,8 +32,19 @@ namespace { // Server address for the experimental suggestions service. +// +// For now, we wish to disable on-focus suggestions, but do so in a way that +// can be overridden by an experiment config file change. +// +// To disable on-focus suggestions, we set the address to a URL that will not +// reply. It returns a 404. (This URL is at the same host and similar to the +// URL that will reply.) +// +// We'd be able to enable on-focus suggestions again by overriding this +// default address in an experiment config. const char kDefaultExperimentalServerAddress[] = - "https://cuscochromeextension-pa.googleapis.com/v1/omniboxsuggestions"; + "https://cuscochromeextension-pa.googleapis.com/v_turned_down_returns_404/" + "omniboxsuggestions"; void AddVariationHeaders(network::ResourceRequest* request) { // Add Chrome experiment state to the request headers.
diff --git a/components/omnibox/browser/contextual_suggestions_service_unittest.cc b/components/omnibox/browser/contextual_suggestions_service_unittest.cc index d78c6e87..24c15aa 100644 --- a/components/omnibox/browser/contextual_suggestions_service_unittest.cc +++ b/components/omnibox/browser/contextual_suggestions_service_unittest.cc
@@ -10,7 +10,9 @@ #include "base/bind.h" #include "base/memory/scoped_refptr.h" #include "base/test/bind_test_util.h" +#include "base/test/scoped_feature_list.h" #include "base/test/test_mock_time_task_runner.h" +#include "components/omnibox/common/omnibox_features.h" #include "components/search_engines/template_url_service.h" #include "net/base/load_flags.h" #include "services/network/public/cpp/resource_request.h" @@ -45,6 +47,10 @@ }; TEST_F(ContextualSuggestionsServiceTest, EnsureAttachCookies) { + base::test::ScopedFeatureList scoped_feature_list; + scoped_feature_list.InitAndDisableFeature( + omnibox::kZeroSuggestRedirectToChrome); + network::ResourceRequest resource_request; test_url_loader_factory_.SetInterceptor( base::BindLambdaForTesting([&](const network::ResourceRequest& request) {
diff --git a/components/omnibox/browser/zero_suggest_provider_unittest.cc b/components/omnibox/browser/zero_suggest_provider_unittest.cc index 25c097c..6ce45839 100644 --- a/components/omnibox/browser/zero_suggest_provider_unittest.cc +++ b/components/omnibox/browser/zero_suggest_provider_unittest.cc
@@ -502,7 +502,12 @@ // experiments off, IsPersonalizedUrlDataCollectionActive true), and the // redirect to chrome mode on. base::test::ScopedFeatureList features; - features.InitAndEnableFeature(omnibox::kZeroSuggestRedirectToChrome); + std::map<std::string, std::string> params; + params[std::string( + OmniboxFieldTrial::kZeroSuggestRedirectToChromeServerAddressParam)] = + "https://cuscochromeextension-pa.googleapis.com/v1/omniboxsuggestions"; + features.InitAndEnableFeatureWithParameters( + omnibox::kZeroSuggestRedirectToChrome, params); CreateContextualSuggestFieldTrial(); EXPECT_CALL(*client_, IsAuthenticated())
diff --git a/components/omnibox/common/omnibox_features.cc b/components/omnibox/common/omnibox_features.cc index d6cec0b..53318476 100644 --- a/components/omnibox/common/omnibox_features.cc +++ b/components/omnibox/common/omnibox_features.cc
@@ -173,8 +173,18 @@ }; // Feature used for the Zero Suggest Redirect to Chrome Field Trial. +// +// This feature is *enabled* in order to *disable* all forms of suggestions +// based on the URL on-focus (whether from "redirect to Chrome" or the +// default suggest server). The actual disabling of redirect to Chrome +// suggestions happens in contextual_suggestions_service.cc. See comments +// by kDefaultExperimentalServerAddress. +// +// If this feature were not enabled, Chrome would use the default suggest +// server for suggestions based on the current URL on focus. There is no +// code in Chrome to disable that, so that why we took this route. const base::Feature kZeroSuggestRedirectToChrome{ - "ZeroSuggestRedirectToChrome", base::FEATURE_DISABLED_BY_DEFAULT}; + "ZeroSuggestRedirectToChrome", base::FEATURE_ENABLED_BY_DEFAULT}; // Feature used to display the title of the current URL match. const base::Feature kDisplayTitleForCurrentUrl{
diff --git a/components/security_state/core/security_state.cc b/components/security_state/core/security_state.cc index 4890135..b402dc74 100644 --- a/components/security_state/core/security_state.cc +++ b/components/security_state/core/security_state.cc
@@ -88,20 +88,13 @@ return NONE; } - const GURL url = visible_security_state.url; - - const bool is_cryptographic_with_certificate = - (url.SchemeIsCryptographic() && visible_security_state.certificate); - - const bool is_major_cert_error = - net::IsCertStatusError(visible_security_state.cert_status) && - !net::IsCertStatusMinorError(visible_security_state.cert_status); - // Set the security level to DANGEROUS for major certificate errors. - if (is_cryptographic_with_certificate && is_major_cert_error) { + if (HasMajorCertificateError(visible_security_state)) { return DANGEROUS; } + const GURL& url = visible_security_state.url; + // data: URLs don't define a secure context, and are a vector for spoofing. // Likewise, ftp: URLs are always non-secure, and are uncommon enough that // we can treat them as such without significant user impact. @@ -115,6 +108,9 @@ // pseudo URLs (blob:, filesystem:). filesystem: is a standard scheme so does // not need to be explicitly listed here. // TODO(meacer): Remove special case for blob (crbug.com/684751). + const bool is_cryptographic_with_certificate = + visible_security_state.url.SchemeIsCryptographic() && + visible_security_state.certificate; if (!is_cryptographic_with_certificate) { if (!visible_security_state.is_error_page && !is_origin_secure_callback.Run(url) && @@ -174,6 +170,22 @@ return SECURE; } +bool HasMajorCertificateError( + const VisibleSecurityState& visible_security_state) { + if (!visible_security_state.connection_info_initialized) + return false; + + const bool is_cryptographic_with_certificate = + visible_security_state.url.SchemeIsCryptographic() && + visible_security_state.certificate; + + const bool is_major_cert_error = + net::IsCertStatusError(visible_security_state.cert_status) && + !net::IsCertStatusMinorError(visible_security_state.cert_status); + + return is_cryptographic_with_certificate && is_major_cert_error; +} + VisibleSecurityState::VisibleSecurityState() : malicious_content_status(MALICIOUS_CONTENT_STATUS_NONE), connection_info_initialized(false),
diff --git a/components/security_state/core/security_state.h b/components/security_state/core/security_state.h index a4cf2a4..fd69904 100644 --- a/components/security_state/core/security_state.h +++ b/components/security_state/core/security_state.h
@@ -7,6 +7,7 @@ #include <stdint.h> #include <memory> +#include <string> #include "base/callback.h" #include "base/feature_list.h" @@ -160,6 +161,11 @@ bool used_policy_installed_certificate, IsOriginSecureCallback is_origin_secure_callback); +// Returns true if the current page was loaded using a cryptographic protocol +// and its certificate has any major errors. +bool HasMajorCertificateError( + const VisibleSecurityState& visible_security_state); + // Returns true for a valid |url| with a cryptographic scheme, e.g., HTTPS, WSS. bool IsSchemeCryptographic(const GURL& url);
diff --git a/components/security_state/core/security_state_unittest.cc b/components/security_state/core/security_state_unittest.cc index fffe7dc1..db75e16 100644 --- a/components/security_state/core/security_state_unittest.cc +++ b/components/security_state/core/security_state_unittest.cc
@@ -31,6 +31,8 @@ const char kLocalhostUrl[] = "http://localhost"; const char kFileOrigin[] = "file://example_file"; const char kWssUrl[] = "wss://foo.test/"; +const char kFtpUrl[] = "ftp://example.test/"; +const char kDataUrl[] = "data:text/html,<html>test</html>"; // This list doesn't include data: URL, as data: URLs will be explicitly marked // as not secure. @@ -126,6 +128,10 @@ base::BindRepeating(&IsOriginSecure)); } + bool HasMajorCertificateError() const { + return security_state::HasMajorCertificateError(*GetVisibleSecurityState()); + } + private: GURL url_; scoped_refptr<net::X509Certificate> cert_; @@ -221,14 +227,14 @@ // Tests that pseudo URLs always cause an HTTP_SHOW_WARNING to be shown. TEST(SecurityStateTest, AlwaysWarnOnDataUrls) { TestSecurityStateHelper helper; - helper.SetUrl(GURL("data:text/html,<html>test</html>")); + helper.SetUrl(GURL(kDataUrl)); EXPECT_EQ(HTTP_SHOW_WARNING, helper.GetSecurityLevel()); } // Tests that FTP URLs always cause an HTTP_SHOW_WARNING to be shown. TEST(SecurityStateTest, AlwaysWarnOnFtpUrls) { TestSecurityStateHelper helper; - helper.SetUrl(GURL("ftp://example.test/")); + helper.SetUrl(GURL(kFtpUrl)); EXPECT_EQ(HTTP_SHOW_WARNING, helper.GetSecurityLevel()); } @@ -422,4 +428,61 @@ EXPECT_EQ(DANGEROUS, helper.GetSecurityLevel()); } +// Tests that non-cryptographic schemes are handled as having no certificate +// errors. +TEST(SecurityStateTest, NonCryptoHasNoCertificateErrors) { + TestSecurityStateHelper helper; + helper.set_cert_status(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT | + net::CERT_STATUS_REVOKED); + + helper.SetUrl(GURL(kHttpUrl)); + EXPECT_FALSE(helper.HasMajorCertificateError()); + + helper.SetUrl(GURL(kFtpUrl)); + EXPECT_FALSE(helper.HasMajorCertificateError()); + + helper.SetUrl(GURL(kDataUrl)); + EXPECT_FALSE(helper.HasMajorCertificateError()); +} + +// Tests that cryptographic schemes without certificate errors are acceptable. +TEST(SecurityStateTest, CryptoWithNoCertificateErrors) { + TestSecurityStateHelper helper; + EXPECT_FALSE(helper.HasMajorCertificateError()); + + helper.set_cert_status(0); + EXPECT_FALSE(helper.HasMajorCertificateError()); + + helper.SetCertificate(nullptr); + EXPECT_FALSE(helper.HasMajorCertificateError()); +} + +// Tests that minor certificate errors are properly ignored. +TEST(SecurityStateTest, MinorCertificateErrors) { + TestSecurityStateHelper helper; + helper.set_cert_status(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT | + net::CERT_STATUS_UNABLE_TO_CHECK_REVOCATION); + EXPECT_FALSE(helper.HasMajorCertificateError()); + + helper.set_cert_status(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT | + net::CERT_STATUS_NO_REVOCATION_MECHANISM); + EXPECT_FALSE(helper.HasMajorCertificateError()); +} + +// Tests that major certificate errors are detected. +TEST(SecurityStateTest, MajorCertificateErrors) { + TestSecurityStateHelper helper; + helper.set_cert_status(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT | + net::CERT_STATUS_REVOKED); + EXPECT_TRUE(helper.HasMajorCertificateError()); + + helper.set_cert_status(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT | + net::CERT_STATUS_WEAK_SIGNATURE_ALGORITHM); + EXPECT_TRUE(helper.HasMajorCertificateError()); + + helper.set_cert_status(net::CERT_STATUS_SHA1_SIGNATURE_PRESENT | + net::CERT_STATUS_PINNED_KEY_MISSING); + EXPECT_TRUE(helper.HasMajorCertificateError()); +} + } // namespace security_state
diff --git a/content/browser/appcache/appcache_host.cc b/content/browser/appcache/appcache_host.cc index d6ed8eb6..5e7c21a2 100644 --- a/content/browser/appcache/appcache_host.cc +++ b/content/browser/appcache/appcache_host.cc
@@ -19,7 +19,9 @@ #include "content/browser/appcache/appcache_subresource_url_factory.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/common/appcache_interfaces.h" +#include "content/public/browser/child_process_security_policy.h" #include "content/public/common/content_features.h" +#include "content/public/common/url_constants.h" #include "net/url_request/url_request.h" #include "services/network/public/cpp/features.h" #include "services/network/public/mojom/url_loader_factory.mojom.h" @@ -137,6 +139,20 @@ return; } + DCHECK_NE(process_id_, ChildProcessHost::kInvalidUniqueID); + auto* security_policy = ChildProcessSecurityPolicy::GetInstance(); + if (document_url != kAboutSrcDocURL && + !security_policy->CanAccessDataForOrigin(process_id_, document_url)) { + mojo::ReportBadMessage("ACH_SELECT_CACHE_DOCUMENT_URL_ACCESS_NOT_ALLOWED"); + return; + } + + if (!manifest_url.is_empty() && + !security_policy->CanAccessDataForOrigin(process_id_, manifest_url)) { + mojo::ReportBadMessage("ACH_SELECT_CACHE_MANIFEST_URL_ACCESS_NOT_ALLOWED"); + return; + } + DCHECK(pending_start_update_callback_.is_null() && pending_swap_cache_callback_.is_null() && pending_get_status_callback_.is_null() && !is_selection_pending()); @@ -229,6 +245,14 @@ return; } + auto* security_policy = ChildProcessSecurityPolicy::GetInstance(); + if (document_url != kAboutSrcDocURL && + !security_policy->CanAccessDataForOrigin(process_id_, document_url)) { + mojo::ReportBadMessage( + "ACH_MARK_AS_FOREIGN_ENTRY_DOCUMENT_URL_ACCESS_NOT_ALLOWED"); + return; + } + // The document url is not the resource url in the fallback case. storage()->MarkEntryAsForeign( main_resource_was_namespace_entry_ ? namespace_entry_url_ : document_url,
diff --git a/content/browser/appcache/appcache_host_unittest.cc b/content/browser/appcache/appcache_host_unittest.cc index fc13cb4..4b54ca87 100644 --- a/content/browser/appcache/appcache_host_unittest.cc +++ b/content/browser/appcache/appcache_host_unittest.cc
@@ -19,6 +19,8 @@ #include "content/browser/appcache/appcache_request_handler.h" #include "content/browser/appcache/mock_appcache_policy.h" #include "content/browser/appcache/mock_appcache_service.h" +#include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/isolation_context.h" #include "content/public/test/test_browser_context.h" #include "content/public/test/test_renderer_host.h" #include "content/test/test_web_contents.h" @@ -621,4 +623,64 @@ } } +TEST_F(AppCacheHostTest, SelectCacheURLsForWrongSite) { + // Lock process to |kProcessLockURL| so we can only accept URLs from + // that site. + const GURL kProcessLockURL("http://foo.com"); + ChildProcessSecurityPolicyImpl::GetInstance()->LockToOrigin( + IsolationContext(&browser_context_), kProcessIdForTest, kProcessLockURL); + + AppCacheHost host(kHostIdForTest, kProcessIdForTest, kRenderFrameIdForTest, + nullptr, &service_); + host.set_frontend_for_testing(&mock_frontend_); + blink::mojom::AppCacheHostPtr host_ptr; + host.BindRequest(mojo::MakeRequest(&host_ptr)); + + // Verify that a document URL from the wrong site triggers a bad message. + { + const GURL kDocumentURL("http://whatever/"); + mojo::test::BadMessageObserver bad_message_observer; + host_ptr->SelectCache(kDocumentURL, blink::mojom::kAppCacheNoCacheId, + GURL()); + + EXPECT_EQ("ACH_SELECT_CACHE_DOCUMENT_URL_ACCESS_NOT_ALLOWED", + bad_message_observer.WaitForBadMessage()); + } + + // Verify that a document URL from the wrong site triggers a bad message. + { + const GURL kDocumentURL = kProcessLockURL; + const GURL kManifestURL("http://whatever/"); + mojo::test::BadMessageObserver bad_message_observer; + host_ptr->SelectCache(kDocumentURL, blink::mojom::kAppCacheNoCacheId, + kManifestURL); + + EXPECT_EQ("ACH_SELECT_CACHE_MANIFEST_URL_ACCESS_NOT_ALLOWED", + bad_message_observer.WaitForBadMessage()); + } +} + +TEST_F(AppCacheHostTest, ForeignEntryForWrongSite) { + // Lock process to |kProcessLockURL| so we can only accept URLs from + // that site. + const GURL kProcessLockURL("http://foo.com"); + ChildProcessSecurityPolicyImpl::GetInstance()->LockToOrigin( + IsolationContext(&browser_context_), kProcessIdForTest, kProcessLockURL); + + AppCacheHost host(kHostIdForTest, kProcessIdForTest, kRenderFrameIdForTest, + nullptr, &service_); + host.set_frontend_for_testing(&mock_frontend_); + blink::mojom::AppCacheHostPtr host_ptr; + host.BindRequest(mojo::MakeRequest(&host_ptr)); + + // Verify that a document URL from the wrong site triggers a bad message. + { + const GURL kDocumentURL("http://origin/document"); + mojo::test::BadMessageObserver bad_message_observer; + host_ptr->MarkAsForeignEntry(kDocumentURL, + blink::mojom::kAppCacheNoCacheId); + EXPECT_EQ("ACH_MARK_AS_FOREIGN_ENTRY_DOCUMENT_URL_ACCESS_NOT_ALLOWED", + bad_message_observer.WaitForBadMessage()); + } +} } // namespace content
diff --git a/content/browser/appcache/appcache_storage_impl_unittest.cc b/content/browser/appcache/appcache_storage_impl_unittest.cc index c58f47ef..e98fd1c 100644 --- a/content/browser/appcache/appcache_storage_impl_unittest.cc +++ b/content/browser/appcache/appcache_storage_impl_unittest.cc
@@ -36,8 +36,10 @@ #include "content/browser/appcache/appcache_request_handler.h" #include "content/browser/appcache/appcache_service_impl.h" #include "content/browser/appcache/appcache_url_loader_request.h" +#include "content/browser/child_process_security_policy_impl.h" #include "content/public/browser/browser_task_traits.h" #include "content/public/common/content_features.h" +#include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" #include "net/base/net_errors.h" #include "net/base/request_priority.h" @@ -73,6 +75,8 @@ return GURL("http://mockhost/" + path); } +std::unique_ptr<TestBrowserContext> browser_context; +const int kProcessId = 1; std::unique_ptr<base::test::ScopedTaskEnvironment> scoped_task_environment; scoped_refptr<base::SingleThreadTaskRunner> io_runner; std::unique_ptr<base::Thread> background_thread; @@ -276,6 +280,10 @@ scoped_task_environment = std::make_unique<TestBrowserThreadBundle>( TestBrowserThreadBundle::REAL_IO_THREAD); + browser_context = std::make_unique<TestBrowserContext>(); + ChildProcessSecurityPolicyImpl::GetInstance()->Add(kProcessId, + browser_context.get()); + io_runner = base::CreateSingleThreadTaskRunnerWithTraits({BrowserThread::IO}); @@ -289,6 +297,8 @@ static void TearDownTestCase() { io_runner.reset(); background_thread.reset(); + ChildProcessSecurityPolicyImpl::GetInstance()->Remove(kProcessId); + browser_context.reset(); scoped_task_environment.reset(); } @@ -1694,10 +1704,9 @@ } void Continue_Reinitialize(ReinitTestCase test_case) { - const int kMockProcessId = 1; const int kMockRenderFrameId = MSG_ROUTING_NONE; backend_ = - std::make_unique<AppCacheBackendImpl>(service_.get(), kMockProcessId); + std::make_unique<AppCacheBackendImpl>(service_.get(), kProcessId); if (test_case == CORRUPT_SQL_ON_INSTALL) { // Break the db file @@ -2039,4 +2048,4 @@ // That's all folks! -} // namespace content \ No newline at end of file +} // namespace content
diff --git a/content/browser/appcache/appcache_update_job_unittest.cc b/content/browser/appcache/appcache_update_job_unittest.cc index d6820b6..b37d46d 100644 --- a/content/browser/appcache/appcache_update_job_unittest.cc +++ b/content/browser/appcache/appcache_update_job_unittest.cc
@@ -28,8 +28,10 @@ #include "content/browser/appcache/appcache_response.h" #include "content/browser/appcache/appcache_update_url_loader_request.h" #include "content/browser/appcache/mock_appcache_service.h" +#include "content/browser/child_process_security_policy_impl.h" #include "content/browser/url_loader_factory_getter.h" #include "content/public/browser/browser_task_traits.h" +#include "content/public/test/test_browser_context.h" #include "content/public/test/test_browser_thread_bundle.h" #include "mojo/public/cpp/bindings/binding.h" #include "mojo/public/cpp/system/data_pipe.h" @@ -701,7 +703,8 @@ expect_non_null_update_time_(false), tested_manifest_(NONE), tested_manifest_path_override_(nullptr), - thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD) { + thread_bundle_(content::TestBrowserThreadBundle::REAL_IO_THREAD), + process_id_(123) { base::PostTaskWithTraits( FROM_HERE, {BrowserThread::IO}, base::BindOnce(&IOThread::Init, base::Unretained(io_thread_.get()))); @@ -723,6 +726,14 @@ base::BindOnce(&IOThread::CleanUp, base::Unretained(io_thread_.get()))); } + void SetUp() override { + ChildProcessSecurityPolicyImpl::GetInstance()->Add(process_id_, + &browser_context_); + } + + void TearDown() override { + ChildProcessSecurityPolicyImpl::GetInstance()->Remove(process_id_); + } // Use a separate IO thread to run a test. Thread will be destroyed // when it goes out of scope. template <class Method> @@ -3502,11 +3513,9 @@ AppCacheHost* MakeHost(int host_id, blink::mojom::AppCacheFrontend* frontend) { - constexpr int kProcessIdForTests = 123; constexpr int kRenderFrameIdForTests = 456; - hosts_.push_back(std::make_unique<AppCacheHost>(host_id, kProcessIdForTests, - kRenderFrameIdForTests, - nullptr, service_.get())); + hosts_.push_back(std::make_unique<AppCacheHost>( + host_id, process_id_, kRenderFrameIdForTests, nullptr, service_.get())); hosts_.back()->set_frontend_for_testing(frontend); return hosts_.back().get(); } @@ -3855,6 +3864,8 @@ MockURLLoaderFactory mock_url_loader_factory_; scoped_refptr<URLLoaderFactoryGetter> loader_factory_getter_; content::TestBrowserThreadBundle thread_bundle_; + content::TestBrowserContext browser_context_; + const int process_id_; }; TEST_F(AppCacheUpdateJobTest, AlreadyChecking) {
diff --git a/content/browser/browser_context.cc b/content/browser/browser_context.cc index 41bdc53..758d955 100644 --- a/content/browser/browser_context.cc +++ b/content/browser/browser_context.cc
@@ -60,8 +60,6 @@ #include "media/mojo/services/video_decode_perf_history.h" #include "mojo/public/cpp/bindings/remote.h" #include "net/cookies/cookie_store.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/channel_id_store.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_getter.h" #include "services/content/public/mojom/constants.mojom.h" @@ -599,7 +597,6 @@ if (BrowserThread::IsThreadInitialized(BrowserThread::IO)) { scoped_refptr<net::URLRequestContextGetter> context_getter; - // Channel ID isn't supported with network service. if (!base::FeatureList::IsEnabled(network::features::kNetworkService)) context_getter = storage_partition->GetURLRequestContext(); base::PostTaskWithTraits(
diff --git a/content/browser/net/quota_policy_cookie_store.cc b/content/browser/net/quota_policy_cookie_store.cc index ef27c43c..85a9fec 100644 --- a/content/browser/net/quota_policy_cookie_store.cc +++ b/content/browser/net/quota_policy_cookie_store.cc
@@ -44,8 +44,7 @@ CookieStoreConfig::CookieStoreConfig() : restore_old_session_cookies(false), persist_session_cookies(false), - crypto_delegate(nullptr), - channel_id_service(nullptr) { + crypto_delegate(nullptr) { // Default to an in-memory cookie store. } @@ -58,8 +57,7 @@ restore_old_session_cookies(restore_old_session_cookies), persist_session_cookies(persist_session_cookies), storage_policy(storage_policy), - crypto_delegate(nullptr), - channel_id_service(nullptr) { + crypto_delegate(nullptr) { CHECK(!path.empty() || (!restore_old_session_cookies && !persist_session_cookies)); }
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.cc b/content/browser/renderer_host/render_widget_host_view_aura.cc index 5b9f5aa..ab248a1 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.cc +++ b/content/browser/renderer_host/render_widget_host_view_aura.cc
@@ -1525,7 +1525,7 @@ } #if defined(OS_WIN) || defined(OS_CHROMEOS) -void RenderWidgetHostViewAura::SetCompositionFromExistingText( +bool RenderWidgetHostViewAura::SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { RenderFrameHostImpl* frame = GetFocusedFrame(); @@ -1534,6 +1534,7 @@ range.start(), range.end(), ui_ime_text_spans); has_composition_text_ = true; } + return true; } #endif
diff --git a/content/browser/renderer_host/render_widget_host_view_aura.h b/content/browser/renderer_host/render_widget_host_view_aura.h index 682ce86..9313e04 100644 --- a/content/browser/renderer_host/render_widget_host_view_aura.h +++ b/content/browser/renderer_host/render_widget_host_view_aura.h
@@ -234,7 +234,7 @@ bool ShouldDoLearning() override; #if defined(OS_WIN) || defined(OS_CHROMEOS) - void SetCompositionFromExistingText( + bool SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override; #endif
diff --git a/content/browser/tracing/background_tracing_active_scenario.cc b/content/browser/tracing/background_tracing_active_scenario.cc index f239682..e3e123da 100644 --- a/content/browser/tracing/background_tracing_active_scenario.cc +++ b/content/browser/tracing/background_tracing_active_scenario.cc
@@ -16,8 +16,14 @@ #include "content/browser/tracing/background_tracing_manager_impl.h" #include "content/browser/tracing/background_tracing_rule.h" #include "content/browser/tracing/tracing_controller_impl.h" +#include "content/public/common/service_manager_connection.h" +#include "mojo/public/cpp/bindings/binding.h" +#include "mojo/public/cpp/system/data_pipe_drainer.h" +#include "services/service_manager/public/cpp/connector.h" +#include "services/tracing/public/cpp/perfetto/perfetto_config.h" #include "services/tracing/public/cpp/perfetto/trace_event_data_source.h" #include "services/tracing/public/cpp/tracing_features.h" +#include "services/tracing/public/mojom/constants.mojom.h" using base::trace_event::TraceConfig; using Metrics = content::BackgroundTracingManagerImpl::Metrics; @@ -50,6 +56,216 @@ BackgroundTracingManager::StartedFinalizingCallback callback_; }; +class BackgroundTracingActiveScenario::TracingSession { + public: + virtual ~TracingSession() = default; + virtual void BeginFinalizing(const base::RepeatingClosure& on_success, + const base::RepeatingClosure& on_failure) = 0; + virtual void AbortScenario( + const base::RepeatingClosure& on_abort_callback) = 0; +}; + +class PerfettoTracingSession + : public BackgroundTracingActiveScenario::TracingSession, + public tracing::mojom::TracingSessionClient, + public mojo::DataPipeDrainer::Client { + public: + PerfettoTracingSession(BackgroundTracingActiveScenario* parent_scenario, + const TraceConfig& chrome_config, + BackgroundTracingConfigImpl::CategoryPreset preset) + : parent_scenario_(parent_scenario), + category_preset_(preset), + raw_data_(std::make_unique<std::string>()) { +#if !defined(OS_ANDROID) + // TODO(crbug.com/941318): Re-enable startup tracing for Android once all + // Perfetto-related deadlocks are resolved. + if (!TracingControllerImpl::GetInstance()->IsTracing() && + tracing::TracingUsesPerfettoBackend()) { + tracing::TraceEventDataSource::GetInstance()->SetupStartupTracing( + /*privacy_filtering_enabled=*/true); + } +#endif + + ServiceManagerConnection::GetForProcess()->GetConnector()->BindInterface( + tracing::mojom::kServiceName, &consumer_host_); + + perfetto::TraceConfig perfetto_config = tracing::GetDefaultPerfettoConfig( + chrome_config, /*privacy_filtering_enabled=*/true); + + tracing::mojom::TracingSessionClientPtr tracing_session_client; + binding_.Bind(mojo::MakeRequest(&tracing_session_client)); + binding_.set_connection_error_handler( + base::BindOnce(&PerfettoTracingSession::OnTracingSessionEnded, + base::Unretained(this))); + + consumer_host_->EnableTracing( + mojo::MakeRequest(&tracing_session_host_), + std::move(tracing_session_client), std::move(perfetto_config), + tracing::mojom::TracingClientPriority::kBackground); + tracing_session_host_.set_connection_error_handler( + base::BindOnce(&PerfettoTracingSession::OnTracingSessionEnded, + base::Unretained(this))); + } + + // BackgroundTracingActiveScenario::TracingSession implementation. + void BeginFinalizing(const base::RepeatingClosure& on_success, + const base::RepeatingClosure& on_failure) override { + bool is_allowed_finalization = + BackgroundTracingManagerImpl::GetInstance()->IsAllowedFinalization(); + + if (!is_allowed_finalization) { + on_failure.Run(); + return; + } + + tracing_session_host_->DisableTracing(); + on_success.Run(); + } + + void AbortScenario(const base::RepeatingClosure& on_abort_callback) override { + on_abort_callback.Run(); + } + + // mojo::DataPipeDrainer::Client implementation: + void OnDataAvailable(const void* data, size_t num_bytes) override { + raw_data_->append(reinterpret_cast<const char*>(data), num_bytes); + } + + void OnDataComplete() override { + has_finished_receiving_data_ = true; + MaybeFinishedReceivingTrace(); + } + + // tracing::mojom::TracingSession implementation: + void OnTracingEnabled() override { + BackgroundTracingManagerImpl::GetInstance()->OnStartTracingDone( + category_preset_); + } + + void OnTracingDisabled() override { + mojo::ScopedDataPipeProducerHandle producer_handle; + mojo::ScopedDataPipeConsumerHandle consumer_handle; + + MojoResult result = + mojo::CreateDataPipe(nullptr, &producer_handle, &consumer_handle); + DCHECK_EQ(MOJO_RESULT_OK, result); + + drainer_ = std::make_unique<mojo::DataPipeDrainer>( + this, std::move(consumer_handle)); + tracing_session_host_->ReadBuffers( + std::move(producer_handle), + base::BindOnce(&PerfettoTracingSession::OnReadBuffersComplete, + base::Unretained(this))); + } + + void OnReadBuffersComplete() { + has_finished_read_buffers_ = true; + MaybeFinishedReceivingTrace(); + } + + void MaybeFinishedReceivingTrace() { + if (has_finished_read_buffers_ && has_finished_receiving_data_) { + DCHECK(raw_data_); + parent_scenario_->OnProtoDataComplete(std::move(raw_data_)); + } + } + + private: + void OnTracingSessionEnded() { parent_scenario_->AbortScenario(); } + + BackgroundTracingActiveScenario* const parent_scenario_; + mojo::Binding<tracing::mojom::TracingSessionClient> binding_{this}; + tracing::mojom::TracingSessionHostPtr tracing_session_host_; + std::unique_ptr<mojo::DataPipeDrainer> drainer_; + tracing::mojom::ConsumerHostPtr consumer_host_; + BackgroundTracingConfigImpl::CategoryPreset category_preset_; + std::unique_ptr<std::string> raw_data_; + bool has_finished_read_buffers_ = false; + bool has_finished_receiving_data_ = false; +}; + +class LegacyTracingSession + : public BackgroundTracingActiveScenario::TracingSession { + public: + LegacyTracingSession(BackgroundTracingActiveScenario* parent_scenario, + const TraceConfig& chrome_config, + BackgroundTracingConfigImpl::CategoryPreset preset) + : parent_scenario_(parent_scenario) { +#if !defined(OS_ANDROID) + // TODO(crbug.com/941318): Re-enable startup tracing for Android once all + // Perfetto-related deadlocks are resolved. + if (!TracingControllerImpl::GetInstance()->IsTracing() && + tracing::TracingUsesPerfettoBackend()) { + tracing::TraceEventDataSource::GetInstance()->SetupStartupTracing( + /*privacy_filtering_enabled=*/false); + } +#endif + + bool result = TracingControllerImpl::GetInstance()->StartTracing( + chrome_config, + base::BindOnce( + &BackgroundTracingManagerImpl::OnStartTracingDone, + base::Unretained(BackgroundTracingManagerImpl::GetInstance()), + preset)); + // We check IsEnabled() before creating the LegacyTracingSession, + // so any failures to start tracing at this point would be due to invalid + // configs which we treat as a failure scenario. + DCHECK(result); + } + + ~LegacyTracingSession() override { + DCHECK(!TracingControllerImpl::GetInstance()->IsTracing()); + } + + // BackgroundTracingActiveScenario::TracingSession implementation. + void BeginFinalizing(const base::RepeatingClosure& on_success, + const base::RepeatingClosure& on_failure) override { + if (!BackgroundTracingManagerImpl::GetInstance()->IsAllowedFinalization()) { + TracingControllerImpl::GetInstance()->StopTracing( + TracingControllerImpl::CreateCallbackEndpoint(base::BindRepeating( + [](const base::RepeatingClosure& on_failure, + std::unique_ptr<const base::DictionaryValue>, + base::RefCountedString*) { on_failure.Run(); }, + std::move(on_failure)))); + return; + } + + auto trace_data_endpoint = + TracingControllerImpl::CreateCompressedStringEndpoint( + TracingControllerImpl::CreateCallbackEndpoint(base::BindRepeating( + [](base::WeakPtr<BackgroundTracingActiveScenario> weak_this, + const base::RepeatingClosure& on_success, + std::unique_ptr<const base::DictionaryValue> metadata, + base::RefCountedString* file_contents) { + on_success.Run(); + if (weak_this) { + weak_this->OnJSONDataComplete(std::move(metadata), + file_contents); + } + }, + parent_scenario_->GetWeakPtr(), std::move(on_success))), + true /* compress_with_background_priority */); + + TracingControllerImpl::GetInstance()->StopTracing(trace_data_endpoint); + } + + void AbortScenario(const base::RepeatingClosure& on_abort_callback) override { + if (TracingControllerImpl::GetInstance()->IsTracing()) { + TracingControllerImpl::GetInstance()->StopTracing( + TracingControllerImpl::CreateCallbackEndpoint(base::BindRepeating( + [](const base::RepeatingClosure& on_abort_callback, + std::unique_ptr<const base::DictionaryValue>, + base::RefCountedString*) { on_abort_callback.Run(); }, + std::move(on_abort_callback)))); + } else { + on_abort_callback.Run(); + } + } + + private: + BackgroundTracingActiveScenario* const parent_scenario_; +}; + BackgroundTracingActiveScenario::BackgroundTracingActiveScenario( std::unique_ptr<BackgroundTracingConfigImpl> config, bool requires_anonymized_data, @@ -104,6 +320,7 @@ } if (scenario_state_ == State::kAborted) { + tracing_session_.reset(); std::move(on_aborted_callback_).Run(); } } @@ -118,6 +335,11 @@ rule_triggered_callback_for_testing_ = callback; } +base::WeakPtr<BackgroundTracingActiveScenario> +BackgroundTracingActiveScenario::GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + void BackgroundTracingActiveScenario::StartTracingIfConfigNeedsIt() { DCHECK(config_); if (config_->tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE) { @@ -132,50 +354,45 @@ void BackgroundTracingActiveScenario::StartTracing( BackgroundTracingConfigImpl::CategoryPreset preset, base::trace_event::TraceRecordMode record_mode) { - TraceConfig config = BackgroundTracingConfigImpl::GetConfigForCategoryPreset( - preset, record_mode); + TraceConfig chrome_config = + BackgroundTracingConfigImpl::GetConfigForCategoryPreset(preset, + record_mode); if (requires_anonymized_data_) - config.EnableArgumentFilter(); + chrome_config.EnableArgumentFilter(); #if defined(OS_ANDROID) // Set low trace buffer size on Android in order to upload small trace files. if (config_->tracing_mode() == BackgroundTracingConfigImpl::PREEMPTIVE) { - config.SetTraceBufferSizeInEvents(20000); - config.SetTraceBufferSizeInKb(500); - } -#else - // TODO(crbug.com/941318): Re-enable startup tracing for Android once all - // Perfetto-related deadlocks are resolved. - if (!TracingControllerImpl::GetInstance()->IsTracing() && - tracing::TracingUsesPerfettoBackend()) { - // TODO(oysteine): This should pass in |requires_anonymized_data_| instead - // of false only when using consumer API with proto output. But, for JSON - // output we still need this to be false since filtering happens in the JSON - // exporter. - tracing::TraceEventDataSource::GetInstance()->SetupStartupTracing( - /*privacy_filtering_enabled=*/false); + chrome_config.SetTraceBufferSizeInEvents(20000); + chrome_config.SetTraceBufferSizeInKb(500); } #endif - if (!TracingControllerImpl::GetInstance()->StartTracing( - config, - base::BindOnce( - &BackgroundTracingManagerImpl::OnStartTracingDone, - base::Unretained(BackgroundTracingManagerImpl::GetInstance()), - preset))) { + // If the tracing controller is tracing, i.e. DevTools or about://tracing, + // we don't start background tracing to not interfere with the user activity. + if (TracingControllerImpl::GetInstance()->IsTracing()) { AbortScenario(); return; } - SetState(State::kTracing); - // Activate the categories immediately. StartTracing eventually does this - // itself, but asynchronously via PostTask, and in the meantime events will be + // itself, but asynchronously via Mojo, and in the meantime events will be // dropped. This ensures that we start recording events for those categories // immediately. uint8_t modes = base::trace_event::TraceLog::RECORDING_MODE; - if (!config.event_filters().empty()) + if (!chrome_config.event_filters().empty()) modes |= base::trace_event::TraceLog::FILTERING_MODE; - base::trace_event::TraceLog::GetInstance()->SetEnabled(config, modes); + base::trace_event::TraceLog::GetInstance()->SetEnabled(chrome_config, modes); + + DCHECK(!tracing_session_); + if (base::FeatureList::IsEnabled(features::kBackgroundTracingProtoOutput)) { + tracing_session_ = + std::make_unique<PerfettoTracingSession>(this, chrome_config, preset); + } else { + tracing_session_ = + std::make_unique<LegacyTracingSession>(this, chrome_config, preset); + } + + SetState(State::kTracing); BackgroundTracingManagerImpl::RecordMetric(Metrics::RECORDING_ENABLED); } @@ -185,56 +402,54 @@ triggered_named_event_handle_ = -1; tracing_timer_.reset(); - scoped_refptr<TracingControllerImpl::TraceDataEndpoint> trace_data_endpoint; - bool is_allowed_finalization = - BackgroundTracingManagerImpl::GetInstance()->IsAllowedFinalization(); - base::RepeatingClosure started_finalizing_closure; - if (!callback.is_null()) { - started_finalizing_closure = - base::BindRepeating(callback, is_allowed_finalization); - } + auto on_begin_finalization_success = base::BindRepeating( + [](base::WeakPtr<BackgroundTracingActiveScenario> weak_this, + BackgroundTracingManager::StartedFinalizingCallback callback) { + if (!weak_this) { + return; + } - if (is_allowed_finalization) { - trace_data_endpoint = TracingControllerImpl::CreateCompressedStringEndpoint( - TracingControllerImpl::CreateCallbackEndpoint(base::BindRepeating( - &BackgroundTracingActiveScenario::OnTracingStopped, - weak_ptr_factory_.GetWeakPtr(), - std::move(started_finalizing_closure))), - true /* compress_with_background_priority */); - BackgroundTracingManagerImpl::RecordMetric(Metrics::FINALIZATION_ALLOWED); - } else { - trace_data_endpoint = - TracingControllerImpl::CreateCallbackEndpoint(base::BindRepeating( - [](base::RepeatingClosure closure, - base::WeakPtr<BackgroundTracingActiveScenario> active_scenario, - std::unique_ptr<const base::DictionaryValue> metadata, - base::RefCountedString* file_contents) { - if (active_scenario) { - active_scenario->SetState(State::kAborted); - } + weak_this->SetState(State::kFinalizing); + BackgroundTracingManagerImpl::RecordMetric( + Metrics::FINALIZATION_ALLOWED); + DCHECK(!weak_this->started_finalizing_closure_); + if (!callback.is_null()) { + weak_this->started_finalizing_closure_ = + base::BindOnce(callback, /*is_allowed_finalization=*/true); + } + }, + weak_ptr_factory_.GetWeakPtr(), callback); - if (closure) { - std::move(closure).Run(); - } - }, - std::move(started_finalizing_closure), - weak_ptr_factory_.GetWeakPtr())); - BackgroundTracingManagerImpl::RecordMetric( - Metrics::FINALIZATION_DISALLOWED); - } + auto on_begin_finalization_failure = base::BindRepeating( + [](base::WeakPtr<BackgroundTracingActiveScenario> weak_this, + BackgroundTracingManager::StartedFinalizingCallback callback) { + if (!weak_this) { + return; + } - TracingControllerImpl::GetInstance()->StopTracing(trace_data_endpoint); + BackgroundTracingManagerImpl::RecordMetric( + Metrics::FINALIZATION_DISALLOWED); + weak_this->SetState(State::kAborted); + + if (!callback.is_null()) { + callback.Run(false); + } + }, + weak_ptr_factory_.GetWeakPtr(), callback); + + tracing_session_->BeginFinalizing(std::move(on_begin_finalization_success), + std::move(on_begin_finalization_failure)); } -void BackgroundTracingActiveScenario::OnTracingStopped( - base::RepeatingClosure started_finalizing_closure, +void BackgroundTracingActiveScenario::OnJSONDataComplete( std::unique_ptr<const base::DictionaryValue> metadata, base::RefCountedString* file_contents) { - SetState(State::kFinalizing); BackgroundTracingManagerImpl::RecordMetric(Metrics::FINALIZATION_STARTED); UMA_HISTOGRAM_MEMORY_KB("Tracing.Background.FinalizingTraceSizeInKB", file_contents->size() / 1024); + // Send the finalized and compressed tracing data to the destination + // callback. if (!receive_callback_.is_null()) { receive_callback_.Run( file_contents, std::move(metadata), @@ -242,8 +457,22 @@ weak_ptr_factory_.GetWeakPtr())); } - if (!started_finalizing_closure.is_null()) { - std::move(started_finalizing_closure).Run(); + if (started_finalizing_closure_) { + std::move(started_finalizing_closure_).Run(); + } +} + +void BackgroundTracingActiveScenario::OnProtoDataComplete( + std::unique_ptr<std::string> proto_trace) { + BackgroundTracingManagerImpl::RecordMetric(Metrics::FINALIZATION_STARTED); + UMA_HISTOGRAM_MEMORY_KB("Tracing.Background.FinalizingTraceSizeInKB", + proto_trace->size() / 1024); + + BackgroundTracingManager::GetInstance()->SetTraceToUploadForTesting( + std::move(proto_trace)); + + if (started_finalizing_closure_) { + std::move(started_finalizing_closure_).Run(); } } @@ -254,6 +483,7 @@ BackgroundTracingManagerImpl::RecordMetric(Metrics::UPLOAD_FAILED); } + tracing_session_.reset(); SetState(State::kIdle); // Now that a trace has completed, we may need to enable recording again. @@ -261,24 +491,18 @@ } void BackgroundTracingActiveScenario::AbortScenario() { - if ((state() != State::kTracing)) { + if (tracing_session_) { + tracing_session_->AbortScenario(base::BindRepeating( + [](base::WeakPtr<BackgroundTracingActiveScenario> weak_this) { + if (weak_this) { + weak_this->SetState(State::kAborted); + } + }, + weak_ptr_factory_.GetWeakPtr())); + } else { // Setting the kAborted state will cause |this| to be destroyed. SetState(State::kAborted); - return; } - - auto trace_data_endpoint = - TracingControllerImpl::CreateCallbackEndpoint(base::BindRepeating( - [](base::WeakPtr<BackgroundTracingActiveScenario> active_scenario, - std::unique_ptr<const base::DictionaryValue>, - base::RefCountedString*) { - if (active_scenario) { - active_scenario->SetState(State::kAborted); - } - }, - weak_ptr_factory_.GetWeakPtr())); - - TracingControllerImpl::GetInstance()->StopTracing(trace_data_endpoint); } void BackgroundTracingActiveScenario::TriggerNamedEvent( @@ -371,6 +595,10 @@ BackgroundTracingManagerImpl::RecordMetric(Metrics::PREEMPTIVE_TRIGGERED); } + // Make a copy of the callback in case BeginFinalizing() ends up aborting the + // scenario and |this| gets deleted. + auto rule_triggered_callback_for_testing = + rule_triggered_callback_for_testing_; if (trace_delay < 0) { BeginFinalizing(std::move(callback)); } else { @@ -378,8 +606,8 @@ tracing_timer_->StartTimer(trace_delay); } - if (!rule_triggered_callback_for_testing_.is_null()) { - rule_triggered_callback_for_testing_.Run(); + if (!rule_triggered_callback_for_testing.is_null()) { + rule_triggered_callback_for_testing.Run(); } }
diff --git a/content/browser/tracing/background_tracing_active_scenario.h b/content/browser/tracing/background_tracing_active_scenario.h index e64cb0f..67bbc25 100644 --- a/content/browser/tracing/background_tracing_active_scenario.h +++ b/content/browser/tracing/background_tracing_active_scenario.h
@@ -11,7 +11,9 @@ #include "base/macros.h" #include "base/memory/weak_ptr.h" #include "content/browser/tracing/background_tracing_config_impl.h" +#include "content/browser/tracing/tracing_controller_impl.h" #include "content/public/browser/background_tracing_manager.h" +#include "services/tracing/public/mojom/perfetto_service.mojom.h" namespace base { class RefCountedString; @@ -24,13 +26,14 @@ class BackgroundTracingActiveScenario { public: enum class State { kIdle, kTracing, kFinalizing, kUploading, kAborted }; + class TracingSession; BackgroundTracingActiveScenario( std::unique_ptr<BackgroundTracingConfigImpl> config, bool requires_anonymized_data, BackgroundTracingManager::ReceiveCallback receive_callback, base::OnceClosure on_aborted_callback); - ~BackgroundTracingActiveScenario(); + virtual ~BackgroundTracingActiveScenario(); void StartTracingIfConfigNeedsIt(); void AbortScenario(); @@ -39,6 +42,7 @@ void GenerateMetadataDict(base::DictionaryValue* metadata_dict); State state() const { return scenario_state_; } bool requires_anonymized_data() const { return requires_anonymized_data_; } + base::WeakPtr<BackgroundTracingActiveScenario> GetWeakPtr(); void TriggerNamedEvent( BackgroundTracingManager::TriggerHandle handle, @@ -48,6 +52,16 @@ const BackgroundTracingRule* triggered_rule, BackgroundTracingManager::StartedFinalizingCallback callback); + // Called by LegacyTracingSession when the final trace data is ready. + void OnJSONDataComplete(std::unique_ptr<const base::DictionaryValue> metadata, + base::RefCountedString*); + // Called by the PerfettoTracingSession when the proto trace is ready. + void OnProtoDataComplete(std::unique_ptr<std::string> proto_trace); + + // Called when the finalized trace data has been uploaded/transferred away + // from the background tracing system. + void OnFinalizeComplete(bool success); + // For testing CONTENT_EXPORT void FireTimerForTesting(); CONTENT_EXPORT void SetRuleTriggeredCallbackForTesting( @@ -56,20 +70,15 @@ private: void StartTracing(BackgroundTracingConfigImpl::CategoryPreset, base::trace_event::TraceRecordMode); - void BeginFinalizing( BackgroundTracingManager::StartedFinalizingCallback callback); - void OnTracingStopped(base::RepeatingClosure started_finalizing_closure, - std::unique_ptr<const base::DictionaryValue> metadata, - base::RefCountedString*); - - void OnFinalizeComplete(bool success); BackgroundTracingRule* GetRuleAbleToTriggerTracing( const std::string& trigger_name); void SetState(State new_state); + std::unique_ptr<TracingSession> tracing_session_; std::unique_ptr<BackgroundTracingConfigImpl> config_; bool requires_anonymized_data_; State scenario_state_; @@ -78,6 +87,7 @@ BackgroundTracingManager::ReceiveCallback receive_callback_; BackgroundTracingManager::TriggerHandle triggered_named_event_handle_; base::OnceClosure on_aborted_callback_; + base::OnceClosure started_finalizing_closure_; class TracingTimer; std::unique_ptr<TracingTimer> tracing_timer_;
diff --git a/content/browser/tracing/background_tracing_manager_browsertest.cc b/content/browser/tracing/background_tracing_manager_browsertest.cc index 6e4b2c5..7f2ab1b 100644 --- a/content/browser/tracing/background_tracing_manager_browsertest.cc +++ b/content/browser/tracing/background_tracing_manager_browsertest.cc
@@ -16,8 +16,11 @@ #include "base/run_loop.h" #include "base/strings/pattern.h" #include "base/task/post_task.h" +#include "base/test/scoped_feature_list.h" +#include "base/test/test_timeouts.h" #include "base/trace_event/trace_event.h" #include "build/build_config.h" +#include "content/browser/devtools/protocol/devtools_protocol_test_support.h" #include "content/browser/tracing/background_startup_tracing_observer.h" #include "content/browser/tracing/background_tracing_active_scenario.h" #include "content/browser/tracing/background_tracing_manager_impl.h" @@ -28,6 +31,7 @@ #include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test_utils.h" #include "content/public/test/test_utils.h" +#include "services/tracing/public/cpp/tracing_features.h" #include "third_party/zlib/zlib.h" using base::trace_event::TraceLog; @@ -48,6 +52,21 @@ bool enabled_ = false; }; +// Wait until |condition| returns true. +void WaitForCondition(base::RepeatingCallback<bool()> condition, + const std::string& description) { + const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(30); + const base::TimeTicks start_time = base::TimeTicks::Now(); + while (!condition.Run() && (base::TimeTicks::Now() - start_time < kTimeout)) { + base::RunLoop run_loop; + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( + FROM_HERE, run_loop.QuitClosure(), TestTimeouts::tiny_timeout()); + run_loop.Run(); + } + ASSERT_TRUE(condition.Run()) + << "Timeout waiting for condition: " << description; +} + // An helper class that observes tracing states transition and allows // synchronisation with tests. The class adds itself as a tracelog // enable state observer and provides methods to wait for a given state. @@ -357,7 +376,7 @@ handle, trigger_helper.receive_closure(true)); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -388,7 +407,7 @@ handle, trigger_helper.receive_closure(false)); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -422,7 +441,7 @@ trigger_helper.WaitForTriggerReceived(); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -469,7 +488,7 @@ trigger_helper.WaitForTriggerReceived(); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -500,7 +519,7 @@ handle, trigger_helper.receive_closure(true)); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -539,7 +558,7 @@ handle, trigger_helper.receive_closure(true)); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -598,7 +617,7 @@ handle2, trigger_helper.receive_closure(false)); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -662,7 +681,7 @@ trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -705,7 +724,7 @@ handle, trigger_helper.receive_closure(false)); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_FALSE(trace_receiver_helper.trace_received()); @@ -737,7 +756,7 @@ handle, trigger_helper.receive_closure(false)); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_FALSE(trace_receiver_helper.trace_received()); @@ -783,7 +802,7 @@ handle, trigger_helper.receive_closure(false)); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_FALSE(trace_receiver_helper.trace_received()); @@ -829,7 +848,7 @@ trigger_helper.WaitForTriggerReceived(); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_FALSE(trace_receiver_helper.trace_received()); @@ -872,7 +891,7 @@ LOCAL_HISTOGRAM_COUNTS("fake", 2); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -917,7 +936,7 @@ trace_receiver_helper.WaitForTraceReceived(); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -961,7 +980,7 @@ LOCAL_HISTOGRAM_COUNTS("fake", 0); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_FALSE(trace_receiver_helper.trace_received()); @@ -1006,7 +1025,7 @@ LOCAL_HISTOGRAM_COUNTS("fake", 0); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_FALSE(trace_receiver_helper.trace_received()); @@ -1060,7 +1079,7 @@ ->FireTimerForTesting(); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -1090,7 +1109,7 @@ handle, trigger_helper.receive_closure(true)); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -1135,7 +1154,7 @@ EXPECT_TRUE(trace_receiver_helper.trace_received(1)); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); } @@ -1200,7 +1219,7 @@ handle1, trigger_helper.receive_closure(true)); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -1235,7 +1254,7 @@ handle, trigger_helper.receive_closure(false)); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -1295,7 +1314,7 @@ ->FireTimerForTesting(); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); @@ -1343,7 +1362,7 @@ EXPECT_TRUE(preferences->GetBackgroundStartupTracingEnabled()); // Abort the scenario. - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_FALSE(trace_receiver_helper.trace_received()); @@ -1402,11 +1421,85 @@ ->FireTimerForTesting(); trace_receiver_helper.WaitForTraceReceived(); - BackgroundTracingManager::GetInstance()->AbortScenario(); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); background_tracing_helper.WaitForScenarioAborted(); EXPECT_TRUE(trace_receiver_helper.trace_received()); EXPECT_FALSE(preferences->GetBackgroundStartupTracingEnabled()); } +namespace { + +class ProtoBackgroundTracingTest : public DevToolsProtocolTest { + public: + ProtoBackgroundTracingTest() { + scoped_feature_list_.InitWithFeatures( + /*enabled_features=*/{features::kTracingPerfettoBackend, + features::kBackgroundTracingProtoOutput}, + /*disabled_features=*/{}); + } + + private: + base::test::ScopedFeatureList scoped_feature_list_; +}; + +} // namespace + +IN_PROC_BROWSER_TEST_F(ProtoBackgroundTracingTest, + DevtoolsInterruptsBackgroundTracing) { + TestBackgroundTracingHelper background_tracing_helper; + TestTraceReceiverHelper trace_receiver_helper; + + std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig(); + + EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario( + std::move(config), trace_receiver_helper.get_receive_callback(), + BackgroundTracingManager::NO_DATA_FILTERING)); + + background_tracing_helper.WaitForTracingEnabled(); + + NavigateToURLBlockUntilNavigationsComplete(shell(), GURL("about:blank"), 1); + Attach(); + + base::Value* start_tracing_result = + SendCommand("Tracing.start", nullptr, true); + ASSERT_TRUE(start_tracing_result); + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); + background_tracing_helper.WaitForScenarioAborted(); +} + +IN_PROC_BROWSER_TEST_F(ProtoBackgroundTracingTest, ProtoTraceReceived) { + TestBackgroundTracingHelper background_tracing_helper; + + std::unique_ptr<BackgroundTracingConfig> config = CreatePreemptiveConfig(); + + BackgroundTracingManager::TriggerHandle handle = + BackgroundTracingManager::GetInstance()->RegisterTriggerType( + "preemptive_test"); + + EXPECT_TRUE(BackgroundTracingManager::GetInstance()->SetActiveScenario( + std::move(config), base::DoNothing(), + BackgroundTracingManager::NO_DATA_FILTERING)); + + background_tracing_helper.WaitForTracingEnabled(); + + TestTriggerHelper trigger_helper; + BackgroundTracingManager::GetInstance()->TriggerNamedEvent( + handle, trigger_helper.receive_closure(true)); + + WaitForCondition( + base::BindRepeating([]() { + return BackgroundTracingManager::GetInstance()->HasTraceToUpload(); + }), + "trace received"); + + std::string trace_data = + BackgroundTracingManager::GetInstance()->GetLatestTraceToUpload(); + + BackgroundTracingManager::GetInstance()->AbortScenarioForTesting(); + background_tracing_helper.WaitForScenarioAborted(); + + EXPECT_TRUE(!trace_data.empty()); +} + } // namespace content
diff --git a/content/browser/tracing/background_tracing_manager_impl.cc b/content/browser/tracing/background_tracing_manager_impl.cc index 8bb32561..055bafc 100644 --- a/content/browser/tracing/background_tracing_manager_impl.cc +++ b/content/browser/tracing/background_tracing_manager_impl.cc
@@ -162,18 +162,19 @@ } bool BackgroundTracingManagerImpl::HasTraceToUpload() { - // TODO(oysteine): This should return the collected trace once we have the new - // coordinator API to collect protos. https://crbug.com/925142. - // Note: This can be called on any thread and needs to be thread safe. - return !trace_to_upload_for_testing_.empty(); + DCHECK_CURRENTLY_ON(BrowserThread::UI); + return !trace_to_upload_.empty(); } std::string BackgroundTracingManagerImpl::GetLatestTraceToUpload() { - // TODO(oysteine): This should return the collected trace once we have the new - // coordinator API to collect protos. https://crbug.com/925142. - // Note: This can be called on any thread and needs to be thread safe. + DCHECK_CURRENTLY_ON(BrowserThread::UI); std::string ret; - ret.swap(trace_to_upload_for_testing_); + ret.swap(trace_to_upload_); + + if (active_scenario_) { + active_scenario_->OnFinalizeComplete(true); + } + return ret; } @@ -241,8 +242,18 @@ } void BackgroundTracingManagerImpl::SetTraceToUploadForTesting( - base::StringPiece data) { - trace_to_upload_for_testing_ = data.data(); + std::unique_ptr<std::string> trace_data) { + SetTraceToUpload(std::move(trace_data)); +} + +void BackgroundTracingManagerImpl::SetTraceToUpload( + std::unique_ptr<std::string> trace_data) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (trace_data) { + trace_to_upload_.swap(*trace_data); + } else { + trace_to_upload_.clear(); + } } void BackgroundTracingManagerImpl::ValidateStartupScenario() { @@ -315,7 +326,6 @@ return static_cast<TriggerHandle>(trigger_handle_ids_); } - bool BackgroundTracingManagerImpl::IsTriggerHandleValid( BackgroundTracingManager::TriggerHandle handle) const { return trigger_handles_.find(handle) != trigger_handles_.end(); @@ -368,6 +378,10 @@ return metadata_dict; } +void BackgroundTracingManagerImpl::AbortScenarioForTesting() { + AbortScenario(); +} + void BackgroundTracingManagerImpl::AbortScenario() { if (active_scenario_) { active_scenario_->AbortScenario();
diff --git a/content/browser/tracing/background_tracing_manager_impl.h b/content/browser/tracing/background_tracing_manager_impl.h index 1c50eb5..b021c54 100644 --- a/content/browser/tracing/background_tracing_manager_impl.h +++ b/content/browser/tracing/background_tracing_manager_impl.h
@@ -78,7 +78,7 @@ bool SetActiveScenario(std::unique_ptr<BackgroundTracingConfig>, ReceiveCallback, DataFiltering data_filtering) override; - CONTENT_EXPORT void AbortScenario() override; + void AbortScenario(); bool HasActiveScenario() override; // Named triggers @@ -92,6 +92,7 @@ StartedFinalizingCallback callback); bool HasTraceToUpload() override; std::string GetLatestTraceToUpload() override; + void SetTraceToUpload(std::unique_ptr<std::string> trace_data); // Add/remove EnabledStateObserver. CONTENT_EXPORT void AddEnabledStateObserver(EnabledStateObserver* observer); @@ -116,9 +117,9 @@ CONTENT_EXPORT void InvalidateTriggerHandlesForTesting(); CONTENT_EXPORT bool IsTracingForTesting(); void WhenIdle(IdleCallback idle_callback) override; - + CONTENT_EXPORT void AbortScenarioForTesting() override; CONTENT_EXPORT void SetTraceToUploadForTesting( - base::StringPiece data) override; + std::unique_ptr<std::string> trace_data) override; private: friend class base::NoDestructor<BackgroundTracingManagerImpl>; @@ -147,8 +148,9 @@ IdleCallback idle_callback_; base::RepeatingClosure tracing_enabled_callback_for_testing_; + // This field contains serialized trace log proto. - std::string trace_to_upload_for_testing_; + std::string trace_to_upload_; DISALLOW_COPY_AND_ASSIGN(BackgroundTracingManagerImpl); };
diff --git a/content/common/content_constants_internal.cc b/content/common/content_constants_internal.cc index f933ffa..be2463a 100644 --- a/content/common/content_constants_internal.cc +++ b/content/common/content_constants_internal.cc
@@ -37,7 +37,4 @@ const char kMachBootstrapName[] = "rohitfork"; #endif -const char kCorsExemptPurposeHeaderName[] = "Purpose"; -const char kCorsExemptRequestedWithHeaderName[] = "X-Requested-With"; - } // namespace content
diff --git a/content/common/content_constants_internal.h b/content/common/content_constants_internal.h index abdc9ba2..9c0767b 100644 --- a/content/common/content_constants_internal.h +++ b/content/common/content_constants_internal.h
@@ -45,12 +45,6 @@ CONTENT_EXPORT extern const char kMachBootstrapName[]; #endif -// Defines a HTTP header name that is set internally, and some code places -// in content need to know the name to manage the header stored in -// network::ResourceRequest::cors_exempt_headers. -extern const char kCorsExemptPurposeHeaderName[]; -extern const char kCorsExemptRequestedWithHeaderName[]; - } // namespace content #endif // CONTENT_COMMON_CONTENT_CONSTANTS_INTERNAL_H_
diff --git a/content/public/browser/background_tracing_manager.h b/content/public/browser/background_tracing_manager.h index d3178a3c..c6d4700 100644 --- a/content/public/browser/background_tracing_manager.h +++ b/content/public/browser/background_tracing_manager.h
@@ -102,8 +102,9 @@ virtual std::string GetLatestTraceToUpload() = 0; // For tests - virtual void AbortScenario() = 0; - virtual void SetTraceToUploadForTesting(base::StringPiece data) = 0; + virtual void AbortScenarioForTesting() = 0; + virtual void SetTraceToUploadForTesting( + std::unique_ptr<std::string> trace_data) = 0; protected: virtual ~BackgroundTracingManager() {}
diff --git a/content/public/browser/cookie_store_factory.h b/content/public/browser/cookie_store_factory.h index c459156..300160e2 100644 --- a/content/public/browser/cookie_store_factory.h +++ b/content/public/browser/cookie_store_factory.h
@@ -18,7 +18,6 @@ } namespace net { -class ChannelIDService; class CookieCryptoDelegate; class CookieStore; class NetLog; @@ -61,11 +60,6 @@ // config. net::CookieCryptoDelegate* crypto_delegate; - // Provides the cookie store with a pointer to the corresponding - // ChannelIDService that should be used with that cookie store. The - // ChannelIDService must outlive any cookie store created with this config. - net::ChannelIDService* channel_id_service; - // Callbacks for data load events will be performed on |client_task_runner|. // If nullptr, uses the task runner for BrowserThread::IO. //
diff --git a/content/public/browser/cors_exempt_headers.cc b/content/public/browser/cors_exempt_headers.cc index 616f3a4..6faee52 100644 --- a/content/public/browser/cors_exempt_headers.cc +++ b/content/public/browser/cors_exempt_headers.cc
@@ -4,7 +4,7 @@ #include "content/public/browser/cors_exempt_headers.h" -#include "content/common/content_constants_internal.h" +#include "content/public/common/content_constants.h" namespace content {
diff --git a/content/public/common/content_constants.cc b/content/public/common/content_constants.cc index f2cd0b0..c2523f8 100644 --- a/content/public/common/content_constants.cc +++ b/content/public/common/content_constants.cc
@@ -42,4 +42,7 @@ // same resource (see bugs 46104 and 31014). const int kDefaultDetachableCancelDelayMs = 30000; +const char kCorsExemptPurposeHeaderName[] = "Purpose"; +const char kCorsExemptRequestedWithHeaderName[] = "X-Requested-With"; + } // namespace content
diff --git a/content/public/common/content_constants.h b/content/public/common/content_constants.h index 2595b7d..b3422e67 100644 --- a/content/public/common/content_constants.h +++ b/content/public/common/content_constants.h
@@ -62,6 +62,12 @@ // How long to keep a detachable resource load alive before aborting it. CONTENT_EXPORT extern const int kDefaultDetachableCancelDelayMs; +// Defines a HTTP header name that is set internally, and some code places +// in content need to know the name to manage the header stored in +// network::ResourceRequest::cors_exempt_headers. +CONTENT_EXPORT extern const char kCorsExemptPurposeHeaderName[]; +CONTENT_EXPORT extern const char kCorsExemptRequestedWithHeaderName[]; + } // namespace content #endif // CONTENT_PUBLIC_COMMON_CONTENT_CONSTANTS_H_
diff --git a/content/renderer/loader/web_url_loader_impl.cc b/content/renderer/loader/web_url_loader_impl.cc index 5ea249f..de8d73e 100644 --- a/content/renderer/loader/web_url_loader_impl.cc +++ b/content/renderer/loader/web_url_loader_impl.cc
@@ -28,8 +28,8 @@ #include "base/time/time.h" #include "build/build_config.h" #include "content/child/child_thread_impl.h" -#include "content/common/content_constants_internal.h" #include "content/common/service_worker/service_worker_types.h" +#include "content/public/common/content_constants.h" #include "content/public/common/content_features.h" #include "content/public/common/navigation_policy.h" #include "content/public/common/origin_util.h"
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt index a5e1204..f1e8cd0 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl2_conformance_expectations.txt
@@ -60,7 +60,7 @@ # https://github.com/KhronosGroup/WebGL/pull/2878 land and are rolled # in. # TODO(kbr): this is actually crbug.com/angleproject/3285 . -crbug.com/3285 conformance/glsl/misc/shaders-with-invariance.html [ Failure ] +crbug.com/angleproject/3285 conformance/glsl/misc/shaders-with-invariance.html [ Failure ] # Too slow (take about one hour to run) crbug.com/619403 deqp/functional/gles3/builtinprecision/* [ Skip ] @@ -90,9 +90,9 @@ # Windows only. crbug.com/736926 [ win ] conformance2/textures/svg_image/tex-2d-rgb565-rgb-unsigned_short_5_6_5.html [ RetryOnFailure ] -crbug.com/2291 [ win ] conformance2/rendering/framebuffer-texture-changing-base-level.html [ Failure ] -crbug.com/3033 [ win no-passthrough ] conformance2/textures/misc/generate-mipmap-with-large-base-level.html [ Failure ] -crbug.com/1465 [ win ] conformance2/glsl3/tricky-loop-conditions.html [ Failure ] +crbug.com/angleproject/2291 [ win ] conformance2/rendering/framebuffer-texture-changing-base-level.html [ Failure ] +crbug.com/angleproject/3033 [ win no-passthrough ] conformance2/textures/misc/generate-mipmap-with-large-base-level.html [ Failure ] +crbug.com/angleproject/1465 [ win ] conformance2/glsl3/tricky-loop-conditions.html [ Failure ] crbug.com/951628 [ win no-passthrough ] conformance/rendering/blending.html [ Failure ] # Win / NVidia @@ -166,18 +166,18 @@ crbug.com/878780 [ win amd ] conformance2/textures/webgl_canvas/* [ RetryOnFailure ] # Recent AMD drivers seem to have a regression with 3D textures. -crbug.com/2424 [ d3d11 win amd ] conformance2/textures/canvas_sub_rectangle/tex-3d-* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] conformance2/textures/image/tex-3d-* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] conformance2/textures/image_data/tex-3d-* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] conformance2/textures/misc/tex-unpack-params.html [ Failure ] -crbug.com/2424 [ d3d11 win amd ] conformance2/textures/video/tex-3d-* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] deqp/functional/gles3/shadertexturefunction/* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] deqp/functional/gles3/texturefiltering/3d_* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/basic_teximage3d_3d_* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/basic_texsubimage3d_* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/teximage3d_pbo_3d* [ Failure ] -crbug.com/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/teximage3d_unpack_params.html [ Failure ] -crbug.com/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/texsubimage3d_unpack_params.html [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] conformance2/textures/canvas_sub_rectangle/tex-3d-* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] conformance2/textures/image/tex-3d-* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] conformance2/textures/image_data/tex-3d-* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] conformance2/textures/misc/tex-unpack-params.html [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] conformance2/textures/video/tex-3d-* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] deqp/functional/gles3/shadertexturefunction/* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] deqp/functional/gles3/texturefiltering/3d_* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/basic_teximage3d_3d_* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/basic_texsubimage3d_* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/teximage3d_pbo_3d* [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/teximage3d_unpack_params.html [ Failure ] +crbug.com/angleproject/2424 [ d3d11 win amd ] deqp/functional/gles3/texturespecification/texsubimage3d_unpack_params.html [ Failure ] # Have seen this time out. Think it may be because it's currently # the first test that runs in the shard, and the browser might not @@ -185,7 +185,7 @@ crbug.com/687374 [ win amd-0x6613 ] deqp/functional/gles3/multisample.html [ RetryOnFailure ] # Failing on AMD RX 550 -crbug.com/3354 [ win amd-0x699f ] deqp/functional/gles3/fborender/shared_colorbuffer_02.html [ Skip ] +crbug.com/angleproject/3354 [ win amd-0x699f ] deqp/functional/gles3/fborender/shared_colorbuffer_02.html [ Skip ] # Win / Intel crbug.com/782317 [ d3d11 win intel ] conformance/rendering/rendering-stencil-large-viewport.html [ Failure ] @@ -232,7 +232,7 @@ crbug.com/795030 [ opengl passthrough ] deqp/functional/gles3/shadercommonfunction.html [ Failure ] crbug.com/794341 [ opengl passthrough ] deqp/functional/gles3/shaderpackingfunction.html [ Failure ] crbug.com/814905 [ opengl passthrough ] conformance2/rendering/attrib-type-match.html [ Failure ] -crbug.com/2994 [ opengl passthrough ] conformance2/textures/misc/copy-texture-image-same-texture.html [ Failure ] +crbug.com/angleproject/2994 [ opengl passthrough ] conformance2/textures/misc/copy-texture-image-same-texture.html [ Failure ] # Passthrough command decoder / OpenGL / Windows crbug.com/835364 [ opengl win passthrough ] deqp/functional/gles3/fbocompleteness.html [ Failure ] @@ -252,14 +252,14 @@ # This case causes no-over-optimization-on-uniform-array fail. crbug.com/884210 [ opengl win passthrough intel ] conformance/ogles/GL/gl_FragCoord/gl_FragCoord_001_to_003.html [ Skip ] crbug.com/854100 [ opengl win passthrough intel ] conformance/glsl/variables/gl-pointcoord.html [ RetryOnFailure ] -crbug.com/2760 [ opengl win passthrough intel ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ] +crbug.com/angleproject/2760 [ opengl win passthrough intel ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ] crbug.com/912579 [ opengl win passthrough intel ] conformance2/rendering/out-of-bounds-index-buffers-after-copying.html [ RetryOnFailure ] crbug.com/602688 [ opengl win passthrough intel ] conformance/glsl/constructors/glsl-construct-mat2.html [ Failure ] crbug.com/602688 [ opengl win passthrough intel ] conformance2/textures/misc/texture-npot.html [ Failure ] crbug.com/602688 [ opengl win passthrough intel ] conformance2/textures/misc/npot-video-sizing.html [ Failure ] crbug.com/602688 [ opengl win passthrough intel ] conformance2/glsl3/vector-dynamic-indexing-swizzled-lvalue.html [ Failure ] crbug.com/602688 [ opengl win passthrough intel ] conformance2/glsl3/vector-dynamic-indexing.html [ Failure ] -crbug.com/2880 [ opengl win passthrough intel ] deqp/functional/gles3/shaderbuiltinvar.html [ Failure ] +crbug.com/angleproject/2880 [ opengl win passthrough intel ] deqp/functional/gles3/shaderbuiltinvar.html [ Failure ] crbug.com/957631 [ opengl win passthrough intel ] conformance2/rendering/element-index-uint.html [ Failure ] # Passthrough command decoder / Linux / OpenGL / NVIDIA @@ -272,9 +272,9 @@ crbug.com/927407 [ opengl linux passthrough nvidia ] conformance/extensions/webgl-compressed-texture-s3tc.html [ RetryOnFailure ] # Passthrough command decoder / Linux / OpenGL / Intel -crbug.com/2760 [ opengl linux passthrough intel ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ] -crbug.com/2760 [ opengl linux passthrough intel ] conformance2/renderbuffers/multisampled-stencil-renderbuffer-initialization.html [ Failure ] -crbug.com/2761 [ opengl linux passthrough intel ] conformance2/textures/misc/tex-mipmap-levels.html [ Failure ] +crbug.com/angleproject/2760 [ opengl linux passthrough intel ] conformance2/renderbuffers/multisampled-depth-renderbuffer-initialization.html [ Failure ] +crbug.com/angleproject/2760 [ opengl linux passthrough intel ] conformance2/renderbuffers/multisampled-stencil-renderbuffer-initialization.html [ Failure ] +crbug.com/angleproject/2761 [ opengl linux passthrough intel ] conformance2/textures/misc/tex-mipmap-levels.html [ Failure ] crbug.com/950787 [ opengl linux passthrough intel ] conformance/extensions/webgl-compressed-texture-s3tc.html [ RetryOnFailure ] # Regressions in 10.12.4. @@ -695,7 +695,7 @@ crbug.com/483282 [ linux amd ] deqp/functional/gles3/uniformbuffers/random.html [ Failure ] crbug.com/658842 [ linux amd ] conformance2/buffers/uniform-buffers.html [ Failure ] crbug.com/658844 [ linux amd ] conformance2/rendering/uniform-block-buffer-size.html [ Failure ] -crbug.com/2103 [ linux amd ] conformance2/uniforms/uniform-blocks-with-arrays.html [ Failure ] +crbug.com/angleproject/2103 [ linux amd ] conformance2/uniforms/uniform-blocks-with-arrays.html [ Failure ] crbug.com/809595 [ no-angle linux amd ] conformance2/uniforms/simple-buffer-change.html [ Failure ] # Linux AMD R7 240
diff --git a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt index ed224f3..9665e88 100644 --- a/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt +++ b/content/test/gpu/gpu_tests/test_expectations/webgl_conformance_expectations.txt
@@ -16,7 +16,7 @@ [ win ] WebglExtension_EXT_color_buffer_float [ Failure ] [ mac ] WebglExtension_EXT_color_buffer_float [ Failure ] [ win vulkan passthrough ] WebglExtension_EXT_float_blend [ Failure ] -crbug.com/2672 [ vulkan passthrough ] WebglExtension_WEBGL_multi_draw_instanced [ Failure ] +crbug.com/angleproject/2672 [ vulkan passthrough ] WebglExtension_WEBGL_multi_draw_instanced [ Failure ] # Skip these, rather than expect them to fail, to speed up test # execution. The browser is restarted even after expected test @@ -73,7 +73,7 @@ # https://github.com/KhronosGroup/WebGL/pull/2878 land and are rolled # in. # TODO(kbr): this is actually crbug.com/angleproject/3285 . -crbug.com/3285 conformance/glsl/misc/shaders-with-invariance.html [ Failure ] +crbug.com/angleproject/3285 conformance/glsl/misc/shaders-with-invariance.html [ Failure ] # Nvidia bugs fixed in latest driver # TODO(http://crbug.com/887241): Upgrade the drivers on the bots. @@ -97,8 +97,8 @@ crbug.com/953120 [ passthrough ] conformance/programs/program-test.html [ Failure ] # Passthrough command decoder / OpenGL -crbug.com/2952 [ opengl passthrough ] conformance/textures/canvas/tex-2d-alpha-alpha-unsigned_byte.html [ Failure ] -crbug.com/2952 [ opengl passthrough ] conformance/textures/canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2952 [ opengl passthrough ] conformance/textures/canvas/tex-2d-alpha-alpha-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2952 [ opengl passthrough ] conformance/textures/canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] # Intel graphics driver issue. Passed on 25.20.100.6471 crbug.com/665521 [ intel opengl passthrough ] conformance/glsl/constructors/glsl-construct-mat2.html [ Failure ] @@ -113,7 +113,7 @@ # TODO(kbr): re-add after global suppression is removed. # crbug.com/1007 [ linux amd opengl passthrough ] conformance/glsl/misc/shaders-with-invariance.html [ Skip ] crbug.com/665521 [ linux amd opengl passthrough ] conformance/glsl/misc/struct-nesting-of-variable-names.html [ Failure ] -crbug.com/1635 [ amd opengl passthrough ] conformance/renderbuffers/renderbuffer-initialization.html [ Failure ] +crbug.com/angleproject/1635 [ amd opengl passthrough ] conformance/renderbuffers/renderbuffer-initialization.html [ Failure ] crbug.com/665521 [ amd opengl passthrough ] conformance/renderbuffers/framebuffer-state-restoration.html [ Failure ] crbug.com/665521 [ amd opengl passthrough ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Failure ] crbug.com/665521 [ amd opengl passthrough ] conformance/textures/misc/texture-attachment-formats.html [ Failure ] @@ -129,7 +129,7 @@ # Win failures # TODO(kbr): re-enable suppression for same test below once fixed. -crbug.com/2103 [ win ] conformance/glsl/bugs/sampler-struct-function-arg.html [ Skip ] +crbug.com/angleproject/2103 [ win ] conformance/glsl/bugs/sampler-struct-function-arg.html [ Skip ] # Note that the following test seems to pass, but it may still be flaky. crbug.com/525188 [ win ] conformance/glsl/constructors/glsl-construct-vec-mat-index.html [ RetryOnFailure ] @@ -140,7 +140,7 @@ # Win NVIDIA failures crbug.com/626524 [ win nvidia no-passthrough ] conformance/textures/misc/texture-npot-video.html [ RetryOnFailure ] crbug.com/630860 [ win nvidia ] conformance/textures/misc/texture-upload-size.html [ RetryOnFailure ] -crbug.com/3018 [ win nvidia vulkan passthrough ] conformance/rendering/out-of-bounds-index-buffers.html [ Skip ] +crbug.com/angleproject/3018 [ win nvidia vulkan passthrough ] conformance/rendering/out-of-bounds-index-buffers.html [ Skip ] # crbug.com/679696 [ win nvidia no_passthrough ] conformance/extensions/ext-sRGB.html [ Failure ] @@ -196,9 +196,9 @@ # Win / D3D9 failures # Skipping these two tests because they're causing assertion failures. -crbug.com/896 [ win d3d9 no-passthrough ] conformance/extensions/oes-texture-float-with-canvas.html [ Skip ] -crbug.com/896 [ win d3d9 no-passthrough ] conformance/extensions/oes-texture-half-float-with-canvas.html [ Skip ] -crbug.com/1179 [ win d3d9 ] conformance/glsl/bugs/floor-div-cos-should-not-truncate.html [ Failure ] +crbug.com/angleproject/896 [ win d3d9 no-passthrough ] conformance/extensions/oes-texture-float-with-canvas.html [ Skip ] +crbug.com/angleproject/896 [ win d3d9 no-passthrough ] conformance/extensions/oes-texture-half-float-with-canvas.html [ Skip ] +crbug.com/angleproject/1179 [ win d3d9 ] conformance/glsl/bugs/floor-div-cos-should-not-truncate.html [ Failure ] # The functions test have been persistently flaky on D3D9 crbug.com/415609 [ win d3d9 ] conformance/glsl/functions/* [ RetryOnFailure ] @@ -216,11 +216,11 @@ # Win / OpenGL / AMD failures crbug.com/649824 [ win amd opengl ] conformance/attribs/gl-bindAttribLocation-aliasing.html [ Skip ] -crbug.com/1007 [ win amd opengl ] conformance/glsl/misc/shader-struct-scope.html [ Skip ] +crbug.com/angleproject/1007 [ win amd opengl ] conformance/glsl/misc/shader-struct-scope.html [ Skip ] # TODO(kbr): re-add after global suppression is removed. # crbug.com/1007 [ win amd opengl no-passthrough ] conformance/glsl/misc/shaders-with-invariance.html [ Skip ] -crbug.com/1007 [ win amd opengl ] conformance/glsl/misc/struct-nesting-of-variable-names.html [ Failure ] -crbug.com/1506 [ win amd opengl ] conformance/rendering/clipping-wide-points.html [ Failure ] +crbug.com/angleproject/1007 [ win amd opengl ] conformance/glsl/misc/struct-nesting-of-variable-names.html [ Failure ] +crbug.com/angleproject/1506 [ win amd opengl ] conformance/rendering/clipping-wide-points.html [ Failure ] # AMD RX 550 Failures crbug.com/950123 [ win amd-0x699f opengl ] conformance/glsl/bugs/gl-fragcoord-multisampling-bug.html [ Skip ] @@ -240,84 +240,84 @@ crbug.com/602688 [ win intel d3d11 passthrough ] conformance/renderbuffers/framebuffer-state-restoration.html [ RetryOnFailure ] # D3D9 / Passthrough command decoder -crbug.com/2192 [ win d3d9 passthrough ] conformance/textures/canvas/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] -crbug.com/2192 [ win d3d9 passthrough ] conformance/textures/canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] -crbug.com/2192 [ win d3d9 passthrough ] conformance/textures/image_bitmap_from_canvas/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] -crbug.com/2192 [ win d3d9 passthrough ] conformance/textures/image_bitmap_from_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] -crbug.com/2192 [ win d3d9 passthrough ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] -crbug.com/2192 [ win d3d9 passthrough ] conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] -crbug.com/2192 [ win d3d9 passthrough ] conformance/textures/webgl_canvas/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] -crbug.com/2192 [ win d3d9 passthrough ] conformance/textures/webgl_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2192 [ win d3d9 passthrough ] conformance/textures/canvas/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2192 [ win d3d9 passthrough ] conformance/textures/canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2192 [ win d3d9 passthrough ] conformance/textures/image_bitmap_from_canvas/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2192 [ win d3d9 passthrough ] conformance/textures/image_bitmap_from_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2192 [ win d3d9 passthrough ] conformance/textures/video/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2192 [ win d3d9 passthrough ] conformance/textures/video/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2192 [ win d3d9 passthrough ] conformance/textures/webgl_canvas/tex-2d-luminance-luminance-unsigned_byte.html [ Failure ] +crbug.com/angleproject/2192 [ win d3d9 passthrough ] conformance/textures/webgl_canvas/tex-2d-luminance_alpha-luminance_alpha-unsigned_byte.html [ Failure ] # Vulkan / Win / Passthough command decoder -crbug.com/2708 [ win vulkan passthrough ] conformance/attribs/gl-vertex-attrib-unconsumed-out-of-bounds.html [ Failure ] -crbug.com/2929 [ win vulkan passthrough ] conformance/canvas/canvas-test.html [ Failure ] -crbug.com/2918 [ win vulkan passthrough ] conformance/canvas/draw-static-webgl-to-multiple-canvas-test.html [ Failure ] -crbug.com/2918 [ win vulkan passthrough ] conformance/canvas/draw-webgl-to-canvas-test.html [ Failure ] -crbug.com/2913 [ win vulkan passthrough ] conformance/context/context-attribute-preserve-drawing-buffer.html [ Failure ] -crbug.com/2987 [ win vulkan passthrough ] conformance/misc/uninitialized-test.html [ Failure ] -crbug.com/2911 [ win vulkan passthrough ] conformance/more/functions/copyTexSubImage2D.html [ Failure ] -crbug.com/2916 [ win vulkan passthrough ] conformance/offscreencanvas/context-lost-restored-worker.html [ Failure ] -crbug.com/2916 [ win vulkan passthrough ] conformance/offscreencanvas/context-lost-restored.html [ Failure ] -crbug.com/2909 [ win vulkan passthrough ] conformance/ogles/GL/faceforward/faceforward_001_to_006.html [ Failure ] -crbug.com/2722 [ win vulkan passthrough ] conformance/renderbuffers/depth-renderbuffer-initialization.html [ Failure ] -crbug.com/2910 [ win vulkan passthrough ] conformance/renderbuffers/framebuffer-object-attachment.html [ Failure ] -crbug.com/2722 [ win vulkan passthrough ] conformance/renderbuffers/framebuffer-state-restoration.html [ Failure ] -[ win vulkan passthrough ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ Failure ] -crbug.com/2919 [ win vulkan passthrough ] conformance/rendering/preservedrawingbuffer-leak.html [ Failure ] -crbug.com/2722 [ win vulkan passthrough ] conformance/textures/misc/copy-tex-image-and-sub-image-2d.html [ Failure ] -crbug.com/2722 [ win vulkan passthrough ] conformance/textures/misc/copytexsubimage2d-large-partial-copy-corruption.html [ Failure ] -crbug.com/2722 [ win vulkan passthrough ] conformance/textures/misc/copytexsubimage2d-subrects.html [ Failure ] -crbug.com/2920 [ win vulkan passthrough ] conformance/textures/misc/gl-pixelstorei.html [ Failure ] -crbug.com/2912 [ win vulkan passthrough ] conformance/textures/misc/tex-image-and-sub-image-2d-with-array-buffer-view.html [ Failure ] -crbug.com/2722 [ win vulkan passthrough ] conformance/textures/misc/tex-image-webgl.html [ Failure ] -crbug.com/2722 [ win vulkan passthrough ] conformance/textures/misc/texture-attachment-formats.html [ Failure ] -crbug.com/2914 [ win vulkan passthrough ] conformance/textures/misc/texture-copying-feedback-loops.html [ Failure ] -crbug.com/2913 [ win vulkan passthrough ] conformance/textures/misc/texture-hd-dpi.html [ Failure ] -crbug.com/2722 [ win vulkan passthrough ] conformance/textures/misc/texture-mips.html [ Failure ] +crbug.com/angleproject/2708 [ win vulkan passthrough ] conformance/attribs/gl-vertex-attrib-unconsumed-out-of-bounds.html [ Failure ] +crbug.com/angleproject/2929 [ win vulkan passthrough ] conformance/canvas/canvas-test.html [ Failure ] +crbug.com/angleproject/2918 [ win vulkan passthrough ] conformance/canvas/draw-static-webgl-to-multiple-canvas-test.html [ Failure ] +crbug.com/angleproject/2918 [ win vulkan passthrough ] conformance/canvas/draw-webgl-to-canvas-test.html [ Failure ] +crbug.com/angleproject/2913 [ win vulkan passthrough ] conformance/context/context-attribute-preserve-drawing-buffer.html [ Failure ] +crbug.com/angleproject/2987 [ win vulkan passthrough ] conformance/misc/uninitialized-test.html [ Failure ] +crbug.com/angleproject/2911 [ win vulkan passthrough ] conformance/more/functions/copyTexSubImage2D.html [ Failure ] +crbug.com/angleproject/2916 [ win vulkan passthrough ] conformance/offscreencanvas/context-lost-restored-worker.html [ Failure ] +crbug.com/angleproject/2916 [ win vulkan passthrough ] conformance/offscreencanvas/context-lost-restored.html [ Failure ] +crbug.com/angleproject/2909 [ win vulkan passthrough ] conformance/ogles/GL/faceforward/faceforward_001_to_006.html [ Failure ] +crbug.com/angleproject/2722 [ win vulkan passthrough ] conformance/renderbuffers/depth-renderbuffer-initialization.html [ Failure ] +crbug.com/angleproject/2910 [ win vulkan passthrough ] conformance/renderbuffers/framebuffer-object-attachment.html [ Failure ] +crbug.com/angleproject/2722 [ win vulkan passthrough ] conformance/renderbuffers/framebuffer-state-restoration.html [ Failure ] +crbug.com/angleproject/0 [ win vulkan passthrough ] conformance/renderbuffers/stencil-renderbuffer-initialization.html [ Failure ] +crbug.com/angleproject/2919 [ win vulkan passthrough ] conformance/rendering/preservedrawingbuffer-leak.html [ Failure ] +crbug.com/angleproject/2722 [ win vulkan passthrough ] conformance/textures/misc/copy-tex-image-and-sub-image-2d.html [ Failure ] +crbug.com/angleproject/2722 [ win vulkan passthrough ] conformance/textures/misc/copytexsubimage2d-large-partial-copy-corruption.html [ Failure ] +crbug.com/angleproject/2722 [ win vulkan passthrough ] conformance/textures/misc/copytexsubimage2d-subrects.html [ Failure ] +crbug.com/angleproject/2920 [ win vulkan passthrough ] conformance/textures/misc/gl-pixelstorei.html [ Failure ] +crbug.com/angleproject/2912 [ win vulkan passthrough ] conformance/textures/misc/tex-image-and-sub-image-2d-with-array-buffer-view.html [ Failure ] +crbug.com/angleproject/2722 [ win vulkan passthrough ] conformance/textures/misc/tex-image-webgl.html [ Failure ] +crbug.com/angleproject/2722 [ win vulkan passthrough ] conformance/textures/misc/texture-attachment-formats.html [ Failure ] +crbug.com/angleproject/2914 [ win vulkan passthrough ] conformance/textures/misc/texture-copying-feedback-loops.html [ Failure ] +crbug.com/angleproject/2913 [ win vulkan passthrough ] conformance/textures/misc/texture-hd-dpi.html [ Failure ] +crbug.com/angleproject/2722 [ win vulkan passthrough ] conformance/textures/misc/texture-mips.html [ Failure ] # Note: the following test crashes so it's skipped. http://anglebug.com/3352 -crbug.com/2921 [ win vulkan passthrough ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Skip ] -crbug.com/2672 [ win vulkan passthrough ] WebglExtension_ANGLE_instanced_arrays [ Failure ] -crbug.com/2897 [ win vulkan passthrough ] WebglExtension_EXT_blend_minmax [ Failure ] -crbug.com/2898 [ win vulkan passthrough ] WebglExtension_EXT_color_buffer_half_float [ Failure ] -crbug.com/2885 [ win vulkan passthrough ] WebglExtension_EXT_disjoint_timer_query [ Failure ] -crbug.com/2887 [ win vulkan passthrough ] WebglExtension_EXT_frag_depth [ Failure ] -crbug.com/2899 [ win vulkan passthrough ] WebglExtension_EXT_shader_texture_lod [ Failure ] -crbug.com/2902 [ win vulkan passthrough ] WebglExtension_OES_element_index_uint [ Failure ] -crbug.com/2903 [ win vulkan passthrough ] WebglExtension_OES_standard_derivatives [ Failure ] -crbug.com/2898 [ win vulkan passthrough ] WebglExtension_OES_texture_float [ Failure ] -crbug.com/2898 [ win vulkan passthrough ] WebglExtension_OES_texture_float_linear [ Failure ] -crbug.com/2898 [ win vulkan passthrough ] WebglExtension_OES_texture_half_float [ Failure ] -crbug.com/2898 [ win vulkan passthrough ] WebglExtension_OES_texture_half_float_linear [ Failure ] -crbug.com/2898 [ win vulkan passthrough ] WebglExtension_WEBGL_color_buffer_float [ Failure ] -crbug.com/2904 [ win vulkan passthrough ] WebglExtension_WEBGL_compressed_texture_s3tc [ Failure ] -crbug.com/2905 [ win vulkan passthrough ] WebglExtension_WEBGL_depth_texture [ Failure ] -crbug.com/2394 [ win vulkan passthrough ] WebglExtension_WEBGL_draw_buffers [ Failure ] -crbug.com/3111 [ win vulkan passthrough ] deqp/data/gles2/shaders/swizzles.html [ Skip ] +crbug.com/angleproject/2921 [ win vulkan passthrough ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Skip ] +crbug.com/angleproject/2672 [ win vulkan passthrough ] WebglExtension_ANGLE_instanced_arrays [ Failure ] +crbug.com/angleproject/2897 [ win vulkan passthrough ] WebglExtension_EXT_blend_minmax [ Failure ] +crbug.com/angleproject/2898 [ win vulkan passthrough ] WebglExtension_EXT_color_buffer_half_float [ Failure ] +crbug.com/angleproject/2885 [ win vulkan passthrough ] WebglExtension_EXT_disjoint_timer_query [ Failure ] +crbug.com/angleproject/2887 [ win vulkan passthrough ] WebglExtension_EXT_frag_depth [ Failure ] +crbug.com/angleproject/2899 [ win vulkan passthrough ] WebglExtension_EXT_shader_texture_lod [ Failure ] +crbug.com/angleproject/2902 [ win vulkan passthrough ] WebglExtension_OES_element_index_uint [ Failure ] +crbug.com/angleproject/2903 [ win vulkan passthrough ] WebglExtension_OES_standard_derivatives [ Failure ] +crbug.com/angleproject/2898 [ win vulkan passthrough ] WebglExtension_OES_texture_float [ Failure ] +crbug.com/angleproject/2898 [ win vulkan passthrough ] WebglExtension_OES_texture_float_linear [ Failure ] +crbug.com/angleproject/2898 [ win vulkan passthrough ] WebglExtension_OES_texture_half_float [ Failure ] +crbug.com/angleproject/2898 [ win vulkan passthrough ] WebglExtension_OES_texture_half_float_linear [ Failure ] +crbug.com/angleproject/2898 [ win vulkan passthrough ] WebglExtension_WEBGL_color_buffer_float [ Failure ] +crbug.com/angleproject/2904 [ win vulkan passthrough ] WebglExtension_WEBGL_compressed_texture_s3tc [ Failure ] +crbug.com/angleproject/2905 [ win vulkan passthrough ] WebglExtension_WEBGL_depth_texture [ Failure ] +crbug.com/angleproject/2394 [ win vulkan passthrough ] WebglExtension_WEBGL_draw_buffers [ Failure ] +crbug.com/angleproject/3111 [ win vulkan passthrough ] deqp/data/gles2/shaders/swizzles.html [ Skip ] # Vulkan / Win / NVIDIA / Passthough command decoder -crbug.com/2918 [ win nvidia vulkan passthrough ] conformance/canvas/to-data-url-test.html [ Failure ] -crbug.com/2922 [ win nvidia vulkan passthrough ] conformance/context/premultiplyalpha-test.html [ Failure ] -crbug.com/2939 [ win nvidia vulkan passthrough ] conformance/rendering/gl-scissor-fbo-test.html [ RetryOnFailure ] -crbug.com/2915 [ win nvidia vulkan passthrough ] conformance/textures/misc/texture-size.html [ Failure ] -crbug.com/2930 [ win nvidia vulkan passthrough ] conformance/textures/misc/texture-size-cube-maps.html [ Failure ] -crbug.com/2915 [ win nvidia vulkan passthrough ] conformance/limits/gl-max-texture-dimensions.html [ Failure ] -crbug.com/2926 [ win nvidia vulkan passthrough ] deqp/data/gles2/shaders/conversions.html [ Failure ] +crbug.com/angleproject/2918 [ win nvidia vulkan passthrough ] conformance/canvas/to-data-url-test.html [ Failure ] +crbug.com/angleproject/2922 [ win nvidia vulkan passthrough ] conformance/context/premultiplyalpha-test.html [ Failure ] +crbug.com/angleproject/2939 [ win nvidia vulkan passthrough ] conformance/rendering/gl-scissor-fbo-test.html [ RetryOnFailure ] +crbug.com/angleproject/2915 [ win nvidia vulkan passthrough ] conformance/textures/misc/texture-size.html [ Failure ] +crbug.com/angleproject/2930 [ win nvidia vulkan passthrough ] conformance/textures/misc/texture-size-cube-maps.html [ Failure ] +crbug.com/angleproject/2915 [ win nvidia vulkan passthrough ] conformance/limits/gl-max-texture-dimensions.html [ Failure ] +crbug.com/angleproject/2926 [ win nvidia vulkan passthrough ] deqp/data/gles2/shaders/conversions.html [ Failure ] # Vulkan / Win / Intel / Passthough command decoder -crbug.com/2722 [ win intel vulkan passthrough ] conformance/rendering/clipping-wide-points.html [ Failure ] +crbug.com/angleproject/2722 [ win intel vulkan passthrough ] conformance/rendering/clipping-wide-points.html [ Failure ] # Vulkan / Win / AMD / Passthough command decoder -crbug.com/2931 [ win amd vulkan passthrough ] conformance/buffers/buffer-data-dynamic-delay.html [ Failure ] -crbug.com/2918 [ win amd vulkan passthrough ] conformance/canvas/to-data-url-test.html [ Failure ] -crbug.com/2922 [ win amd vulkan passthrough ] conformance/context/premultiplyalpha-test.html [ Failure ] -crbug.com/2722 [ win amd vulkan passthrough ] conformance/rendering/clipping-wide-points.html [ Failure ] -crbug.com/2926 [ win amd vulkan passthrough ] deqp/data/gles2/shaders/conversions.html [ Failure ] -crbug.com/2926 [ win amd vulkan passthrough ] deqp/data/gles2/shaders/linkage.html [ Failure ] +crbug.com/angleproject/2931 [ win amd vulkan passthrough ] conformance/buffers/buffer-data-dynamic-delay.html [ Failure ] +crbug.com/angleproject/2918 [ win amd vulkan passthrough ] conformance/canvas/to-data-url-test.html [ Failure ] +crbug.com/angleproject/2922 [ win amd vulkan passthrough ] conformance/context/premultiplyalpha-test.html [ Failure ] +crbug.com/angleproject/2722 [ win amd vulkan passthrough ] conformance/rendering/clipping-wide-points.html [ Failure ] +crbug.com/angleproject/2926 [ win amd vulkan passthrough ] deqp/data/gles2/shaders/conversions.html [ Failure ] +crbug.com/angleproject/2926 [ win amd vulkan passthrough ] deqp/data/gles2/shaders/linkage.html [ Failure ] crbug.com/931016 [ win amd vulkan passthrough ] conformance/textures/image_bitmap_from_canvas/tex-2d-luminance* [ Failure ] crbug.com/931016 [ win amd vulkan passthrough ] conformance/textures/image_bitmap_from_canvas/tex-2d-rgb* [ Failure ] -crbug.com/3343 [ win amd vulkan passthrough ] conformance/glsl/bugs/assign-to-swizzled-twice-in-function.html [ Failure ] +crbug.com/angleproject/3343 [ win amd vulkan passthrough ] conformance/glsl/bugs/assign-to-swizzled-twice-in-function.html [ Failure ] crbug.com/857644 [ win passthrough amd vulkan ] conformance/glsl/samplers/glsl-function-texture2dproj.html [ Failure ] crbug.com/957644 [ win passthrough amd vulkan ] conformance/glsl/samplers/glsl-function-texture2dprojlod.html [ Failure ] crbug.com/957644 [ win passthrough amd vulkan ] conformance/textures/misc/texture-corner-case-videos.html [ Failure ] @@ -519,7 +519,7 @@ crbug.com/693135 [ android qualcomm-adreno-(tm)-420 ] conformance/offscreencanvas/context-attribute-preserve-drawing-buffer.html [ Failure ] [ qualcomm-adreno-(tm)-420 android ] WebglExtension_EXT_sRGB [ Failure ] [ qualcomm-adreno-(tm)-430 android ] WebglExtension_EXT_sRGB [ Failure ] -crbug.com/2046 [ android qualcomm-adreno-(tm)-420 ] conformance/glsl/misc/uninitialized-local-global-variables.html [ Failure ] +crbug.com/angleproject/2046 [ android qualcomm-adreno-(tm)-420 ] conformance/glsl/misc/uninitialized-local-global-variables.html [ Failure ] # Nexus 9 crbug.com/478572 [ android nvidia ] deqp/data/gles2/shaders/functions.html [ Failure ] @@ -558,11 +558,11 @@ crbug.com/908866 [ android opengles ] conformance/textures/canvas/* [ Failure ] # Misc failures -crbug.com/2988 [ android opengles ] conformance/context/context-size-change.html [ Failure ] -crbug.com/2407 [ android opengles ] conformance/misc/uninitialized-test.html [ Failure ] +crbug.com/angleproject/2988 [ android opengles ] conformance/context/context-size-change.html [ Failure ] +crbug.com/angleproject/2407 [ android opengles ] conformance/misc/uninitialized-test.html [ Failure ] crbug.com/908912 [ android opengles ] conformance/renderbuffers/framebuffer-test.html [ Failure ] -crbug.com/2978 [ android opengles ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Failure ] -crbug.com/1552 [ android opengles ] WebglExtension_WEBGL_compressed_texture_etc1 [ Failure ] +crbug.com/angleproject/2978 [ android opengles ] conformance/uniforms/out-of-bounds-uniform-array-access.html [ Failure ] +crbug.com/angleproject/1552 [ android opengles ] WebglExtension_WEBGL_compressed_texture_etc1 [ Failure ] ############ # ChromeOS #
diff --git a/device/fido/pin.cc b/device/fido/pin.cc index 9f0bbc62..b09ea3d 100644 --- a/device/fido/pin.cc +++ b/device/fido/pin.cc
@@ -122,16 +122,12 @@ const KeyAgreementResponse& response) { bssl::UniquePtr<EC_POINT> ret(EC_POINT_new(group)); - BIGNUM x_bn, y_bn; - BN_init(&x_bn); - BN_init(&y_bn); - BN_bin2bn(response.x, sizeof(response.x), &x_bn); - BN_bin2bn(response.y, sizeof(response.y), &y_bn); + bssl::UniquePtr<BIGNUM> x_bn(BN_new()), y_bn(BN_new()); + BN_bin2bn(response.x, sizeof(response.x), x_bn.get()); + BN_bin2bn(response.y, sizeof(response.y), y_bn.get()); const bool on_curve = - EC_POINT_set_affine_coordinates_GFp(group, ret.get(), &x_bn, &y_bn, - nullptr /* ctx */) == 1; - BN_clear(&x_bn); - BN_clear(&y_bn); + EC_POINT_set_affine_coordinates_GFp(group, ret.get(), x_bn.get(), + y_bn.get(), nullptr /* ctx */) == 1; if (!on_curve) { return base::nullopt;
diff --git a/device/vr/BUILD.gn b/device/vr/BUILD.gn index c57824a..8d29f9c 100644 --- a/device/vr/BUILD.gn +++ b/device/vr/BUILD.gn
@@ -178,6 +178,25 @@ "windows_mixed_reality/wrappers/wmr_timestamp.cc", "windows_mixed_reality/wrappers/wmr_timestamp.h", ] + + # Sources only meant to be actually used in tests, but need to be always + # included. + sources += [ + "test/locked_vr_test_hook.cc", + "test/locked_vr_test_hook.h", + "windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.cc", + "windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.h", + "windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.cc", + "windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.h", + "windows_mixed_reality/wrappers/test/mock_wmr_input_manager.cc", + "windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h", + "windows_mixed_reality/wrappers/test/mock_wmr_origins.cc", + "windows_mixed_reality/wrappers/test/mock_wmr_origins.h", + "windows_mixed_reality/wrappers/test/mock_wmr_rendering.cc", + "windows_mixed_reality/wrappers/test/mock_wmr_rendering.h", + "windows_mixed_reality/wrappers/test/mock_wmr_timestamp.cc", + "windows_mixed_reality/wrappers/test/mock_wmr_timestamp.h", + ] } if (enable_oculus_vr) {
diff --git a/device/vr/oculus/oculus_gamepad_helper.cc b/device/vr/oculus/oculus_gamepad_helper.cc index 99fa28db..da83554b 100644 --- a/device/vr/oculus/oculus_gamepad_helper.cc +++ b/device/vr/oculus/oculus_gamepad_helper.cc
@@ -201,7 +201,7 @@ // TODO(https://crbug.com/942201): Get correct ID string once WebXR spec issue // #550 (https://github.com/immersive-web/webxr/issues/550) is resolved. OculusGamepadBuilder(ovrInputState state, ovrHandType hand) - : GamepadBuilder("unknown", + : GamepadBuilder("oculus-touch", GamepadMapping::kXRStandard, OculusToMojomHand(hand)), state_(state) {}
diff --git a/device/vr/openvr/openvr_gamepad_helper.cc b/device/vr/openvr/openvr_gamepad_helper.cc index 98293081..00c5edbf 100644 --- a/device/vr/openvr/openvr_gamepad_helper.cc +++ b/device/vr/openvr/openvr_gamepad_helper.cc
@@ -249,7 +249,7 @@ uint32_t controller_id, vr::VRControllerState_t controller_state, device::mojom::XRHandedness handedness) - : GamepadBuilder("unknown", GamepadMapping::kXRStandard, handedness), + : GamepadBuilder("openvr", GamepadMapping::kXRStandard, handedness), controller_state_(controller_state) { supported_buttons_ = vr_system->GetUint64TrackedDeviceProperty( controller_id, vr::Prop_SupportedButtons_Uint64);
diff --git a/device/vr/test/locked_vr_test_hook.cc b/device/vr/test/locked_vr_test_hook.cc new file mode 100644 index 0000000..d1383ea --- /dev/null +++ b/device/vr/test/locked_vr_test_hook.cc
@@ -0,0 +1,39 @@ +// Copyright 2019 The Chromium 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/vr/test/locked_vr_test_hook.h" + +namespace device { + +// LockedVRTestHook +LockedVRTestHook::LockedVRTestHook(VRTestHook* test_hook) + : test_hook_(test_hook) { + LockProvider::GetLock()->Acquire(); +} + +LockedVRTestHook::~LockedVRTestHook() { + LockProvider::GetLock()->Release(); +} + +VRTestHook* LockedVRTestHook::GetHook() { + return test_hook_; +} + +// LockProvider +LockProvider* LockProvider::instance_ = nullptr; + +base::Lock* LockProvider::GetLock() { + if (!instance_) { + instance_ = new LockProvider(); + } + return &(instance_->lock_); +} + +LockProvider::LockProvider() : lock_() { + DCHECK(!instance_); +} + +LockProvider::~LockProvider() = default; + +} // namespace device
diff --git a/device/vr/test/locked_vr_test_hook.h b/device/vr/test/locked_vr_test_hook.h new file mode 100644 index 0000000..5c493251 --- /dev/null +++ b/device/vr/test/locked_vr_test_hook.h
@@ -0,0 +1,42 @@ +// Copyright 2019 The Chromium 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_VR_TEST_LOCKED_VR_TEST_HOOK_H_ +#define DEVICE_VR_TEST_LOCKED_VR_TEST_HOOK_H_ + +#include "base/synchronization/lock.h" + +namespace device { + +class VRTestHook; + +// Provides thread safe access to a VRTestHook. Holds the lock as long as the +// object is alive. +class LockedVRTestHook { + public: + explicit LockedVRTestHook(VRTestHook* test_hook); + ~LockedVRTestHook(); + + VRTestHook* GetHook(); + + private: + VRTestHook* test_hook_; +}; + +// Singleton Lock holder. Workaround for not being able to have a static member +// lock due to not being able to re-assign. +class LockProvider { + public: + static base::Lock* GetLock(); + ~LockProvider(); + + private: + LockProvider(); + static LockProvider* instance_; + base::Lock lock_; +}; + +} // namespace device + +#endif // DEVICE_VR_TEST_LOCKED_VR_TEST_HOOK_H_
diff --git a/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc b/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc index 649c0418..da8f34bd 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_input_helper.cc
@@ -193,7 +193,8 @@ // TODO(https://crbug.com/942201): Get correct ID string once WebXR spec issue // #550 (https://github.com/immersive-web/webxr/issues/550) is resolved. - GamepadBuilder builder("unknown", GamepadBuilder::GamepadMapping::kXRStandard, + GamepadBuilder builder("windows-mixed-reality", + GamepadBuilder::GamepadMapping::kXRStandard, handedness); builder.SetAxisDeadzone(kDeadzoneMinimum);
diff --git a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc index 7bbda73..4438a3a 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_renderloop.cc
@@ -19,8 +19,10 @@ #include "base/win/core_winrt_util.h" #include "base/win/scoped_co_mem.h" #include "base/win/scoped_hstring.h" +#include "device/vr/test/test_hook.h" #include "device/vr/windows/d3d11_texture_helper.h" #include "device/vr/windows_mixed_reality/mixed_reality_input_helper.h" +#include "device/vr/windows_mixed_reality/mixed_reality_statics.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_logging.h" @@ -198,6 +200,13 @@ bool MixedRealityRenderLoop::StartRuntime() { initializer_ = std::make_unique<base::win::ScopedWinrtInitializer>(); + { + auto hook = MixedRealityDeviceStatics::GetLockedTestHook(); + if (hook.GetHook()) { + hook.GetHook()->AttachCurrentThread(); + } + } + InitializeSpace(); if (!holographic_space_) return false; @@ -261,6 +270,13 @@ if (initializer_) initializer_ = nullptr; + + { + auto hook = MixedRealityDeviceStatics::GetLockedTestHook(); + if (hook.GetHook()) { + hook.GetHook()->DetachCurrentThread(); + } + } } void MixedRealityRenderLoop::InitializeOrigin() { @@ -327,6 +343,8 @@ void MixedRealityRenderLoop::ClearStageStatics() { stage_changed_subscription_ = nullptr; + if (stage_statics_) + stage_statics_->Dispose(); stage_statics_ = nullptr; }
diff --git a/device/vr/windows_mixed_reality/mixed_reality_statics.cc b/device/vr/windows_mixed_reality/mixed_reality_statics.cc index 6ab4d48..09d79d0 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_statics.cc +++ b/device/vr/windows_mixed_reality/mixed_reality_statics.cc
@@ -12,6 +12,8 @@ #include "base/strings/utf_string_conversions.h" #include "base/win/core_winrt_util.h" #include "base/win/scoped_hstring.h" +#include "device/vr/test/locked_vr_test_hook.h" +#include "device/vr/test/test_hook.h" namespace device { @@ -35,11 +37,25 @@ ComPtr<IHolographicSpaceStatics2> holographic_space_statics_; }; +VRTestHook* MixedRealityDeviceStatics::test_hook_ = nullptr; + std::unique_ptr<MixedRealityDeviceStatics> MixedRealityDeviceStatics::CreateInstance() { return std::make_unique<MixedRealityDeviceStaticsImpl>(); } +void MixedRealityDeviceStatics::SetTestHook(VRTestHook* hook) { + // This may be called from any thread - tests are responsible for + // maintaining thread safety, typically by not changing the test hook + // while presenting. + auto locked_hook = GetLockedTestHook(); + test_hook_ = hook; +} + +LockedVRTestHook MixedRealityDeviceStatics::GetLockedTestHook() { + return LockedVRTestHook(test_hook_); +} + MixedRealityDeviceStatics::~MixedRealityDeviceStatics() {} MixedRealityDeviceStaticsImpl::MixedRealityDeviceStaticsImpl() { @@ -70,6 +86,8 @@ } bool MixedRealityDeviceStaticsImpl::IsHardwareAvailable() { + if (GetLockedTestHook().GetHook()) + return true; if (!holographic_space_statics_) return false; @@ -79,6 +97,8 @@ } bool MixedRealityDeviceStaticsImpl::IsApiAvailable() { + if (GetLockedTestHook().GetHook()) + return true; if (!holographic_space_statics_) return false;
diff --git a/device/vr/windows_mixed_reality/mixed_reality_statics.h b/device/vr/windows_mixed_reality/mixed_reality_statics.h index d7d4d21..c1cb5ac 100644 --- a/device/vr/windows_mixed_reality/mixed_reality_statics.h +++ b/device/vr/windows_mixed_reality/mixed_reality_statics.h
@@ -7,19 +7,27 @@ #include <memory> +#include "device/vr/test/locked_vr_test_hook.h" #include "device/vr/vr_export.h" namespace device { +class VRTestHook; + class DEVICE_VR_EXPORT MixedRealityDeviceStatics { public: static std::unique_ptr<MixedRealityDeviceStatics> CreateInstance(); + static void SetTestHook(VRTestHook* hook); + static LockedVRTestHook GetLockedTestHook(); virtual ~MixedRealityDeviceStatics(); // TODO(billorr): Consider notifications instead of polling. virtual bool IsHardwareAvailable() = 0; virtual bool IsApiAvailable() = 0; + + private: + static VRTestHook* test_hook_; }; } // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.cc new file mode 100644 index 0000000..6582ab7 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.cc
@@ -0,0 +1,50 @@ +// Copyright 2019 The Chromium 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/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.h" + +#include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_rendering.h" +#include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_timestamp.h" +#include "device/vr/windows_mixed_reality/wrappers/wmr_rendering.h" + +namespace device { + +// MockWMRHolographicFramePrediction +MockWMRHolographicFramePrediction::MockWMRHolographicFramePrediction() {} + +MockWMRHolographicFramePrediction::~MockWMRHolographicFramePrediction() = + default; + +std::unique_ptr<WMRTimestamp> MockWMRHolographicFramePrediction::Timestamp() { + return std::make_unique<MockWMRTimestamp>(); +} + +std::vector<std::unique_ptr<WMRCameraPose>> +MockWMRHolographicFramePrediction::CameraPoses() { + std::vector<std::unique_ptr<WMRCameraPose>> ret; + // Production code only expects a single camera pose. + ret.push_back(std::make_unique<MockWMRCameraPose>()); + return ret; +} + +// MockWMRHolographicFrame +MockWMRHolographicFrame::MockWMRHolographicFrame() {} + +MockWMRHolographicFrame::~MockWMRHolographicFrame() = default; + +std::unique_ptr<WMRHolographicFramePrediction> +MockWMRHolographicFrame::CurrentPrediction() { + return std::make_unique<MockWMRHolographicFramePrediction>(); +} + +std::unique_ptr<WMRRenderingParameters> +MockWMRHolographicFrame::TryGetRenderingParameters(const WMRCameraPose* pose) { + return std::make_unique<MockWMRRenderingParameters>(); +} + +bool MockWMRHolographicFrame::TryPresentUsingCurrentPrediction() { + return true; +} + +} // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.h b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.h new file mode 100644 index 0000000..f0a8044 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.h
@@ -0,0 +1,39 @@ +// Copyright 2019 The Chromium 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_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_HOLOGRAPHIC_FRAME_H_ +#define DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_HOLOGRAPHIC_FRAME_H_ + +#include "device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.h" + +namespace device { + +class MockWMRHolographicFramePrediction : public WMRHolographicFramePrediction { + public: + MockWMRHolographicFramePrediction(); + ~MockWMRHolographicFramePrediction() override; + + std::unique_ptr<WMRTimestamp> Timestamp() override; + std::vector<std::unique_ptr<WMRCameraPose>> CameraPoses() override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRHolographicFramePrediction); +}; + +class MockWMRHolographicFrame : public WMRHolographicFrame { + public: + MockWMRHolographicFrame(); + ~MockWMRHolographicFrame() override; + + std::unique_ptr<WMRHolographicFramePrediction> CurrentPrediction() override; + std::unique_ptr<WMRRenderingParameters> TryGetRenderingParameters( + const WMRCameraPose* pose) override; + bool TryPresentUsingCurrentPrediction() override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRHolographicFrame); +}; + +} // namespace device + +#endif // DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_HOLOGRAPHIC_FRAME_H_
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.cc new file mode 100644 index 0000000..c250e18 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.cc
@@ -0,0 +1,76 @@ +// Copyright 2019 The Chromium 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/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.h" + +#include <D3D11_1.h> +#include <dxgi.h> +#include <wrl.h> + +#include "base/stl_util.h" + +#include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.h" + +namespace device { + +MockWMRHolographicSpace::MockWMRHolographicSpace() {} + +MockWMRHolographicSpace::~MockWMRHolographicSpace() = default; + +ABI::Windows::Graphics::Holographic::HolographicAdapterId +MockWMRHolographicSpace::PrimaryAdapterId() { + ABI::Windows::Graphics::Holographic::HolographicAdapterId ret; + + // This is currently duplicated from the mock OpenVR implementation. It can + // be de-duped once https://crrev.com/c/1575030, which moves the DX11.1 + // helper code into a standalone library. + // Enumerate devices until we find one that supports 11.1. + int32_t adapter_index = -1; + Microsoft::WRL::ComPtr<IDXGIFactory1> dxgi_factory; + Microsoft::WRL::ComPtr<IDXGIAdapter> adapter; + bool success = SUCCEEDED(CreateDXGIFactory1(IID_PPV_ARGS(&dxgi_factory))); + DCHECK(success); + for (int i = 0; SUCCEEDED(dxgi_factory->EnumAdapters(i, &adapter)); ++i) { + D3D_FEATURE_LEVEL feature_levels[] = {D3D_FEATURE_LEVEL_11_1}; + UINT flags = 0; + D3D_FEATURE_LEVEL feature_level_out = D3D_FEATURE_LEVEL_11_1; + + Microsoft::WRL::ComPtr<ID3D11Device> d3d11_device; + Microsoft::WRL::ComPtr<ID3D11DeviceContext> d3d11_device_context; + if (SUCCEEDED(D3D11CreateDevice( + adapter.Get(), D3D_DRIVER_TYPE_UNKNOWN, NULL, flags, feature_levels, + base::size(feature_levels), D3D11_SDK_VERSION, &d3d11_device, + &feature_level_out, &d3d11_device_context))) { + adapter_index = i; + break; + } + } + + if (adapter_index == -1) + return ret; + + DXGI_ADAPTER_DESC description; + success = SUCCEEDED(adapter->GetDesc(&description)); + if (!success) { + return ret; + } + + ret.LowPart = description.AdapterLuid.LowPart; + ret.HighPart = description.AdapterLuid.HighPart; + + return ret; +} + +std::unique_ptr<WMRHolographicFrame> +MockWMRHolographicSpace::TryCreateNextFrame() { + return std::make_unique<MockWMRHolographicFrame>(); +} + +bool MockWMRHolographicSpace::TrySetDirect3D11Device( + const Microsoft::WRL::ComPtr< + ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>& device) { + return true; +} + +} // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.h b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.h new file mode 100644 index 0000000..2e9a354f --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.h
@@ -0,0 +1,30 @@ +// Copyright 2019 The Chromium 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_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_HOLOGRAPHIC_SPACE_H_ +#define DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_HOLOGRAPHIC_SPACE_H_ + +#include "device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h" + +namespace device { + +class MockWMRHolographicSpace : public WMRHolographicSpace { + public: + MockWMRHolographicSpace(); + ~MockWMRHolographicSpace() override; + + ABI::Windows::Graphics::Holographic::HolographicAdapterId PrimaryAdapterId() + override; + std::unique_ptr<WMRHolographicFrame> TryCreateNextFrame() override; + bool TrySetDirect3D11Device( + const Microsoft::WRL::ComPtr< + ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>& device) + override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRHolographicSpace); +}; + +} // namespace device + +#endif // DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_HOLOGRAPHIC_SPACE_H_
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.cc new file mode 100644 index 0000000..68d57f6 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.cc
@@ -0,0 +1,22 @@ +// Copyright 2019 The Chromium 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/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h" +#include "device/vr/windows_mixed_reality/wrappers/wmr_input_source_state.h" + +namespace device { + +// MockWMRInputManager +MockWMRInputManager::MockWMRInputManager() {} + +MockWMRInputManager::~MockWMRInputManager() = default; + +std::vector<WMRInputSourceState> +MockWMRInputManager::GetDetectedSourcesAtTimestamp( + Microsoft::WRL::ComPtr<ABI::Windows::Perception::IPerceptionTimestamp> + timestamp) const { + return {}; +} + +} // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h new file mode 100644 index 0000000..5f68077 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h
@@ -0,0 +1,26 @@ +// Copyright 2019 The Chromium 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_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_INPUT_MANAGER_H_ +#define DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_INPUT_MANAGER_H_ + +#include "device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h" + +namespace device { + +class MockWMRInputManager : public WMRInputManager { + public: + MockWMRInputManager(); + ~MockWMRInputManager() override; + + std::vector<WMRInputSourceState> GetDetectedSourcesAtTimestamp( + Microsoft::WRL::ComPtr<ABI::Windows::Perception::IPerceptionTimestamp> + timestamp) const override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRInputManager); +}; + +} // namespace device + +#endif // DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_INPUT_MANAGER_H_
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.cc new file mode 100644 index 0000000..9e794fc --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.cc
@@ -0,0 +1,74 @@ +// Copyright 2019 The Chromium 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/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.h" + +namespace device { + +// MockWMRCoordinateSystem +MockWMRCoordinateSystem::MockWMRCoordinateSystem() {} + +MockWMRCoordinateSystem::~MockWMRCoordinateSystem() = default; + +bool MockWMRCoordinateSystem::TryGetTransformTo( + const WMRCoordinateSystem* other, + ABI::Windows::Foundation::Numerics::Matrix4x4* this_to_other) { + *this_to_other = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; + return true; +} + +// MockWMRStationaryOrigin +MockWMRStationaryOrigin::MockWMRStationaryOrigin() {} + +MockWMRStationaryOrigin::~MockWMRStationaryOrigin() = default; + +std::unique_ptr<WMRCoordinateSystem> +MockWMRStationaryOrigin::CoordinateSystem() { + return std::make_unique<MockWMRCoordinateSystem>(); +} + +// MockWMRAttachedOrigin +MockWMRAttachedOrigin::MockWMRAttachedOrigin() {} + +MockWMRAttachedOrigin::~MockWMRAttachedOrigin() = default; + +std::unique_ptr<WMRCoordinateSystem> +MockWMRAttachedOrigin::TryGetCoordinatesAtTimestamp( + const WMRTimestamp* timestamp) { + return std::make_unique<MockWMRCoordinateSystem>(); +} + +// MockWMRStageOrigin +MockWMRStageOrigin::MockWMRStageOrigin() {} + +MockWMRStageOrigin::~MockWMRStageOrigin() = default; + +std::unique_ptr<WMRCoordinateSystem> MockWMRStageOrigin::CoordinateSystem() { + return std::make_unique<MockWMRCoordinateSystem>(); +} + +ABI::Windows::Perception::Spatial::SpatialMovementRange +MockWMRStageOrigin::MovementRange() { + return ABI::Windows::Perception::Spatial::SpatialMovementRange_NoMovement; +} + +std::vector<ABI::Windows::Foundation::Numerics::Vector3> +MockWMRStageOrigin::GetMovementBounds(const WMRCoordinateSystem* coordinates) { + return {}; +} + +// MockWMRStageStatics +MockWMRStageStatics::MockWMRStageStatics() {} + +MockWMRStageStatics::~MockWMRStageStatics() {} + +void MockWMRStageStatics::Dispose() { + dispose_called_ = true; +} + +std::unique_ptr<WMRStageOrigin> MockWMRStageStatics::CurrentStage() { + return std::make_unique<MockWMRStageOrigin>(); +} + +} // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.h b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.h new file mode 100644 index 0000000..88fcc148 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.h
@@ -0,0 +1,79 @@ +// Copyright 2019 The Chromium 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_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_ORIGINS_H_ +#define DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_ORIGINS_H_ + +#include <windows.perception.spatial.h> +#include <wrl.h> + +#include "device/vr/windows_mixed_reality/wrappers/wmr_origins.h" + +namespace device { + +class MockWMRCoordinateSystem : public WMRCoordinateSystem { + public: + MockWMRCoordinateSystem(); + ~MockWMRCoordinateSystem() override; + bool TryGetTransformTo( + const WMRCoordinateSystem* other, + ABI::Windows::Foundation::Numerics::Matrix4x4* this_to_other) override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRCoordinateSystem); +}; + +class MockWMRStationaryOrigin : public WMRStationaryOrigin { + public: + MockWMRStationaryOrigin(); + ~MockWMRStationaryOrigin() override; + + std::unique_ptr<WMRCoordinateSystem> CoordinateSystem() override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRStationaryOrigin); +}; + +class MockWMRAttachedOrigin : public WMRAttachedOrigin { + public: + MockWMRAttachedOrigin(); + ~MockWMRAttachedOrigin() override; + + std::unique_ptr<WMRCoordinateSystem> TryGetCoordinatesAtTimestamp( + const WMRTimestamp* timestamp) override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRAttachedOrigin); +}; + +class MockWMRStageOrigin : public WMRStageOrigin { + public: + MockWMRStageOrigin(); + ~MockWMRStageOrigin() override; + + std::unique_ptr<WMRCoordinateSystem> CoordinateSystem() override; + ABI::Windows::Perception::Spatial::SpatialMovementRange MovementRange() + override; + std::vector<ABI::Windows::Foundation::Numerics::Vector3> GetMovementBounds( + const WMRCoordinateSystem* coordinates) override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRStageOrigin); +}; + +class MockWMRStageStatics : public WMRStageStatics { + public: + MockWMRStageStatics(); + ~MockWMRStageStatics() override; + + std::unique_ptr<WMRStageOrigin> CurrentStage() override; + + void Dispose() override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRStageStatics); +}; + +} // namespace device + +#endif // DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_ORIGINS_H_
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_rendering.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_rendering.cc new file mode 100644 index 0000000..4baba390 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_rendering.cc
@@ -0,0 +1,157 @@ +// Copyright 2019 The Chromium 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/vr/windows_mixed_reality/wrappers/test/mock_wmr_rendering.h" + +#include "base/debug/debugger.h" +#include "base/logging.h" +#include "device/vr/test/test_hook.h" +#include "device/vr/windows_mixed_reality/mixed_reality_statics.h" +#include "ui/gfx/transform.h" + +namespace device { + +// MockWMRCamera +MockWMRCamera::MockWMRCamera() {} + +MockWMRCamera::~MockWMRCamera() = default; + +ABI::Windows::Foundation::Size MockWMRCamera::RenderTargetSize() { + ABI::Windows::Foundation::Size ret; + ret.Width = kDefaultWmrRenderWidth; + ret.Height = kDefaultWmrRenderHeight; + return ret; +} + +bool MockWMRCamera::IsStereo() { + return true; +} + +// MockWMRCameraPose +MockWMRCameraPose::MockWMRCameraPose() {} + +MockWMRCameraPose::~MockWMRCameraPose() = default; + +ABI::Windows::Foundation::Rect MockWMRCameraPose::Viewport() { + ABI::Windows::Foundation::Rect ret; + ret.X = 0; + ret.Y = 0; + ret.Width = kDefaultWmrRenderWidth; + ret.Height = kDefaultWmrRenderHeight; + return ret; +} + +std::unique_ptr<WMRCamera> MockWMRCameraPose::HolographicCamera() { + return std::make_unique<MockWMRCamera>(); +} + +void FrustumToMatrix(float left, + float right, + float top, + float bottom, + ABI::Windows::Foundation::Numerics::Matrix4x4* m) { + float x_scale = 2.0f / (left + right); + float y_scale = 2.0f / (top + bottom); + // We don't actually care about the near/far planes, so set to arbitrary + // sane values. + float n = 0.1f; + float f = 100.0f; + float inv_nf = 1.0f / (n - f); + + m->M11 = x_scale; + m->M21 = 0.0f; + m->M31 = 0.0f; + m->M41 = 0.0f; + m->M12 = 0.0f; + m->M22 = y_scale; + m->M32 = 0.0f; + m->M42 = 0.0f; + m->M13 = -((left - right) * x_scale * 0.5); + m->M23 = ((top - bottom) * y_scale * 0.5); + m->M33 = (n + f) * inv_nf; + m->M43 = -1.0f; + m->M14 = 0.0f; + m->M24 = 0.0f; + // TODO(https://crbug.com/931376): Make this go between 0 and 1 instead of + // -1 and 1 when adding tests for decomposition and recomposition of + // projection matrices. + m->M34 = (2.0f * f * n) * inv_nf; + m->M44 = 0.0f; +} + +ABI::Windows::Graphics::Holographic::HolographicStereoTransform +MockWMRCameraPose::ProjectionTransform() { + ABI::Windows::Graphics::Holographic::HolographicStereoTransform ret; + auto hook = MixedRealityDeviceStatics::GetLockedTestHook(); + + if (!hook.GetHook()) + return ret; + + auto device_config = hook.GetHook()->WaitGetDeviceConfig(); + auto* frustum_left = device_config.viewport_left; + auto* frustum_right = device_config.viewport_right; + + // TODO: Properly reuse some code instead of copying from + // XRView::UpdateProjectionMatrixFromFoV. + FrustumToMatrix(frustum_left[0], frustum_left[1], frustum_left[2], + frustum_left[3], &ret.Left); + FrustumToMatrix(frustum_right[0], frustum_right[1], frustum_right[2], + frustum_right[3], &ret.Right); + return ret; +} + +void CopyRowMajorFloatArrayToWindowsMatrix( + float t[16], + ABI::Windows::Foundation::Numerics::Matrix4x4& matrix) { + matrix = {t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], + t[8], t[9], t[10], t[11], t[12], t[13], t[14], t[15]}; +} + +bool MockWMRCameraPose::TryGetViewTransform( + const WMRCoordinateSystem* origin, + ABI::Windows::Graphics::Holographic::HolographicStereoTransform* + transform) { + // No idea if the view transform should be the same for both. + auto hook = MixedRealityDeviceStatics::GetLockedTestHook(); + + if (!hook.GetHook()) + return false; + + auto pose_data = hook.GetHook()->WaitGetPresentingPose(); + if (!pose_data.is_valid) + return false; + + // We need to get the inverse of the given transform, as it's the + // device-to-origin transform and we need the origin-to-device transform. + float* t = pose_data.device_to_origin; + // The gfx::Transform constructor takes arguments in row-major order, but + // we're given data in column-major order. Construct in column-major order and + // transpose since it looks cleaner than manually transposing the arguments + // passed to the constructor. + gfx::Transform device_to_origin(t[0], t[1], t[2], t[3], t[4], t[5], t[6], + t[7], t[8], t[9], t[10], t[11], t[12], t[13], + t[14], t[15]); + device_to_origin.Transpose(); + gfx::Transform origin_to_device = device_to_origin; + auto success = origin_to_device.GetInverse(&origin_to_device); + DCHECK(success); + float row_major_transform[16]; + origin_to_device.matrix().asRowMajorf(row_major_transform); + + CopyRowMajorFloatArrayToWindowsMatrix(row_major_transform, transform->Left); + CopyRowMajorFloatArrayToWindowsMatrix(row_major_transform, transform->Right); + + return true; +} + +MockWMRRenderingParameters::MockWMRRenderingParameters() {} + +MockWMRRenderingParameters::~MockWMRRenderingParameters() = default; + +Microsoft::WRL::ComPtr<ID3D11Texture2D> +MockWMRRenderingParameters::TryGetBackbufferAsTexture2D() { + return nullptr; +} + +} // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_rendering.h b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_rendering.h new file mode 100644 index 0000000..32893fe --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_rendering.h
@@ -0,0 +1,58 @@ +// Copyright 2019 The Chromium 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_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_RENDERING_H_ +#define DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_RENDERING_H_ + +#include "device/vr/windows_mixed_reality/wrappers/wmr_rendering.h" + +namespace device { + +static constexpr int kDefaultWmrRenderWidth = 1440; +static constexpr int kDefaultWmrRenderHeight = 1600; + +class MockWMRCamera : public WMRCamera { + public: + MockWMRCamera(); + ~MockWMRCamera() override; + + ABI::Windows::Foundation::Size RenderTargetSize() override; + bool IsStereo() override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRCamera); +}; + +class MockWMRCameraPose : public WMRCameraPose { + public: + MockWMRCameraPose(); + ~MockWMRCameraPose() override; + + ABI::Windows::Foundation::Rect Viewport() override; + std::unique_ptr<WMRCamera> HolographicCamera() override; + ABI::Windows::Graphics::Holographic::HolographicStereoTransform + ProjectionTransform() override; + bool TryGetViewTransform( + const WMRCoordinateSystem* origin, + ABI::Windows::Graphics::Holographic::HolographicStereoTransform* + transform) override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRCameraPose); +}; + +class MockWMRRenderingParameters : public WMRRenderingParameters { + public: + MockWMRRenderingParameters(); + ~MockWMRRenderingParameters() override; + + Microsoft::WRL::ComPtr<ID3D11Texture2D> TryGetBackbufferAsTexture2D() + override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRRenderingParameters); +}; + +} // namespace device + +#endif // DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_RENDERING_H_
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_timestamp.cc b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_timestamp.cc new file mode 100644 index 0000000..503e289 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_timestamp.cc
@@ -0,0 +1,24 @@ +// Copyright 2019 The Chromium 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/vr/windows_mixed_reality/wrappers/test/mock_wmr_timestamp.h" + +namespace device { + +// MockWMRTimestamp +MockWMRTimestamp::MockWMRTimestamp() {} + +MockWMRTimestamp::~MockWMRTimestamp() = default; + +ABI::Windows::Foundation::DateTime MockWMRTimestamp::TargetTime() const { + return ABI::Windows::Foundation::DateTime(); +} + +ABI::Windows::Foundation::TimeSpan MockWMRTimestamp::PredictionAmount() const { + ABI::Windows::Foundation::TimeSpan ret; + ret.Duration = 0; + return ret; +} + +} // namespace device
diff --git a/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_timestamp.h b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_timestamp.h new file mode 100644 index 0000000..80f608c4 --- /dev/null +++ b/device/vr/windows_mixed_reality/wrappers/test/mock_wmr_timestamp.h
@@ -0,0 +1,25 @@ +// Copyright 2019 The Chromium 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_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_TIMESTAMP_H_ +#define DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_TIMESTAMP_H_ + +#include "device/vr/windows_mixed_reality/wrappers/wmr_timestamp.h" + +namespace device { + +class MockWMRTimestamp : public WMRTimestamp { + public: + MockWMRTimestamp(); + ~MockWMRTimestamp() override; + + ABI::Windows::Foundation::DateTime TargetTime() const override; + ABI::Windows::Foundation::TimeSpan PredictionAmount() const override; + + private: + DISALLOW_COPY_AND_ASSIGN(MockWMRTimestamp); +}; + +} // namespace device + +#endif // DEVICE_VR_WINDOWS_MIXED_REALITY_WRAPPERS_TEST_MOCK_WMR_TIMESTAMP_H_
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.cc b/device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.cc index d33febbca..8771748 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.cc +++ b/device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.cc
@@ -37,6 +37,8 @@ DCHECK(prediction_); } +WMRHolographicFramePrediction::WMRHolographicFramePrediction() {} + WMRHolographicFramePrediction::~WMRHolographicFramePrediction() = default; std::unique_ptr<WMRTimestamp> WMRHolographicFramePrediction::Timestamp() { @@ -74,6 +76,8 @@ DCHECK(holographic_frame_); } +WMRHolographicFrame::WMRHolographicFrame() {} + WMRHolographicFrame::~WMRHolographicFrame() = default; std::unique_ptr<WMRHolographicFramePrediction>
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.h b/device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.h index 8a99eac..f59e6d4 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.h +++ b/device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.h
@@ -25,8 +25,12 @@ prediction); virtual ~WMRHolographicFramePrediction(); - std::unique_ptr<WMRTimestamp> Timestamp(); - std::vector<std::unique_ptr<WMRCameraPose>> CameraPoses(); + virtual std::unique_ptr<WMRTimestamp> Timestamp(); + virtual std::vector<std::unique_ptr<WMRCameraPose>> CameraPoses(); + + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRHolographicFramePrediction(); private: Microsoft::WRL::ComPtr< @@ -44,10 +48,14 @@ holographic_frame); virtual ~WMRHolographicFrame(); - std::unique_ptr<WMRHolographicFramePrediction> CurrentPrediction(); - std::unique_ptr<WMRRenderingParameters> TryGetRenderingParameters( + virtual std::unique_ptr<WMRHolographicFramePrediction> CurrentPrediction(); + virtual std::unique_ptr<WMRRenderingParameters> TryGetRenderingParameters( const WMRCameraPose* pose); - bool TryPresentUsingCurrentPrediction(); + virtual bool TryPresentUsingCurrentPrediction(); + + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRHolographicFrame(); private: Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Holographic::IHolographicFrame>
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc b/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc index a4e78d25..1441d553 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc +++ b/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.cc
@@ -14,6 +14,9 @@ #include "base/strings/string_util.h" #include "base/win/core_winrt_util.h" #include "base/win/scoped_hstring.h" +#include "device/vr/windows_mixed_reality/mixed_reality_statics.h" +#include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_frame.h" +#include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_holographic_space.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_holographic_frame.h" using ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice; @@ -25,6 +28,9 @@ namespace device { std::unique_ptr<WMRHolographicSpace> WMRHolographicSpace::CreateForWindow( HWND hwnd) { + if (MixedRealityDeviceStatics::GetLockedTestHook().GetHook()) { + return std::make_unique<MockWMRHolographicSpace>(); + } if (!hwnd) return nullptr; @@ -53,6 +59,8 @@ DCHECK(space_); } +WMRHolographicSpace::WMRHolographicSpace() {} + WMRHolographicSpace::~WMRHolographicSpace() = default; HolographicAdapterId WMRHolographicSpace::PrimaryAdapterId() {
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h b/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h index e4a51d4..d6f385a 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h +++ b/device/vr/windows_mixed_reality/wrappers/wmr_holographic_space.h
@@ -21,13 +21,18 @@ ABI::Windows::Graphics::Holographic::IHolographicSpace> space); virtual ~WMRHolographicSpace(); - ABI::Windows::Graphics::Holographic::HolographicAdapterId PrimaryAdapterId(); - std::unique_ptr<WMRHolographicFrame> TryCreateNextFrame(); - bool TrySetDirect3D11Device( + virtual ABI::Windows::Graphics::Holographic::HolographicAdapterId + PrimaryAdapterId(); + virtual std::unique_ptr<WMRHolographicFrame> TryCreateNextFrame(); + virtual bool TrySetDirect3D11Device( const Microsoft::WRL::ComPtr< ABI::Windows::Graphics::DirectX::Direct3D11::IDirect3DDevice>& device); + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRHolographicSpace(); + private: Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Holographic::IHolographicSpace> space_;
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.cc b/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.cc index a29616c..40ba7c7e 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.cc +++ b/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.cc
@@ -16,6 +16,8 @@ #include "base/strings/string_util.h" #include "base/win/core_winrt_util.h" #include "base/win/scoped_hstring.h" +#include "device/vr/windows_mixed_reality/mixed_reality_statics.h" +#include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_input_manager.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_input_source_state.h" using ABI::Windows::Foundation::ITypedEventHandler; @@ -64,6 +66,9 @@ } std::unique_ptr<WMRInputManager> WMRInputManager::GetForWindow(HWND hwnd) { + if (MixedRealityDeviceStatics::GetLockedTestHook().GetHook()) { + return std::make_unique<MockWMRInputManager>(); + } if (!hwnd) return nullptr; @@ -93,6 +98,8 @@ SubscribeEvents(); } +WMRInputManager::WMRInputManager() {} + WMRInputManager::~WMRInputManager() { UnsubscribeEvents(); }
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h b/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h index be9b0b3..87f32d5e 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h +++ b/device/vr/windows_mixed_reality/wrappers/wmr_input_manager.h
@@ -52,7 +52,7 @@ manager); virtual ~WMRInputManager(); - std::vector<WMRInputSourceState> GetDetectedSourcesAtTimestamp( + virtual std::vector<WMRInputSourceState> GetDetectedSourcesAtTimestamp( Microsoft::WRL::ComPtr<ABI::Windows::Perception::IPerceptionTimestamp> timestamp) const; @@ -62,6 +62,10 @@ std::unique_ptr<InputEventCallbackList::Subscription> AddReleasedCallback( const InputEventCallback& cb); + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRInputManager(); + private: void SubscribeEvents(); void UnsubscribeEvents();
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_origins.cc b/device/vr/windows_mixed_reality/wrappers/wmr_origins.cc index 71c61d4..ab4e5cb 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_origins.cc +++ b/device/vr/windows_mixed_reality/wrappers/wmr_origins.cc
@@ -17,6 +17,8 @@ #include "base/win/core_winrt_util.h" #include "base/win/scoped_co_mem.h" #include "base/win/scoped_hstring.h" +#include "device/vr/windows_mixed_reality/mixed_reality_statics.h" +#include "device/vr/windows_mixed_reality/wrappers/test/mock_wmr_origins.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_logging.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_timestamp.h" @@ -69,6 +71,8 @@ DCHECK(coordinates_); } +WMRCoordinateSystem::WMRCoordinateSystem() {} + WMRCoordinateSystem::~WMRCoordinateSystem() = default; bool WMRCoordinateSystem::TryGetTransformTo(const WMRCoordinateSystem* other, @@ -95,6 +99,9 @@ // WMRStationaryOrigin std::unique_ptr<WMRStationaryOrigin> WMRStationaryOrigin::CreateAtCurrentLocation() { + if (MixedRealityDeviceStatics::GetLockedTestHook().GetHook()) { + return std::make_unique<MockWMRStationaryOrigin>(); + } ComPtr<ISpatialLocator> locator = GetSpatialLocator(); if (!locator) return nullptr; @@ -116,6 +123,8 @@ DCHECK(stationary_origin_); } +WMRStationaryOrigin::WMRStationaryOrigin() {} + WMRStationaryOrigin::~WMRStationaryOrigin() = default; std::unique_ptr<WMRCoordinateSystem> WMRStationaryOrigin::CoordinateSystem() { @@ -128,6 +137,9 @@ // WMRAttachedOrigin std::unique_ptr<WMRAttachedOrigin> WMRAttachedOrigin::CreateAtCurrentLocation() { + if (MixedRealityDeviceStatics::GetLockedTestHook().GetHook()) { + return std::make_unique<MockWMRAttachedOrigin>(); + } ComPtr<ISpatialLocator> locator = GetSpatialLocator(); if (!locator) return nullptr; @@ -148,6 +160,8 @@ DCHECK(attached_origin_); } +WMRAttachedOrigin::WMRAttachedOrigin() {} + WMRAttachedOrigin::~WMRAttachedOrigin() = default; std::unique_ptr<WMRCoordinateSystem> @@ -168,6 +182,8 @@ DCHECK(stage_origin_); } +WMRStageOrigin::WMRStageOrigin() {} + WMRStageOrigin::~WMRStageOrigin() = default; std::unique_ptr<WMRCoordinateSystem> WMRStageOrigin::CoordinateSystem() { @@ -207,6 +223,8 @@ // WMRStageStatics std::unique_ptr<WMRStageStatics> WMRStageStatics::Create() { + if (MixedRealityDeviceStatics::GetLockedTestHook().GetHook()) + return std::make_unique<MockWMRStageStatics>(); ComPtr<ISpatialStageFrameOfReferenceStatics> stage_statics; base::win::ScopedHString spatial_stage_string = base::win::ScopedHString::Create( @@ -230,12 +248,19 @@ DCHECK(SUCCEEDED(hr)); } +WMRStageStatics::WMRStageStatics() {} + WMRStageStatics::~WMRStageStatics() { + DCHECK(dispose_called_); +} + +void WMRStageStatics::Dispose() { if (stage_changed_token_.value != 0) { HRESULT hr = stage_statics_->remove_CurrentChanged(stage_changed_token_); stage_changed_token_.value = 0; DCHECK(SUCCEEDED(hr)); } + dispose_called_ = true; } std::unique_ptr<WMRStageOrigin> WMRStageStatics::CurrentStage() {
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_origins.h b/device/vr/windows_mixed_reality/wrappers/wmr_origins.h index b7dedb9..1c64489 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_origins.h +++ b/device/vr/windows_mixed_reality/wrappers/wmr_origins.h
@@ -24,13 +24,17 @@ coordinates); virtual ~WMRCoordinateSystem(); - bool TryGetTransformTo( + virtual bool TryGetTransformTo( const WMRCoordinateSystem* other, ABI::Windows::Foundation::Numerics::Matrix4x4* this_to_other); ABI::Windows::Perception::Spatial::ISpatialCoordinateSystem* GetRawPtr() const; + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRCoordinateSystem(); + private: Microsoft::WRL::ComPtr< ABI::Windows::Perception::Spatial::ISpatialCoordinateSystem> @@ -48,7 +52,11 @@ stationary_origin); virtual ~WMRStationaryOrigin(); - std::unique_ptr<WMRCoordinateSystem> CoordinateSystem(); + virtual std::unique_ptr<WMRCoordinateSystem> CoordinateSystem(); + + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRStationaryOrigin(); private: Microsoft::WRL::ComPtr< @@ -67,9 +75,13 @@ attached_origin); virtual ~WMRAttachedOrigin(); - std::unique_ptr<WMRCoordinateSystem> TryGetCoordinatesAtTimestamp( + virtual std::unique_ptr<WMRCoordinateSystem> TryGetCoordinatesAtTimestamp( const WMRTimestamp* timestamp); + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRAttachedOrigin(); + private: Microsoft::WRL::ComPtr<ABI::Windows::Perception::Spatial:: ISpatialLocatorAttachedFrameOfReference> @@ -87,12 +99,17 @@ stage_origin); virtual ~WMRStageOrigin(); - std::unique_ptr<WMRCoordinateSystem> CoordinateSystem(); - ABI::Windows::Perception::Spatial::SpatialMovementRange MovementRange(); + virtual std::unique_ptr<WMRCoordinateSystem> CoordinateSystem(); + virtual ABI::Windows::Perception::Spatial::SpatialMovementRange + MovementRange(); // This will return an empty array if no bounds are set. - std::vector<ABI::Windows::Foundation::Numerics::Vector3> GetMovementBounds( - const WMRCoordinateSystem* coordinates); + virtual std::vector<ABI::Windows::Foundation::Numerics::Vector3> + GetMovementBounds(const WMRCoordinateSystem* coordinates); + + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRStageOrigin(); private: Microsoft::WRL::ComPtr< @@ -111,11 +128,18 @@ stage_statics); virtual ~WMRStageStatics(); - std::unique_ptr<WMRStageOrigin> CurrentStage(); + virtual std::unique_ptr<WMRStageOrigin> CurrentStage(); std::unique_ptr<base::CallbackList<void()>::Subscription> AddStageChangedCallback(const base::RepeatingCallback<void()>& cb); + virtual void Dispose(); + + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRStageStatics(); + bool dispose_called_ = false; + private: HRESULT OnCurrentChanged(IInspectable* sender, IInspectable* args); Microsoft::WRL::ComPtr<
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_rendering.cc b/device/vr/windows_mixed_reality/wrappers/wmr_rendering.cc index 8bd8bd6f..d39ace2 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_rendering.cc +++ b/device/vr/windows_mixed_reality/wrappers/wmr_rendering.cc
@@ -10,7 +10,6 @@ #include <memory> #include <vector> -#include "base/logging.h" #include "device/vr/windows/d3d11_texture_helper.h" #include "device/vr/windows_mixed_reality/wrappers/wmr_origins.h" @@ -31,6 +30,8 @@ DCHECK(camera_); } +WMRCamera::WMRCamera() {} + WMRCamera::~WMRCamera() = default; WF::Size WMRCamera::RenderTargetSize() { @@ -53,6 +54,8 @@ DCHECK(pose_); } +WMRCameraPose::WMRCameraPose() {} + WMRCameraPose::~WMRCameraPose() = default; WF::Rect WMRCameraPose::Viewport() { @@ -98,6 +101,8 @@ DCHECK(rendering_params_); } +WMRRenderingParameters::WMRRenderingParameters() {} + WMRRenderingParameters::~WMRRenderingParameters() = default; ComPtr<ID3D11Texture2D> WMRRenderingParameters::TryGetBackbufferAsTexture2D() {
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_rendering.h b/device/vr/windows_mixed_reality/wrappers/wmr_rendering.h index c295077..803c59e 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_rendering.h +++ b/device/vr/windows_mixed_reality/wrappers/wmr_rendering.h
@@ -23,8 +23,12 @@ ABI::Windows::Graphics::Holographic::IHolographicCamera> camera); virtual ~WMRCamera(); - ABI::Windows::Foundation::Size RenderTargetSize(); - bool IsStereo(); + virtual ABI::Windows::Foundation::Size RenderTargetSize(); + virtual bool IsStereo(); + + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRCamera(); private: Microsoft::WRL::ComPtr< @@ -41,17 +45,21 @@ ABI::Windows::Graphics::Holographic::IHolographicCameraPose> pose); virtual ~WMRCameraPose(); - ABI::Windows::Foundation::Rect Viewport(); - std::unique_ptr<WMRCamera> HolographicCamera(); - ABI::Windows::Graphics::Holographic::HolographicStereoTransform + virtual ABI::Windows::Foundation::Rect Viewport(); + virtual std::unique_ptr<WMRCamera> HolographicCamera(); + virtual ABI::Windows::Graphics::Holographic::HolographicStereoTransform ProjectionTransform(); - bool TryGetViewTransform( + virtual bool TryGetViewTransform( const WMRCoordinateSystem* origin, ABI::Windows::Graphics::Holographic::HolographicStereoTransform* transform); ABI::Windows::Graphics::Holographic::IHolographicCameraPose* GetRawPtr() const; + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRCameraPose(); + private: Microsoft::WRL::ComPtr< ABI::Windows::Graphics::Holographic::IHolographicCameraPose> @@ -68,7 +76,11 @@ rendering_params); virtual ~WMRRenderingParameters(); - Microsoft::WRL::ComPtr<ID3D11Texture2D> TryGetBackbufferAsTexture2D(); + virtual Microsoft::WRL::ComPtr<ID3D11Texture2D> TryGetBackbufferAsTexture2D(); + + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRRenderingParameters(); private: Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Holographic::
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_timestamp.cc b/device/vr/windows_mixed_reality/wrappers/wmr_timestamp.cc index 0508ab94..8b74e30 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_timestamp.cc +++ b/device/vr/windows_mixed_reality/wrappers/wmr_timestamp.cc
@@ -19,6 +19,8 @@ DCHECK(timestamp_); } +WMRTimestamp::WMRTimestamp() {} + WMRTimestamp::~WMRTimestamp() = default; DateTime WMRTimestamp::TargetTime() const {
diff --git a/device/vr/windows_mixed_reality/wrappers/wmr_timestamp.h b/device/vr/windows_mixed_reality/wrappers/wmr_timestamp.h index 1bd36d0c..8394406 100644 --- a/device/vr/windows_mixed_reality/wrappers/wmr_timestamp.h +++ b/device/vr/windows_mixed_reality/wrappers/wmr_timestamp.h
@@ -17,10 +17,14 @@ timestamp); virtual ~WMRTimestamp(); - ABI::Windows::Foundation::DateTime TargetTime() const; - ABI::Windows::Foundation::TimeSpan PredictionAmount() const; + virtual ABI::Windows::Foundation::DateTime TargetTime() const; + virtual ABI::Windows::Foundation::TimeSpan PredictionAmount() const; ABI::Windows::Perception::IPerceptionTimestamp* GetRawPtr() const; + protected: + // Necessary so subclasses don't call the explicit constructor. + WMRTimestamp(); + private: Microsoft::WRL::ComPtr<ABI::Windows::Perception::IPerceptionTimestamp> timestamp_;
diff --git a/extensions/renderer/extension_frame_helper.cc b/extensions/renderer/extension_frame_helper.cc index 4508021..4fc06c4 100644 --- a/extensions/renderer/extension_frame_helper.cc +++ b/extensions/renderer/extension_frame_helper.cc
@@ -340,6 +340,16 @@ v8::Local<v8::Context> context = render_frame()->GetWebFrame()->MainWorldScriptContext(); v8::Context::Scope context_scope(context); + // Normally we would use Document's URL for all kinds of checks, e.g. whether + // to inject a content script. However, when committing a navigation, we + // should use the URL of a Document being committed instead. This URL is + // accessible through WebDocumentLoader::GetURL(). + // The scope below temporary maps a frame to a document loader, so that places + // which retrieve URL can use the right one. Ideally, we would plumb the + // correct URL (or maybe WebDocumentLoader) through the callchain, but there + // are many callers which will have to pass nullptr. + ScriptContext::ScopedFrameDocumentLoader scoped_document_loader( + render_frame()->GetWebFrame(), document_loader); extension_dispatcher_->DidCreateScriptContext(render_frame()->GetWebFrame(), context, kMainWorldId); // TODO(devlin): Add constants for main world id, no extension group.
diff --git a/extensions/renderer/script_context.cc b/extensions/renderer/script_context.cc index 9e87412..778a6e1 100644 --- a/extensions/renderer/script_context.cc +++ b/extensions/renderer/script_context.cc
@@ -67,8 +67,48 @@ return ascii_value.empty() ? dflt : ascii_value; } +using FrameToDocumentLoader = + base::flat_map<blink::WebLocalFrame*, blink::WebDocumentLoader*>; + +FrameToDocumentLoader& FrameDocumentLoaderMap() { + static base::NoDestructor<FrameToDocumentLoader> map; + return *map; +} + +blink::WebDocumentLoader* CurrentDocumentLoader( + const blink::WebLocalFrame* frame) { + auto& map = FrameDocumentLoaderMap(); + auto it = map.find(frame); + blink::WebDocumentLoader* loader = frame->GetDocumentLoader(); + if (it != map.end()) { + loader = it->second; + // This and next are temporary DCHECKs which verify that + // document loader we have in the map is the same as + // (soon to be removed) GetProvisionalDocumentLoader. + DCHECK_EQ(loader, frame->GetProvisionalDocumentLoader()); + } else { + DCHECK(!frame->GetProvisionalDocumentLoader()); + } + return loader; +} + } // namespace +ScriptContext::ScopedFrameDocumentLoader::ScopedFrameDocumentLoader( + blink::WebLocalFrame* frame, + blink::WebDocumentLoader* document_loader) + : frame_(frame), document_loader_(document_loader) { + auto& map = FrameDocumentLoaderMap(); + DCHECK(map.find(frame_) == map.end()); + map[frame_] = document_loader_; +} + +ScriptContext::ScopedFrameDocumentLoader::~ScopedFrameDocumentLoader() { + auto& map = FrameDocumentLoaderMap(); + DCHECK_EQ(document_loader_, map.find(frame_)->second); + map.erase(frame_); +} + ScriptContext::ScriptContext(const v8::Local<v8::Context>& v8_context, blink::WebLocalFrame* web_frame, const Extension* extension, @@ -264,10 +304,7 @@ // changes to match the parent document after Gmail document.writes into // it to create the editor. // http://code.google.com/p/chromium/issues/detail?id=86742 - blink::WebDocumentLoader* document_loader = - frame->GetProvisionalDocumentLoader() - ? frame->GetProvisionalDocumentLoader() - : frame->GetDocumentLoader(); + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame); return document_loader ? GURL(document_loader->GetUrl()) : GURL(); } @@ -276,10 +313,7 @@ const blink::WebLocalFrame* frame) { const blink::WebURL& weburl = frame->GetDocument().Url(); if (weburl.IsEmpty()) { - blink::WebDocumentLoader* document_loader = - frame->GetProvisionalDocumentLoader() - ? frame->GetProvisionalDocumentLoader() - : frame->GetDocumentLoader(); + blink::WebDocumentLoader* document_loader = CurrentDocumentLoader(frame); if (document_loader && frame->GetSecurityOrigin().CanAccess( blink::WebSecurityOrigin::Create(document_loader->GetUrl()))) {
diff --git a/extensions/renderer/script_context.h b/extensions/renderer/script_context.h index f714d8d..e6d98085 100644 --- a/extensions/renderer/script_context.h +++ b/extensions/renderer/script_context.h
@@ -24,6 +24,7 @@ #include "v8/include/v8.h" namespace blink { +class WebDocumentLoader; class WebLocalFrame; } @@ -174,6 +175,21 @@ bool IsAnyFeatureAvailableToContext(const extensions::Feature& api, CheckAliasStatus check_alias); + // Scope which maps a frame to a document loader. This is used by various + // static methods below, which need to account for "just about to load" + // document when retrieving URL. + class ScopedFrameDocumentLoader { + public: + ScopedFrameDocumentLoader(blink::WebLocalFrame* frame, + blink::WebDocumentLoader* document_loader); + ~ScopedFrameDocumentLoader(); + + private: + blink::WebLocalFrame* frame_; + blink::WebDocumentLoader* document_loader_; + DISALLOW_COPY_AND_ASSIGN(ScopedFrameDocumentLoader); + }; + // Utility to get the URL we will match against for a frame. If the frame has // committed, this is the commited URL. Otherwise it is the provisional URL. // The returned URL may be invalid.
diff --git a/fuchsia/base/test_navigation_listener.cc b/fuchsia/base/test_navigation_listener.cc index d86f1a36..f602a3c 100644 --- a/fuchsia/base/test_navigation_listener.cc +++ b/fuchsia/base/test_navigation_listener.cc
@@ -11,27 +11,27 @@ #include "base/bind.h" #include "base/fuchsia/fuchsia_logging.h" #include "base/run_loop.h" +#include "base/strings/stringprintf.h" #include "fuchsia/base/mem_buffer_util.h" namespace cr_fuchsia { namespace { void QuitRunLoopAndRunCallback( - base::RunLoop* run_loop, + base::OnceClosure quit_run_loop_closure, TestNavigationListener::BeforeAckCallback before_ack_callback, const fuchsia::web::NavigationState& change, fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback ack_callback) { - run_loop->Quit(); + std::move(quit_run_loop_closure).Run(); before_ack_callback.Run(change, std::move(ack_callback)); } } // namespace TestNavigationListener::TestNavigationListener() { - before_ack_ = base::BindRepeating( - [](const fuchsia::web::NavigationState&, - OnNavigationStateChangedCallback callback) { callback(); }); + // Set up the default acknowledgement handling behavior. + SetBeforeAckHook({}); } TestNavigationListener::~TestNavigationListener() = default; @@ -44,9 +44,8 @@ while (!AllFieldsMatch(expected_state)) { base::RunLoop run_loop; base::AutoReset<BeforeAckCallback> callback_setter( - &before_ack_, - base::BindRepeating(&QuitRunLoopAndRunCallback, - base::Unretained(&run_loop), before_ack_)); + &before_ack_, base::BindRepeating(&QuitRunLoopAndRunCallback, + run_loop.QuitClosure(), before_ack_)); run_loop.Run(); } } @@ -54,6 +53,7 @@ void TestNavigationListener::RunUntilUrlEquals(const GURL& expected_url) { fuchsia::web::NavigationState state; state.set_url(expected_url.spec()); + state.set_is_main_document_loaded(true); RunUntilNavigationStateMatches(state); } @@ -93,45 +93,83 @@ current_state_.set_can_go_back(change.can_go_back()); if (change.has_can_go_forward()) current_state_.set_can_go_forward(change.can_go_forward()); + if (change.has_is_main_document_loaded()) + current_state_.set_is_main_document_loaded( + change.is_main_document_loaded()); + + if (VLOG_IS_ON(1)) { + std::string state_string; + state_string.reserve(100); + + if (current_state_.has_url()) + state_string.append( + base::StringPrintf(" url=%s ", current_state_.url().c_str())); + + if (current_state_.has_title()) + state_string.append( + base::StringPrintf(" title='%s' ", current_state_.title().c_str())); + + if (current_state_.has_can_go_back()) + state_string.append( + base::StringPrintf(" can_go_back=%d ", current_state_.can_go_back())); + + if (current_state_.has_can_go_forward()) + state_string.append(base::StringPrintf(" can_go_forward=%d ", + current_state_.can_go_forward())); + + if (current_state_.has_is_main_document_loaded()) + state_string.append( + base::StringPrintf(" is_main_document_loaded=%d ", + current_state_.is_main_document_loaded())); + VLOG(1) << "Navigation state changed: " << state_string; + } // Signal readiness for the next navigation event. before_ack_.Run(change, std::move(callback)); } void TestNavigationListener::SetBeforeAckHook(BeforeAckCallback send_ack_cb) { - DCHECK(send_ack_cb); - before_ack_ = send_ack_cb; + if (send_ack_cb) { + before_ack_ = send_ack_cb; + } else { + before_ack_ = base::BindRepeating( + [](const fuchsia::web::NavigationState&, + OnNavigationStateChangedCallback callback) { callback(); }); + } } bool TestNavigationListener::AllFieldsMatch( const fuchsia::web::NavigationState& expected) { - bool all_equal = true; - - if (expected.has_url()) { - if (!current_state_.has_url() || expected.url() != current_state_.url()) { - all_equal = false; - } - } - if (expected.has_title()) { - if (!current_state_.has_title() || - expected.title() != current_state_.title()) { - all_equal = false; - } - } - if (expected.has_can_go_back()) { - if (!current_state_.has_can_go_back() || - expected.can_go_back() != current_state_.can_go_back()) { - all_equal = false; - } - } - if (expected.has_can_go_forward()) { - if (!current_state_.has_can_go_forward() || - expected.can_go_forward() != current_state_.can_go_forward()) { - all_equal = false; - } + if (expected.has_url() && + (!current_state_.has_url() || expected.url() != current_state_.url())) { + return false; } - return all_equal; + if (expected.has_title() && (!current_state_.has_title() || + expected.title() != current_state_.title())) { + return false; + } + + if (expected.has_can_go_forward() && + (!current_state_.has_can_go_forward() || + expected.can_go_forward() != current_state_.can_go_forward())) { + return false; + } + + if (expected.has_can_go_back() && + (!current_state_.has_can_go_back() || + expected.can_go_back() != current_state_.can_go_back())) { + return false; + } + + if (expected.has_is_main_document_loaded() && + (!current_state_.has_is_main_document_loaded() || + expected.is_main_document_loaded() != + current_state_.is_main_document_loaded())) { + return false; + } + + return true; } } // namespace cr_fuchsia
diff --git a/fuchsia/base/test_navigation_listener.h b/fuchsia/base/test_navigation_listener.h index 9087f3d..74d6f16cbe 100644 --- a/fuchsia/base/test_navigation_listener.h +++ b/fuchsia/base/test_navigation_listener.h
@@ -49,6 +49,8 @@ // Register a callback which intercepts the execution of the event // acknowledgement callback. |before_ack| takes ownership of the // acknowledgement callback and the responsibility for executing it. + // The default behavior can be restored by providing an unbound callback for + // |before_ack|. void SetBeforeAckHook(BeforeAckCallback before_ack); private:
diff --git a/fuchsia/engine/browser/frame_impl.cc b/fuchsia/engine/browser/frame_impl.cc index 842a69a7..61e3f2b0 100644 --- a/fuchsia/engine/browser/frame_impl.cc +++ b/fuchsia/engine/browser/frame_impl.cc
@@ -77,29 +77,30 @@ DISALLOW_COPY_AND_ASSIGN(LayoutManagerImpl); }; -fuchsia::web::NavigationState ConvertContentNavigationEntry( +void UpdateNavigationStateFromNavigationEntry( content::NavigationEntry* entry, - content::WebContents* web_contents) { + content::WebContents* web_contents, + fuchsia::web::NavigationState* navigation_state) { DCHECK(entry); + DCHECK(web_contents); + DCHECK(navigation_state); - fuchsia::web::NavigationState converted; - converted.set_title(base::UTF16ToUTF8(entry->GetTitleForDisplay())); - converted.set_url(entry->GetURL().spec()); + navigation_state->set_title(base::UTF16ToUTF8(entry->GetTitleForDisplay())); + navigation_state->set_url(entry->GetURL().spec()); switch (entry->GetPageType()) { case content::PageType::PAGE_TYPE_NORMAL: case content::PageType::PAGE_TYPE_INTERSTITIAL: - converted.set_page_type(fuchsia::web::PageType::NORMAL); + navigation_state->set_page_type(fuchsia::web::PageType::NORMAL); break; case content::PageType::PAGE_TYPE_ERROR: - converted.set_page_type(fuchsia::web::PageType::ERROR); + navigation_state->set_page_type(fuchsia::web::PageType::ERROR); break; } - converted.set_can_go_back(web_contents->GetController().CanGoBack()); - converted.set_can_go_forward(web_contents->GetController().CanGoForward()); - - return converted; + navigation_state->set_can_go_back(web_contents->GetController().CanGoBack()); + navigation_state->set_can_go_forward( + web_contents->GetController().CanGoForward()); } class FrameFocusRules : public wm::BaseFocusRules { @@ -195,8 +196,8 @@ ContextImpl* context, fidl::InterfaceRequest<fuchsia::web::Frame> frame_request) : web_contents_(std::move(web_contents)), - log_level_(kLogSeverityNone), context_(context), + log_level_(kLogSeverityNone), binding_(this, std::move(frame_request)), weak_factory_(this) { web_contents_->SetDelegate(this); @@ -413,9 +414,8 @@ fidl::InterfaceHandle<fuchsia::web::NavigationEventListener> listener) { // Reset the event buffer state. waiting_for_navigation_event_ack_ = false; - cached_navigation_state_ = {}; + previous_navigation_state_ = {}; pending_navigation_event_ = {}; - pending_navigation_event_is_dirty_ = false; if (listener) { navigation_listener_.Bind(std::move(listener)); @@ -467,12 +467,17 @@ } } -void FrameImpl::OnNavigationEntryChanged(content::NavigationEntry* entry) { - fuchsia::web::NavigationState entry_converted = - ConvertContentNavigationEntry(entry, web_contents_.get()); - pending_navigation_event_is_dirty_ |= DiffNavigationEntries( - cached_navigation_state_, entry_converted, &pending_navigation_event_); - cached_navigation_state_ = std::move(entry_converted); +void FrameImpl::OnNavigationEntryChanged() { + fuchsia::web::NavigationState new_state; + new_state.set_is_main_document_loaded(is_main_document_loaded_); + UpdateNavigationStateFromNavigationEntry( + web_contents_->GetController().GetVisibleEntry(), web_contents_.get(), + &new_state); + + DiffNavigationEntries(previous_navigation_state_, new_state, + &pending_navigation_event_); + previous_navigation_state_ = std::move(new_state); + base::ThreadTaskRunnerHandle::Get()->PostTask( FROM_HERE, base::BindOnce(&FrameImpl::MaybeSendNavigationEvent, weak_factory_.GetWeakPtr())); @@ -482,12 +487,11 @@ if (!navigation_listener_) return; - if (!pending_navigation_event_is_dirty_ || + if (pending_navigation_event_.IsEmpty() || waiting_for_navigation_event_ack_) { return; } - pending_navigation_event_is_dirty_ = false; waiting_for_navigation_event_ack_ = true; // Send the event to the observer and, upon acknowledgement, revisit this @@ -582,7 +586,10 @@ return; } - callback(ConvertContentNavigationEntry(entry, web_contents_.get())); + fuchsia::web::NavigationState state; + state.set_is_main_document_loaded(is_main_document_loaded_); + UpdateNavigationStateFromNavigationEntry(entry, web_contents_.get(), &state); + callback(std::move(state)); } bool FrameImpl::ShouldCreateWebContents( @@ -647,15 +654,6 @@ return true; } -void FrameImpl::DidFinishLoad(content::RenderFrameHost* render_frame_host, - const GURL& validated_url) { - if (web_contents_->GetMainFrame() != render_frame_host) { - return; - } - - OnNavigationEntryChanged(web_contents_->GetController().GetVisibleEntry()); -} - void FrameImpl::ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) { if (before_load_scripts_.empty()) @@ -683,48 +681,72 @@ } void FrameImpl::TitleWasSet(content::NavigationEntry* entry) { - OnNavigationEntryChanged(entry); + // The title was changed after the document was loaded. + OnNavigationEntryChanged(); } -bool DiffNavigationEntries(const fuchsia::web::NavigationState& old_entry, +void FrameImpl::DocumentAvailableInMainFrame() { + // The main document is loaded, but not necessarily all the subresources. Some + // fields like "title" will change here. + + OnNavigationEntryChanged(); +} + +void FrameImpl::DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) { + // The document and its statically-declared subresources are loaded. + + is_main_document_loaded_ = true; + OnNavigationEntryChanged(); +} + +void FrameImpl::DidStartNavigation( + content::NavigationHandle* navigation_handle) { + if (navigation_handle->IsSameDocument()) + return; + + is_main_document_loaded_ = false; + OnNavigationEntryChanged(); +} + +void DiffNavigationEntries(const fuchsia::web::NavigationState& old_entry, const fuchsia::web::NavigationState& new_entry, fuchsia::web::NavigationState* difference) { DCHECK(difference); - bool is_changed = false; - DCHECK(new_entry.has_title()); if (!old_entry.has_title() || (new_entry.title() != old_entry.title())) { - is_changed = true; difference->set_title(new_entry.title()); } DCHECK(new_entry.has_url()); if (!old_entry.has_url() || (new_entry.url() != old_entry.url())) { - is_changed = true; difference->set_url(new_entry.url()); } DCHECK(new_entry.has_page_type()); if (!old_entry.has_page_type() || (new_entry.page_type() != old_entry.page_type())) { - is_changed = true; difference->set_page_type(new_entry.page_type()); } DCHECK(new_entry.has_can_go_back()); if (!old_entry.has_can_go_back() || old_entry.can_go_back() != new_entry.can_go_back()) { - is_changed = true; difference->set_can_go_back(new_entry.can_go_back()); } DCHECK(new_entry.has_can_go_forward()); if (!old_entry.has_can_go_forward() || old_entry.can_go_forward() != new_entry.can_go_forward()) { - is_changed = true; difference->set_can_go_forward(new_entry.can_go_forward()); } - return is_changed; + DCHECK(new_entry.has_is_main_document_loaded()); + if (!old_entry.has_is_main_document_loaded() || + old_entry.is_main_document_loaded() != + new_entry.is_main_document_loaded()) { + difference->set_is_main_document_loaded( + new_entry.is_main_document_loaded()); + } }
diff --git a/fuchsia/engine/browser/frame_impl.h b/fuchsia/engine/browser/frame_impl.h index 1d9e87e..ecc5cc15 100644 --- a/fuchsia/engine/browser/frame_impl.h +++ b/fuchsia/engine/browser/frame_impl.h
@@ -114,7 +114,7 @@ // Processes the most recent changes to the browser's navigation state and // triggers the publishing of change events. - void OnNavigationEntryChanged(content::NavigationEntry* entry); + void OnNavigationEntryChanged(); // Sends |pending_navigation_event_| to the observer if there are any changes // to be reported. @@ -151,27 +151,30 @@ const base::string16& source_id) override; // content::WebContentsObserver implementation. - void DidFinishLoad(content::RenderFrameHost* render_frame_host, - const GURL& validated_url) override; void ReadyToCommitNavigation( content::NavigationHandle* navigation_handle) override; - void TitleWasSet(content::NavigationEntry* entry) override; + void TitleWasSet(content::NavigationEntry*) override; + void DocumentAvailableInMainFrame() override; + void DidFinishLoad(content::RenderFrameHost* render_frame_host, + const GURL& validated_url) override; + void DidStartNavigation( + content::NavigationHandle* navigation_handle) override; std::unique_ptr<aura::WindowTreeHost> window_tree_host_; - std::unique_ptr<content::WebContents> web_contents_; + const std::unique_ptr<content::WebContents> web_contents_; std::unique_ptr<wm::FocusController> focus_controller_; + ContextImpl* const context_; DiscardingEventFilter discarding_event_filter_; fuchsia::web::NavigationEventListenerPtr navigation_listener_; - fuchsia::web::NavigationState cached_navigation_state_; + fuchsia::web::NavigationState previous_navigation_state_; fuchsia::web::NavigationState pending_navigation_event_; bool waiting_for_navigation_event_ack_; - bool pending_navigation_event_is_dirty_; logging::LogSeverity log_level_; std::map<uint64_t, OriginScopedScript> before_load_scripts_; std::vector<uint64_t> before_load_scripts_order_; - ContextImpl* context_ = nullptr; base::RepeatingCallback<void(base::StringPiece)> console_log_message_hook_; + bool is_main_document_loaded_ = false; fidl::Binding<fuchsia::web::Frame> binding_; fidl::BindingSet<fuchsia::web::NavigationController> controller_bindings_; @@ -181,11 +184,11 @@ DISALLOW_COPY_AND_ASSIGN(FrameImpl); }; -// Computes the observable differences between |old_entry| and |new_entry|. -// Returns true if they are different, |false| if their observable fields are -// identical. -WEB_ENGINE_EXPORT bool DiffNavigationEntries( +// Computes the differences from old_entry to new_entry and stores the result in +// |difference|. +WEB_ENGINE_EXPORT void DiffNavigationEntries( const fuchsia::web::NavigationState& old_entry, const fuchsia::web::NavigationState& new_entry, fuchsia::web::NavigationState* difference); + #endif // FUCHSIA_ENGINE_BROWSER_FRAME_IMPL_H_
diff --git a/fuchsia/engine/browser/frame_impl_browsertest.cc b/fuchsia/engine/browser/frame_impl_browsertest.cc index 234285b1..9ce2b00f 100644 --- a/fuchsia/engine/browser/frame_impl_browsertest.cc +++ b/fuchsia/engine/browser/frame_impl_browsertest.cc
@@ -26,6 +26,8 @@ #include "fuchsia/engine/test/web_engine_browser_test.h" #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" +#include "net/test/embedded_test_server/http_response.h" +#include "net/test/embedded_test_server/request_handler_util.h" #include "net/url_request/url_request_context.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" @@ -277,6 +279,167 @@ base::RunLoop().RunUntilIdle(); } +// An HTTP response stream whose response payload can be sent as "chunks" +// with indeterminate-length pauses in between. +class ChunkedHttpTransaction { + public: + ChunkedHttpTransaction(const net::test_server::SendBytesCallback& send, + const net::test_server::SendCompleteCallback& done) + : io_task_runner_(base::ThreadTaskRunnerHandle::Get()), + send_callback_(send), + done_callback_(done) { + DCHECK(!current_instance_); + DCHECK(send_callback_); + DCHECK(done_callback_); + + current_instance_ = this; + } + + static ChunkedHttpTransaction* current() { + DCHECK(current_instance_); + return current_instance_; + } + + void Close() { + EnsureSendCompleted(); + io_task_runner_->PostTask(FROM_HERE, done_callback_); + delete this; + } + + void EnsureSendCompleted() { + if (send_callback_) + return; + + base::RunLoop run_loop; + send_chunk_complete_callback_ = run_loop.QuitClosure(); + run_loop.Run(); + DCHECK(send_callback_); + } + + void SendChunk(std::string chunk) { + EnsureSendCompleted(); + + // Temporarily nullify |send_callback_| while the operation is inflight, to + // guard against concurrent sends. The callback will be restored by + // SendChunkComplete(). + net::test_server::SendBytesCallback inflight_send_callback = send_callback_; + send_callback_ = {}; + + io_task_runner_->PostTask( + FROM_HERE, + base::BindOnce(inflight_send_callback, chunk, + base::BindRepeating( + &ChunkedHttpTransaction::SendChunkCompleteOnIoThread, + base::Unretained(this), inflight_send_callback, + base::ThreadTaskRunnerHandle::Get()))); + } + + private: + static ChunkedHttpTransaction* current_instance_; + + ~ChunkedHttpTransaction() { current_instance_ = nullptr; } + + void SendChunkCompleteOnIoThread( + net::test_server::SendBytesCallback send_callback, + scoped_refptr<base::TaskRunner> ui_thread_task_runner) { + ui_thread_task_runner->PostTask( + FROM_HERE, + base::BindOnce(&ChunkedHttpTransaction::SendChunkCompleteOnUiThread, + base::Unretained(this), send_callback)); + } + + void SendChunkCompleteOnUiThread( + net::test_server::SendBytesCallback send_callback) { + send_callback_ = send_callback; + if (send_chunk_complete_callback_) + std::move(send_chunk_complete_callback_).Run(); + } + + scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_; + + // Set by callers to SendChunk() waiting for the previous chunk to complete. + base::OnceClosure send_chunk_complete_callback_; + + // Callbacks are affine with |io_task_runner_|. + net::test_server::SendBytesCallback send_callback_; + net::test_server::SendCompleteCallback done_callback_; + + DISALLOW_COPY_AND_ASSIGN(ChunkedHttpTransaction); +}; + +ChunkedHttpTransaction* ChunkedHttpTransaction::current_instance_ = nullptr; + +class ChunkedHttpTransactionFactory : public net::test_server::HttpResponse { + public: + ChunkedHttpTransactionFactory() = default; + ~ChunkedHttpTransactionFactory() override = default; + + void SetOnResponseCreatedCallback(base::OnceClosure on_response_created) { + on_response_created_ = std::move(on_response_created); + } + + // net::test_server::HttpResponse implementation. + void SendResponse( + const net::test_server::SendBytesCallback& send, + const net::test_server::SendCompleteCallback& done) override { + // The ChunkedHttpTransaction manages its own lifetime. + new ChunkedHttpTransaction(send, done); + + if (on_response_created_) + std::move(on_response_created_).Run(); + } + + private: + base::OnceClosure on_response_created_; + + DISALLOW_COPY_AND_ASSIGN(ChunkedHttpTransactionFactory); +}; + +IN_PROC_BROWSER_TEST_F(FrameImplTest, NavigationEventDuringPendingLoad) { + fuchsia::web::FramePtr frame = CreateFrame(); + fuchsia::web::NavigationControllerPtr controller; + frame->GetNavigationController(controller.NewRequest()); + ChunkedHttpTransactionFactory* factory = new ChunkedHttpTransactionFactory; + base::RunLoop transaction_created_run_loop; + factory->SetOnResponseCreatedCallback( + transaction_created_run_loop.QuitClosure()); + embedded_test_server()->RegisterRequestHandler(base::BindRepeating( + &net::test_server::HandlePrefixedRequest, "/pausable", + base::BindRepeating( + [](std::unique_ptr<ChunkedHttpTransactionFactory> out_factory, + const net::test_server::HttpRequest&) + -> std::unique_ptr<net::test_server::HttpResponse> { + return out_factory; + }, + base::Passed(base::WrapUnique(factory))))); + + ASSERT_TRUE(embedded_test_server()->Start()); + GURL hung_url(embedded_test_server()->GetURL("/pausable")); + EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( + controller.get(), fuchsia::web::LoadUrlParams(), hung_url.spec())); + fuchsia::web::NavigationState state_change; + state_change.set_url(hung_url.spec()); + state_change.set_is_main_document_loaded(false); + transaction_created_run_loop.Run(); + + ChunkedHttpTransaction* transaction = ChunkedHttpTransaction::current(); + transaction->SendChunk( + "HTTP/1.0 200 OK\r\n" + "Host: localhost\r\n" + "Content-Type: text/html\r\n\r\n" + "<html><head><title>initial load</title>"); + state_change.set_title("initial load"); + state_change.set_is_main_document_loaded(false); + navigation_listener_.RunUntilNavigationStateMatches(state_change); + + transaction->SendChunk( + "<script>document.title='final load';</script><body></body>"); + transaction->Close(); + state_change.set_title("final load"); + state_change.set_is_main_document_loaded(true); + navigation_listener_.RunUntilNavigationStateMatches(state_change); +} + IN_PROC_BROWSER_TEST_F(FrameImplTest, ReloadFrame) { fuchsia::web::FramePtr frame = CreateFrame(); fuchsia::web::NavigationControllerPtr controller; @@ -817,18 +980,19 @@ // Expect an navigation event here, but deliberately postpone acknowledgement // until the end of the test. - base::RunLoop captured_ack_run_loop; OnNavigationStateChangedCallback captured_ack_cb; navigation_listener_.SetBeforeAckHook(base::BindRepeating( [](OnNavigationStateChangedCallback* dest_cb, - const fuchsia::web::NavigationState&, + const fuchsia::web::NavigationState& state, OnNavigationStateChangedCallback cb) { *dest_cb = std::move(cb); }, base::Unretained(&captured_ack_cb))); - EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( controller.get(), fuchsia::web::LoadUrlParams(), title1.spec())); - navigation_listener_.RunUntilUrlAndTitleEquals(title1, kPage1Title); + fuchsia::web::NavigationState expected_state; + expected_state.set_url(title1.spec()); + navigation_listener_.RunUntilNavigationStateMatches(expected_state); EXPECT_TRUE(captured_ack_cb); + navigation_listener_.SetBeforeAckHook({}); // Navigate to a second page. {
diff --git a/fuchsia/engine/browser/frame_impl_unittest.cc b/fuchsia/engine/browser/frame_impl_unittest.cc index a8a4098..f97facd 100644 --- a/fuchsia/engine/browser/frame_impl_unittest.cc +++ b/fuchsia/engine/browser/frame_impl_unittest.cc
@@ -18,7 +18,8 @@ base::StringPiece title, fuchsia::web::PageType page_type, bool can_go_back, - bool can_go_forward) { + bool can_go_forward, + bool is_main_document_loaded) { NavigationState navigation_state; navigation_state.set_url(url.spec()); @@ -26,6 +27,7 @@ navigation_state.set_page_type(fuchsia::web::PageType(page_type)); navigation_state.set_can_go_back(can_go_back); navigation_state.set_can_go_forward(can_go_forward); + navigation_state.set_is_main_document_loaded(is_main_document_loaded); return navigation_state; } @@ -37,22 +39,23 @@ TEST(FrameImplUnitTest, DiffNavigationEntriesNoChange) { fuchsia::web::NavigationState difference; NavigationState state = CreateNavigationState( - GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, true, true); + GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, true, true, true); - EXPECT_FALSE(DiffNavigationEntries(state, state, &difference)); + DiffNavigationEntries(state, state, &difference); + EXPECT_TRUE(difference.IsEmpty()); } // Verifies that states with different URL and title are correctly checked. TEST(FrameImplUnitTest, DiffNavigationEntriesTitleUrl) { fuchsia::web::NavigationState difference; NavigationState state1 = CreateNavigationState( - GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, true, true); + GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, true, true, true); NavigationState state2 = CreateNavigationState( - GURL(kUrl2), kTitle2, fuchsia::web::PageType::NORMAL, true, true); + GURL(kUrl2), kTitle2, fuchsia::web::PageType::NORMAL, true, true, true); - bool is_changed = DiffNavigationEntries(state1, state2, &difference); + DiffNavigationEntries(state1, state2, &difference); - EXPECT_TRUE(is_changed); + EXPECT_FALSE(difference.IsEmpty()); EXPECT_TRUE(difference.has_title()); EXPECT_EQ(difference.title(), kTitle2); EXPECT_TRUE(difference.has_url()); @@ -64,15 +67,32 @@ TEST(FrameImplUnitTest, DiffNavigationEntriesGoBackAndForward) { fuchsia::web::NavigationState difference; NavigationState state1 = CreateNavigationState( - GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, true, false); + GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, true, false, true); NavigationState state2 = CreateNavigationState( - GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, false, true); + GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, false, true, true); - bool is_changed = DiffNavigationEntries(state1, state2, &difference); + DiffNavigationEntries(state1, state2, &difference); + EXPECT_FALSE(difference.IsEmpty()); EXPECT_TRUE(difference.has_can_go_back()); EXPECT_TRUE(difference.has_can_go_back()); - EXPECT_TRUE(is_changed); EXPECT_TRUE(difference.can_go_forward()); EXPECT_FALSE(difference.can_go_back()); } + +// Verifies that is_main_document is checked correctly. +TEST(FrameImplUnitTest, DiffNavigationEntriesIsMainDocumentLoaded) { + fuchsia::web::NavigationState difference; + NavigationState state1 = CreateNavigationState( + GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, true, true, true); + NavigationState state2 = CreateNavigationState( + GURL(kUrl1), kTitle1, fuchsia::web::PageType::NORMAL, true, true, false); + + DiffNavigationEntries(state1, state2, &difference); + EXPECT_FALSE(difference.IsEmpty()); + EXPECT_FALSE(difference.is_main_document_loaded()); + + DiffNavigationEntries(state2, state1, &difference); + EXPECT_FALSE(difference.IsEmpty()); + EXPECT_TRUE(difference.is_main_document_loaded()); +}
diff --git a/fuchsia/engine/browser/web_engine_url_request_context_getter.cc b/fuchsia/engine/browser/web_engine_url_request_context_getter.cc index 48a128b..0eec8886 100644 --- a/fuchsia/engine/browser/web_engine_url_request_context_getter.cc +++ b/fuchsia/engine/browser/web_engine_url_request_context_getter.cc
@@ -10,7 +10,6 @@ #include "content/public/browser/cookie_store_factory.h" #include "net/cookies/cookie_store.h" #include "net/proxy_resolution/proxy_config_service.h" -#include "net/ssl/channel_id_service.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_builder.h"
diff --git a/fuchsia/runners/cast/cast_channel_bindings_browsertest.cc b/fuchsia/runners/cast/cast_channel_bindings_browsertest.cc index 68b041e..ed554fd5 100644 --- a/fuchsia/runners/cast/cast_channel_bindings_browsertest.cc +++ b/fuchsia/runners/cast/cast_channel_bindings_browsertest.cc
@@ -31,8 +31,6 @@ run_timeout_(TestTimeouts::action_timeout(), base::MakeExpectedNotRunClosure(FROM_HERE)) { set_test_server_root(base::FilePath("fuchsia/runners/cast/testdata")); - navigation_listener_.SetBeforeAckHook(base::BindRepeating( - &CastChannelBindingsTest::OnBeforeAckHook, base::Unretained(this))); } ~CastChannelBindingsTest() override = default; @@ -45,16 +43,6 @@ connector_ = std::make_unique<NamedMessagePortConnector>(frame_.get()); } - void OnBeforeAckHook( - const fuchsia::web::NavigationState& change, - fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback - callback) { - connector_->OnPageLoad(); - if (navigate_run_loop_) - navigate_run_loop_->Quit(); - callback(); - } - void Open(fidl::InterfaceHandle<fuchsia::web::MessagePort> channel, OpenCallback receive_next_channel_cb) override { connected_channel_ = channel.Bind(); @@ -64,15 +52,13 @@ std::move(on_channel_connected_cb_).Run(); } - void SignalReadyForNewChannel() { receive_next_channel_cb_(); } - void WaitUntilCastChannelOpened() { - if (connected_channel_) - return; - - base::RunLoop run_loop; - on_channel_connected_cb_ = run_loop.QuitClosure(); - run_loop.Run(); + if (!connected_channel_) { + base::RunLoop run_loop; + on_channel_connected_cb_ = run_loop.QuitClosure(); + run_loop.Run(); + } + receive_next_channel_cb_(); } void WaitUntilCastChannelClosed() { @@ -96,22 +82,20 @@ run_loop.Run(); std::string data; - CHECK(message->has_data()); CHECK(cr_fuchsia::StringFromMemBuffer(message->data(), &data)); return data; } - void CheckLoadUrl(const std::string& url, + void CheckLoadUrl(const GURL& url, fuchsia::web::NavigationController* controller) { navigate_run_loop_ = std::make_unique<base::RunLoop>(); cr_fuchsia::ResultReceiver< fuchsia::web::NavigationController_LoadUrl_Result> result; controller->LoadUrl( - url, fuchsia::web::LoadUrlParams(), + url.spec(), fuchsia::web::LoadUrlParams(), cr_fuchsia::CallbackToFitFunction(result.GetReceiveCallback())); - navigate_run_loop_->Run(); - navigate_run_loop_.reset(); + navigation_listener_.RunUntilUrlEquals(url); EXPECT_TRUE(result->is_response()); } @@ -150,7 +134,8 @@ // Verify that CastChannelBindings can properly handle message, connect, // disconnect, and MessagePort disconnection events. - CheckLoadUrl(test_url.spec(), controller.get()); + CheckLoadUrl(test_url, controller.get()); + connector_->OnPageLoad(); WaitUntilCastChannelOpened(); @@ -178,14 +163,13 @@ // disconnect, and MessagePort disconnection events. // Also verify that the cast channel is used across inter-page navigations. for (int i = 0; i < 5; ++i) { - CheckLoadUrl(test_url.spec(), controller.get()); + CheckLoadUrl(test_url, controller.get()); + connector_->OnPageLoad(); WaitUntilCastChannelOpened(); WaitUntilCastChannelClosed(); - SignalReadyForNewChannel(); - WaitUntilCastChannelOpened(); EXPECT_EQ("reconnected", ReadStringFromChannel()); @@ -202,15 +186,13 @@ std::move(message), cr_fuchsia::CallbackToFitFunction(post_result.GetReceiveCallback())); run_loop.Run(); - EXPECT_TRUE(post_result->is_response()); + EXPECT_FALSE(post_result->is_err()); } EXPECT_EQ("ack hello", ReadStringFromChannel()); // Navigate away. - CheckLoadUrl(empty_url.spec(), controller.get()); - - SignalReadyForNewChannel(); + CheckLoadUrl(empty_url, controller.get()); } }
diff --git a/fuchsia/runners/cast/cast_component.cc b/fuchsia/runners/cast/cast_component.cc index 0b905f1..a482c6e26 100644 --- a/fuchsia/runners/cast/cast_component.cc +++ b/fuchsia/runners/cast/cast_component.cc
@@ -73,7 +73,7 @@ void CastComponent::OnNavigationStateChanged( fuchsia::web::NavigationState change, OnNavigationStateChangedCallback callback) { - if (change.has_url()) + if (change.has_is_main_document_loaded() && change.is_main_document_loaded()) connector_.OnPageLoad(); callback(); }
diff --git a/fuchsia/runners/cast/named_message_port_connector_browsertest.cc b/fuchsia/runners/cast/named_message_port_connector_browsertest.cc index 33f94880..7dd729aa 100644 --- a/fuchsia/runners/cast/named_message_port_connector_browsertest.cc +++ b/fuchsia/runners/cast/named_message_port_connector_browsertest.cc
@@ -52,7 +52,9 @@ const fuchsia::web::NavigationState& change, fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback callback) { - connector_->OnPageLoad(); + if (change.has_is_main_document_loaded() && + change.is_main_document_loaded()) + connector_->OnPageLoad(); // Allow the TestNavigationListener's usual navigation event processing flow // to continue.
diff --git a/fuchsia/runners/cast/not_implemented_api_bindings_browsertest.cc b/fuchsia/runners/cast/not_implemented_api_bindings_browsertest.cc index 7ba1ce9..9d7f2c85 100644 --- a/fuchsia/runners/cast/not_implemented_api_bindings_browsertest.cc +++ b/fuchsia/runners/cast/not_implemented_api_bindings_browsertest.cc
@@ -12,6 +12,7 @@ #include "base/test/test_timeouts.h" #include "base/threading/thread_restrictions.h" #include "fuchsia/base/fit_adapter.h" +#include "fuchsia/base/frame_test_util.h" #include "fuchsia/base/mem_buffer_util.h" #include "fuchsia/base/result_receiver.h" #include "fuchsia/base/test_navigation_listener.h" @@ -70,16 +71,9 @@ fuchsia::web::NavigationControllerPtr controller; frame_->GetNavigationController(controller.NewRequest()); const GURL page_url(embedded_test_server()->GetURL("/defaultresponse")); - navigate_run_loop_ = std::make_unique<base::RunLoop>(); - cr_fuchsia::ResultReceiver< - fuchsia::web::NavigationController_LoadUrl_Result> - result; - controller->LoadUrl( - page_url.spec(), fuchsia::web::LoadUrlParams(), - cr_fuchsia::CallbackToFitFunction(result.GetReceiveCallback())); - navigate_run_loop_->Run(); - navigate_run_loop_.reset(); - EXPECT_TRUE(result->is_response()); + EXPECT_TRUE(cr_fuchsia::LoadUrlAndExpectResponse( + controller.get(), fuchsia::web::LoadUrlParams(), page_url.spec())); + navigation_listener_.RunUntilUrlEquals(page_url); } void OnLogMessage(base::StringPiece message) {
diff --git a/fuchsia/runners/cast/queryable_data_bindings_browsertest.cc b/fuchsia/runners/cast/queryable_data_bindings_browsertest.cc index d039a434..3448628 100644 --- a/fuchsia/runners/cast/queryable_data_bindings_browsertest.cc +++ b/fuchsia/runners/cast/queryable_data_bindings_browsertest.cc
@@ -109,7 +109,8 @@ const fuchsia::web::NavigationState& change, fuchsia::web::NavigationEventListener::OnNavigationStateChangedCallback callback) { - if (change.has_url()) + if (change.has_is_main_document_loaded() && + change.is_main_document_loaded()) connector_->OnPageLoad(); callback();
diff --git a/gpu/command_buffer/service/gl_utils.cc b/gpu/command_buffer/service/gl_utils.cc index dc49d58..ee8cd5d 100644 --- a/gpu/command_buffer/service/gl_utils.cc +++ b/gpu/command_buffer/service/gl_utils.cc
@@ -901,23 +901,6 @@ break; } - // CopyTex{Sub}Image2D() from GL_RGB10_A2 has issues on some Android chipsets. - if (source_internal_format == GL_RGB10_A2) { - if (feature_info->workarounds().disable_copy_tex_image_2d_rgb10_a2_tegra) { - if (dest_internal_format == GL_RGBA4) - return CopyTextureMethod::DIRECT_DRAW; - return CopyTextureMethod::DRAW_AND_COPY; - } - if (feature_info->workarounds().disable_copy_tex_image_2d_rgb10_a2_adreno && - dest_internal_format != GL_RGB10_A2) { - return CopyTextureMethod::DRAW_AND_COPY; - } - if (feature_info->workarounds().disable_copy_tex_image_2d_rgb10_a2_mali && - (dest_internal_format == GL_RGB || dest_internal_format == GL_RGBA)) { - return CopyTextureMethod::DRAW_AND_COPY; - } - } - // CopyTexImage* should not allow internalformat of GL_BGRA_EXT and // GL_BGRA8_EXT. https://crbug.com/663086. bool copy_tex_image_format_valid = @@ -929,6 +912,15 @@ source_internal_format, source_type, &output_error_msg); + // The ES3 spec is vague about whether or not glCopyTexImage2D from a + // GL_RGB10_A2 attachment to an unsized internal format is valid. Most drivers + // interpreted the explicit call out as not valid (and dEQP actually checks + // this), so avoid DIRECT_COPY in that case. + if (feature_info->gl_version_info().is_es && + source_internal_format == GL_RGB10_A2 && + dest_internal_format != source_internal_format) + copy_tex_image_format_valid = false; + // TODO(qiankun.miao@intel.com): for WebGL 2.0 or OpenGL ES 3.0, both // DIRECT_DRAW path for dest_level > 0 and DIRECT_COPY path for source_level > // 0 are not available due to a framebuffer completeness bug:
diff --git a/gpu/config/gpu_driver_bug_list.json b/gpu/config/gpu_driver_bug_list.json index 4c3b0593..6548216 100644 --- a/gpu/config/gpu_driver_bug_list.json +++ b/gpu/config/gpu_driver_bug_list.json
@@ -3067,41 +3067,6 @@ ] }, { - "id": 287, - "description": "glCopyTexImage2D on Adreno fails if source is GL_RGB10_A2 and destination is not.", - "cr_bugs": [925986], - "os": { - "type": "android", - "version": { - "op": ">=", - "value": "5.0.0" - } - }, - "gl_vendor": "Qualcomm.*", - "gl_renderer": ".*4\\d\\d", - "gl_renderer": "Adreno \\(TM\\) [345].*", - "features": [ - "disable_copy_tex_image_2d_rgb10_a2_adreno" - ] - }, - { - "id": 288, - "description": "glCopyTexImage2D on NVIDIA Tegra fails in certain cases if source is GL_RGB10_A2.", - "cr_bugs": [925986], - "os": { - "type": "android" - }, - "gl_vendor": "NVIDIA.*", - "gl_type": "gles", - "gl_version": { - "op": ">=", - "value": "3.0" - }, - "features": [ - "disable_copy_tex_image_2d_rgb10_a2_tegra" - ] - }, - { "id": 289, "description": "Fake entry for testing command buffer init failures on ES 2.0", "cr_bugs": [923134], @@ -3279,19 +3244,6 @@ ] }, { - "id": 302, - "description": "glCopyTexImage2D on Mali-T820 fails in certain cases if source is GL_RGB10_A2.", - "cr_bugs": [953771], - "os": { - "type": "android" - }, - "gl_vendor": "ARM.*", - "gl_renderer": "Mali-T820", - "features": [ - "disable_copy_tex_image_2d_rgb10_a2_mali" - ] - }, - { "id": 303, "cr_bugs": [890227], "description": "Dynamic texture map crashes on Intel drivers less than version 24",
diff --git a/gpu/config/gpu_workaround_list.txt b/gpu/config/gpu_workaround_list.txt index 5532d22..be9290eb 100644 --- a/gpu/config/gpu_workaround_list.txt +++ b/gpu/config/gpu_workaround_list.txt
@@ -110,8 +110,5 @@ validate_multisample_buffer_allocation wake_up_gpu_before_drawing use_copyteximage2d_instead_of_readpixels_on_multisampled_textures -disable_copy_tex_image_2d_rgb10_a2_adreno -disable_copy_tex_image_2d_rgb10_a2_tegra use_eqaa_storage_samples_2 max_3d_array_texture_size_1024 -disable_copy_tex_image_2d_rgb10_a2_mali
diff --git a/gpu/ipc/common/BUILD.gn b/gpu/ipc/common/BUILD.gn index f08e278..9e4e036 100644 --- a/gpu/ipc/common/BUILD.gn +++ b/gpu/ipc/common/BUILD.gn
@@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/ui.gni") +import("//gpu/vulkan/features.gni") import("//mojo/public/tools/bindings/mojom.gni") group("common") { @@ -247,4 +248,8 @@ "//gpu/ipc/common", "//mojo/public/cpp/bindings:bindings", ] + if (enable_vulkan) { + sources += [ "vulkan_ycbcr_info_mojom_traits.h" ] + deps += [ "//gpu/vulkan:vulkan" ] + } }
diff --git a/gpu/ipc/common/OWNERS b/gpu/ipc/common/OWNERS index 62994ee..6aa938a 100644 --- a/gpu/ipc/common/OWNERS +++ b/gpu/ipc/common/OWNERS
@@ -14,3 +14,5 @@ per-file *_struct_traits*.*=file://ipc/SECURITY_OWNERS per-file *.typemap=set noparent per-file *.typemap=file://ipc/SECURITY_OWNERS +per-file *_mojom_traits*.*=set noparent +per-file *_mojom_traits*.*=file://ipc/SECURITY_OWNERS
diff --git a/gpu/ipc/common/typemaps.gni b/gpu/ipc/common/typemaps.gni index 54e4bf2..8316f13 100644 --- a/gpu/ipc/common/typemaps.gni +++ b/gpu/ipc/common/typemaps.gni
@@ -2,6 +2,8 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//gpu/vulkan/features.gni") + typemaps = [ "//gpu/ipc/common/capabilities.typemap", "//gpu/ipc/common/context_result.typemap", @@ -15,3 +17,7 @@ "//gpu/ipc/common/surface_handle.typemap", "//gpu/ipc/common/sync_token.typemap", ] + +if (enable_vulkan) { + typemaps += [ "//gpu/ipc/common/vulkan_ycbcr_info.typemap" ] +}
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.mojom b/gpu/ipc/common/vulkan_ycbcr_info.mojom index e6eadd1..692ad13 100644 --- a/gpu/ipc/common/vulkan_ycbcr_info.mojom +++ b/gpu/ipc/common/vulkan_ycbcr_info.mojom
@@ -8,35 +8,12 @@ // enums defined in the vulkan api which are passed as uint32/uint64 over ipc. // We use all of these values in an "opaque" way and don't consume it directly // in chrome. +// See gpu/vulkan/vulkan_ycbcr_info.h. struct VulkanYCbCrInfo { - // Describes the color matrix for conversion between color models. - // Corresponds to vulkan type: VkSamplerYcbcrModelConversion. uint32 suggested_ycbcr_model; - - // Describes whether the encoded values have headroom and foot room, or - // whether the encoding uses the full numerical range. - // Corresponds to vulkan type: VkSamplerYcbcrRange. uint32 suggested_ycbcr_range; - - // Describes the sample location associated with downsampled chroma channels - // in the x dimension. It has no effect for formats in which chroma channels - // are the same resolution as the luma channel. - // Corresponds to vulkan type: VkChromaLocation. uint32 suggested_xchroma_offset; - - // Describes the sample location associated with downsampled chroma channels - // in the y dimension. It has no effect for formats in which chroma channels - // are not downsampled vertically. - // Corresponds to vulkan type: VkChromaLocation. uint32 suggested_ychroma_offset; - - // Implementation-defined external format identifier for use with - // VkExternalFormatANDROID. - // This property is driver specific. uint64 external_format; - - // Describes the capabilities of the external format when used with an image - // bound to memory imported from buffer. - // Corresponds to vulkan type: VkFormatFeatureFlags. uint32 format_features; };
diff --git a/gpu/ipc/common/vulkan_ycbcr_info.typemap b/gpu/ipc/common/vulkan_ycbcr_info.typemap new file mode 100644 index 0000000..32b17b8 --- /dev/null +++ b/gpu/ipc/common/vulkan_ycbcr_info.typemap
@@ -0,0 +1,8 @@ +# Copyright 2019 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +mojom = "//gpu/ipc/common/vulkan_ycbcr_info.mojom" +public_headers = [ "//gpu/vulkan/vulkan_ycbcr_info.h" ] +traits_headers = [ "//gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h" ] +type_mappings = [ "gpu.mojom.VulkanYCbCrInfo=::gpu::VulkanYCbCrInfo" ]
diff --git a/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h b/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h new file mode 100644 index 0000000..b33e894 --- /dev/null +++ b/gpu/ipc/common/vulkan_ycbcr_info_mojom_traits.h
@@ -0,0 +1,53 @@ +// Copyright 2019 The Chromium 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 GPU_IPC_COMMON_VULKAN_YCBCR_INFO_MOJOM_TRAITS_H_ +#define GPU_IPC_COMMON_VULKAN_YCBCR_INFO_MOJOM_TRAITS_H_ + +#include "gpu/ipc/common/vulkan_ycbcr_info.mojom-shared.h" +#include "gpu/vulkan/vulkan_ycbcr_info.h" + +namespace mojo { + +template <> +struct StructTraits<gpu::mojom::VulkanYCbCrInfoDataView, gpu::VulkanYCbCrInfo> { + static uint32_t suggested_ycbcr_model(const gpu::VulkanYCbCrInfo& info) { + return info.suggested_ycbcr_model; + } + + static uint32_t suggested_ycbcr_range(const gpu::VulkanYCbCrInfo& info) { + return info.suggested_ycbcr_range; + } + + static uint32_t suggested_xchroma_offset(const gpu::VulkanYCbCrInfo& info) { + return info.suggested_xchroma_offset; + } + + static uint32_t suggested_ychroma_offset(const gpu::VulkanYCbCrInfo& info) { + return info.suggested_ychroma_offset; + } + + static uint64_t external_format(const gpu::VulkanYCbCrInfo& info) { + return info.external_format; + } + + static uint32_t format_features(const gpu::VulkanYCbCrInfo& info) { + return info.format_features; + } + + static bool Read(gpu::mojom::VulkanYCbCrInfoDataView data, + gpu::VulkanYCbCrInfo* out) { + out->suggested_ycbcr_model = data.suggested_ycbcr_model(); + out->suggested_ycbcr_range = data.suggested_ycbcr_range(); + out->suggested_xchroma_offset = data.suggested_xchroma_offset(); + out->suggested_ychroma_offset = data.suggested_ychroma_offset(); + out->external_format = data.external_format(); + out->format_features = data.format_features(); + return true; + } +}; + +} // namespace mojo + +#endif // GPU_IPC_COMMON_VULKAN_YCBCR_INFO_MOJOM_TRAITS_H_
diff --git a/gpu/vulkan/BUILD.gn b/gpu/vulkan/BUILD.gn index 5a440b9d..e5e998e 100644 --- a/gpu/vulkan/BUILD.gn +++ b/gpu/vulkan/BUILD.gn
@@ -50,6 +50,8 @@ "vulkan_swap_chain.h", "vulkan_util.cc", "vulkan_util.h", + "vulkan_ycbcr_info.cc", + "vulkan_ycbcr_info.h", ] configs += [ "//build/config:precompiled_headers" ]
diff --git a/gpu/vulkan/android/BUILD.gn b/gpu/vulkan/android/BUILD.gn index 28a39ee..c9c4e59 100644 --- a/gpu/vulkan/android/BUILD.gn +++ b/gpu/vulkan/android/BUILD.gn
@@ -24,7 +24,6 @@ defines = [ "IS_VULKAN_ANDROID_IMPL" ] deps = [ - "//gpu/ipc/common:interfaces", "//ui/gfx", ]
diff --git a/gpu/vulkan/android/vulkan_implementation_android.cc b/gpu/vulkan/android/vulkan_implementation_android.cc index 1e14f87..4a40c40 100644 --- a/gpu/vulkan/android/vulkan_implementation_android.cc +++ b/gpu/vulkan/android/vulkan_implementation_android.cc
@@ -8,13 +8,13 @@ #include "base/bind_helpers.h" #include "base/files/file_path.h" #include "base/logging.h" -#include "gpu/ipc/common/vulkan_ycbcr_info.mojom.h" #include "gpu/vulkan/vulkan_device_queue.h" #include "gpu/vulkan/vulkan_function_pointers.h" #include "gpu/vulkan/vulkan_instance.h" #include "gpu/vulkan/vulkan_posix_util.h" #include "gpu/vulkan/vulkan_surface.h" #include "gpu/vulkan/vulkan_util.h" +#include "gpu/vulkan/vulkan_ycbcr_info.h" #include "ui/gfx/gpu_fence.h" #include "ui/gfx/gpu_memory_buffer.h" @@ -164,7 +164,7 @@ VkImageCreateInfo* vk_image_info, VkDeviceMemory* vk_device_memory, VkDeviceSize* mem_allocation_size, - mojom::VulkanYCbCrInfo* ycbcr_info) { + VulkanYCbCrInfo* ycbcr_info) { DCHECK(ahb_handle.is_valid()); DCHECK(vk_image); DCHECK(vk_image_info);
diff --git a/gpu/vulkan/android/vulkan_implementation_android.h b/gpu/vulkan/android/vulkan_implementation_android.h index 32f66ea..8d3c29a7 100644 --- a/gpu/vulkan/android/vulkan_implementation_android.h +++ b/gpu/vulkan/android/vulkan_implementation_android.h
@@ -60,7 +60,7 @@ VkImageCreateInfo* vk_image_info, VkDeviceMemory* vk_device_memory, VkDeviceSize* mem_allocation_size, - mojom::VulkanYCbCrInfo* ycbcr_info) override; + VulkanYCbCrInfo* ycbcr_info) override; private: VulkanInstance vulkan_instance_;
diff --git a/gpu/vulkan/vulkan_implementation.h b/gpu/vulkan/vulkan_implementation.h index 6f67249a..5e676e9 100644 --- a/gpu/vulkan/vulkan_implementation.h +++ b/gpu/vulkan/vulkan_implementation.h
@@ -33,10 +33,7 @@ class VulkanDeviceQueue; class VulkanSurface; class VulkanInstance; - -namespace mojom { -class VulkanYCbCrInfo; -} // namespace mojom +struct VulkanYCbCrInfo; // Base class which provides functions for creating vulkan objects for different // platforms that use platform-specific extensions (e.g. for creation of @@ -124,7 +121,7 @@ VkImageCreateInfo* vk_image_info, VkDeviceMemory* vk_device_memory, VkDeviceSize* mem_allocation_size, - mojom::VulkanYCbCrInfo* ycbcr_info = nullptr) = 0; + VulkanYCbCrInfo* ycbcr_info = nullptr) = 0; #endif private:
diff --git a/gpu/vulkan/vulkan_ycbcr_info.cc b/gpu/vulkan/vulkan_ycbcr_info.cc new file mode 100644 index 0000000..c5834d90 --- /dev/null +++ b/gpu/vulkan/vulkan_ycbcr_info.cc
@@ -0,0 +1,24 @@ +// Copyright 2019 The Chromium 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 "gpu/vulkan/vulkan_ycbcr_info.h" + +namespace gpu { + +VulkanYCbCrInfo::VulkanYCbCrInfo() = default; + +VulkanYCbCrInfo::VulkanYCbCrInfo(uint32_t suggested_ycbcr_model, + uint32_t suggested_ycbcr_range, + uint32_t suggested_xchroma_offset, + uint32_t suggested_ychroma_offset, + uint64_t external_format, + uint32_t format_features) + : suggested_ycbcr_model(suggested_ycbcr_model), + suggested_ycbcr_range(suggested_ycbcr_range), + suggested_xchroma_offset(suggested_xchroma_offset), + suggested_ychroma_offset(suggested_ychroma_offset), + external_format(external_format), + format_features(format_features) {} + +} // namespace gpu
diff --git a/gpu/vulkan/vulkan_ycbcr_info.h b/gpu/vulkan/vulkan_ycbcr_info.h new file mode 100644 index 0000000..643ffa5e --- /dev/null +++ b/gpu/vulkan/vulkan_ycbcr_info.h
@@ -0,0 +1,58 @@ +// Copyright 2019 The Chromium 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 GPU_VULKAN_VULKAN_YCBCR_INFO_H_ +#define GPU_VULKAN_VULKAN_YCBCR_INFO_H_ + +#include <stdint.h> + +#include "gpu/vulkan/vulkan_export.h" + +namespace gpu { + +// Sampler Ycbcr conversion information. +struct VULKAN_EXPORT VulkanYCbCrInfo { + VulkanYCbCrInfo(); + VulkanYCbCrInfo(uint32_t suggested_ycbcr_model, + uint32_t suggested_ycbcr_range, + uint32_t suggested_xchroma_offset, + uint32_t suggested_ychroma_offset, + uint64_t external_format, + uint32_t format_features); + + // Describes the color matrix for conversion between color models. + // Corresponds to vulkan type: VkSamplerYcbcrModelConversion. + uint32_t suggested_ycbcr_model; + + // Describes whether the encoded values have headroom and foot room, or + // whether the encoding uses the full numerical range. + // Corresponds to vulkan type: VkSamplerYcbcrRange. + uint32_t suggested_ycbcr_range; + + // Describes the sample location associated with downsampled chroma channels + // in the x dimension. It has no effect for formats in which chroma channels + // are the same resolution as the luma channel. + // Corresponds to vulkan type: VkChromaLocation. + uint32_t suggested_xchroma_offset; + + // Describes the sample location associated with downsampled chroma channels + // in the y dimension. It has no effect for formats in which chroma channels + // are not downsampled vertically. + // Corresponds to vulkan type: VkChromaLocation. + uint32_t suggested_ychroma_offset; + + // Implementation-defined external format identifier for use with + // VkExternalFormatANDROID. + // This property is driver specific. + uint64_t external_format; + + // Describes the capabilities of the external format when used with an image + // bound to memory imported from buffer. + // Corresponds to vulkan type: VkFormatFeatureFlags. + uint32_t format_features; +}; + +} // namespace gpu + +#endif // GPU_VULKAN_VULKAN_YCBCR_INFO_H_
diff --git a/infra/config/cr-buildbucket.cfg b/infra/config/cr-buildbucket.cfg index 1b2f05a..676a15f 100644 --- a/infra/config/cr-buildbucket.cfg +++ b/infra/config/cr-buildbucket.cfg
@@ -2857,6 +2857,13 @@ mixins: "goma-j80" } builders { + name: "Chromium Mac Goma RBE Prod" + dimensions: "os:Mac-10.13" + dimensions: "cores:4" + mixins: "goma-ci" + mixins: "goma-j80" + } + builders { name: "Chromium Win Goma RBE ToT" dimensions: "os:Windows-10" mixins: "goma-ats" @@ -2875,6 +2882,30 @@ mixins: "goma-ci" } builders { + name: "Chromium Win Goma RBE Prod" + dimensions: "os:Windows-10" + mixins: "goma-ats" + mixins: "goma-ci" + } + builders { + name: "Chromium Win Goma RBE Prod (clobber)" + dimensions: "os:Windows-10" + mixins: "goma-ats" + mixins: "goma-ci" + } + builders { + name: "Chromium Win Goma RBE Prod (dbg)" + dimensions: "os:Windows-10" + mixins: "goma-ats" + mixins: "goma-ci" + } + builders { + name: "Chromium Win Goma RBE Prod (dbg) (clobber)" + dimensions: "os:Windows-10" + mixins: "goma-ats" + mixins: "goma-ci" + } + builders { name: "Chromium Android ARM 32-bit Goma RBE ToT" dimensions: "os:Ubuntu-14.04" mixins: "goma-ci"
diff --git a/infra/config/luci-milo.cfg b/infra/config/luci-milo.cfg index 112fe1b..4160d93c 100644 --- a/infra/config/luci-milo.cfg +++ b/infra/config/luci-milo.cfg
@@ -2627,6 +2627,28 @@ short_name: "clb" } builders { + name: "buildbucket/luci.chromium.ci/Chromium Mac Goma RBE Prod" + category: "prod|mac|rel" + } + builders { + name: "buildbucket/luci.chromium.ci/Chromium Win Goma RBE Prod" + category: "prod|win|rel" + } + builders { + name: "buildbucket/luci.chromium.ci/Chromium Win Goma RBE Prod (clobber)" + category: "prod|win|rel" + short_name: "clb" + } + builders { + name: "buildbucket/luci.chromium.ci/Chromium Win Goma RBE Prod (dbg)" + category: "prod|win|dbg" + } + builders { + name: "buildbucket/luci.chromium.ci/Chromium Win Goma RBE Prod (dbg) (clobber)" + category: "prod|win|dbg" + short_name: "clb" + } + builders { name: "buildbucket/luci.chromium.ci/Chromium Android ARM 32-bit Goma RBE Prod" category: "prod|android arm|rel" }
diff --git a/infra/config/luci-scheduler.cfg b/infra/config/luci-scheduler.cfg index 55dfb686..3658d9bb 100644 --- a/infra/config/luci-scheduler.cfg +++ b/infra/config/luci-scheduler.cfg
@@ -129,14 +129,19 @@ triggers: "Chromium Linux Goma RBE ToT (ATS)" triggers: "Chromium Linux Goma Staging" triggers: "Chromium Mac 10.13" + triggers: "Chromium Mac Goma RBE Prod" triggers: "Chromium Mac Goma RBE Staging" triggers: "Chromium Mac Goma RBE Staging (clobber)" triggers: "Chromium Mac Goma RBE Staging (dbg)" triggers: "Chromium Mac Goma RBE ToT" triggers: "Chromium Mac Goma Staging" - triggers: "Chromium Win Goma RBE ToT" + triggers: "Chromium Win Goma RBE Prod" + triggers: "Chromium Win Goma RBE Prod (clobber)" + triggers: "Chromium Win Goma RBE Prod (dbg)" + triggers: "Chromium Win Goma RBE Prod (dbg) (clobber)" triggers: "Chromium Win Goma RBE Staging" triggers: "Chromium Win Goma RBE Staging (clobber)" + triggers: "Chromium Win Goma RBE ToT" triggers: "ChromiumOS ASAN Release" triggers: "Closure Compilation Linux" triggers: "CrWinAsan" @@ -4868,6 +4873,16 @@ } job { + id: "Chromium Mac Goma RBE Prod" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Chromium Mac Goma RBE Prod" + } +} + +job { id: "Chromium Win Goma RBE ToT" acl_sets: "default" buildbucket: { @@ -4898,6 +4913,46 @@ } job { + id: "Chromium Win Goma RBE Prod" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Chromium Win Goma RBE Prod" + } +} + +job { + id: "Chromium Win Goma RBE Prod (clobber)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Chromium Win Goma RBE Prod (clobber)" + } +} + +job { + id: "Chromium Win Goma RBE Prod (dbg)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Chromium Win Goma RBE Prod (dbg)" + } +} + +job { + id: "Chromium Win Goma RBE Prod (dbg) (clobber)" + acl_sets: "default" + buildbucket: { + server: "cr-buildbucket.appspot.com" + bucket: "luci.chromium.ci" + builder: "Chromium Win Goma RBE Prod (dbg) (clobber)" + } +} + +job { id: "Cast Linux (Goma RBE FYI)" acl_sets: "default" buildbucket: {
diff --git a/ios/chrome/app/application_delegate/BUILD.gn b/ios/chrome/app/application_delegate/BUILD.gn index 08b9db63..518e2cd 100644 --- a/ios/chrome/app/application_delegate/BUILD.gn +++ b/ios/chrome/app/application_delegate/BUILD.gn
@@ -79,10 +79,7 @@ "//ui/base", "//url", ] - libs = [ - "CoreSpotlight.framework", - "QuartzCore.framework", - ] + libs = [ "CoreSpotlight.framework" ] } source_set("application_delegate_internal") {
diff --git a/ios/chrome/app/application_delegate/DEPS b/ios/chrome/app/application_delegate/DEPS deleted file mode 100644 index 88f46f0..0000000 --- a/ios/chrome/app/application_delegate/DEPS +++ /dev/null
@@ -1,12 +0,0 @@ -specific_include_rules = { - "app_state.mm": [ - # TODO(crbug.com/585700): Remove ios/web/net exceptions, once request - # tracker is removed. - "+ios/web/net/request_tracker_impl.h", - ], - "app_state_unittest.mm": [ - # TODO(crbug.com/585700): Remove ios/web/net exceptions, once request - # tracker is removed. - "+ios/web/net/request_tracker_impl.h", - ], -}
diff --git a/ios/chrome/app/application_delegate/app_state.mm b/ios/chrome/app/application_delegate/app_state.mm index 84219d0..7360ad5 100644 --- a/ios/chrome/app/application_delegate/app_state.mm +++ b/ios/chrome/app/application_delegate/app_state.mm
@@ -52,9 +52,9 @@ #include "ios/public/provider/chrome/browser/chrome_browser_provider.h" #include "ios/public/provider/chrome/browser/distribution/app_distribution_provider.h" #import "ios/public/provider/chrome/browser/user_feedback/user_feedback_provider.h" -#include "ios/web/net/request_tracker_impl.h" #include "ios/web/public/web_task_traits.h" #include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" #if !defined(__has_feature) || !__has_feature(objc_arc) #error "This file requires ARC support." @@ -412,9 +412,6 @@ NO; } - // TODO(crbug.com/585700): remove this. - web::RequestTrackerImpl::BlockUntilTrackersShutdown(); - [_startupInformation stopChromeMain]; }
diff --git a/ios/chrome/app/application_delegate/app_state_unittest.mm b/ios/chrome/app/application_delegate/app_state_unittest.mm index 37870eb..587f9a45 100644 --- a/ios/chrome/app/application_delegate/app_state_unittest.mm +++ b/ios/chrome/app/application_delegate/app_state_unittest.mm
@@ -4,15 +4,11 @@ #import "ios/chrome/app/application_delegate/app_state.h" -#import <QuartzCore/QuartzCore.h> - #include <memory> #include "base/bind.h" #include "base/ios/block_types.h" #include "base/mac/scoped_block.h" -#include "base/synchronization/lock.h" -#include "base/task/post_task.h" #import "ios/chrome/app/application_delegate/app_navigation.h" #import "ios/chrome/app/application_delegate/app_state_testing.h" #import "ios/chrome/app/application_delegate/browser_launcher.h" @@ -53,7 +49,6 @@ #include "ios/public/provider/chrome/browser/test_chrome_browser_provider.h" #include "ios/public/provider/chrome/browser/user_feedback/test_user_feedback_provider.h" #import "ios/testing/ocmock_complex_type_helper.h" -#include "ios/web/net/request_tracker_impl.h" #include "ios/web/public/test/test_web_thread_bundle.h" #include "ios/web/public/web_task_traits.h" #import "third_party/ocmock/OCMock/OCMock.h" @@ -358,44 +353,11 @@ std::unique_ptr<TestChromeBrowserState> browser_state_; }; -// TODO(crbug.com/585700): remove this. -// Creates a requestTracker, needed for teardown. -void createTracker(BOOL* created, base::Lock* lock) { - web::RequestTrackerImpl::GetTrackerForRequestGroupID(@"test"); - base::AutoLock scoped_lock(*lock); - *created = YES; -} - // Used to have a thread handling the closing of the IO threads. class AppStateWithThreadTest : public PlatformTest { protected: AppStateWithThreadTest() : thread_bundle_(web::TestWebThreadBundle::REAL_IO_THREAD) { - BOOL created = NO; - base::Lock* lock = new base::Lock; - - base::PostTaskWithTraits(FROM_HERE, {web::WebThread::IO}, - base::BindOnce(&createTracker, &created, lock)); - - CFTimeInterval start = CACurrentMediaTime(); - - // Poll for at most 1s, waiting for the Tracker creation. - while (1) { - base::AutoLock scoped_lock(*lock); - if (created) - return; - if (CACurrentMediaTime() - start > 1.0) { - trackerCreationFailed(); - return; - } - // Ensure that other threads have a chance to run even on a single-core - // devices. - pthread_yield_np(); - } - } - - void trackerCreationFailed() { - FAIL() << "Tracker creation took too much time."; } private:
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.h b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.h index 91fb5ad6..4d4a921 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.h +++ b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.h
@@ -42,7 +42,6 @@ } namespace net { -class ChannelIDService; class CookieStore; class HttpServerProperties; class HttpTransactionFactory; @@ -132,8 +131,6 @@ AppRequestContext(); void SetCookieStore(std::unique_ptr<net::CookieStore> cookie_store); - void SetChannelIDService( - std::unique_ptr<net::ChannelIDService> channel_id_service); void SetHttpNetworkSession( std::unique_ptr<net::HttpNetworkSession> http_network_session); void SetHttpTransactionFactory( @@ -144,7 +141,6 @@ private: std::unique_ptr<net::CookieStore> cookie_store_; - std::unique_ptr<net::ChannelIDService> channel_id_service_; std::unique_ptr<net::HttpNetworkSession> http_network_session_; std::unique_ptr<net::HttpTransactionFactory> http_factory_; std::unique_ptr<net::URLRequestJobFactory> job_factory_; @@ -195,11 +191,6 @@ void ShutdownOnUIThread( std::unique_ptr<IOSChromeURLRequestContextGetterVector> context_getters); - // A ChannelIDService object is created by a derived class of - // ChromeBrowserStateIOData, and the derived class calls this method to set - // the channel_id_service_ member and transfers ownership to the base class. - void set_channel_id_service(net::ChannelIDService* channel_id_service) const; - net::ProxyResolutionService* proxy_resolution_service() const { return proxy_resolution_service_.get(); } @@ -280,9 +271,6 @@ BooleanPrefMember enable_metrics_; - // Pointed to by URLRequestContext. - mutable std::unique_ptr<net::ChannelIDService> channel_id_service_; - mutable std::unique_ptr<net::ProxyResolutionService> proxy_resolution_service_; mutable std::unique_ptr<net::TransportSecurityState>
diff --git a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm index d2228f2..8263be7 100644 --- a/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm +++ b/ios/chrome/browser/browser_state/chrome_browser_state_io_data.mm
@@ -57,7 +57,6 @@ #include "net/proxy_resolution/pac_file_fetcher_impl.h" #include "net/proxy_resolution/proxy_config_service_fixed.h" #include "net/proxy_resolution/proxy_resolution_service.h" -#include "net/ssl/channel_id_service.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/data_protocol_handler.h" #include "net/url_request/file_protocol_handler.h" @@ -134,12 +133,6 @@ set_cookie_store(cookie_store_.get()); } -void ChromeBrowserStateIOData::AppRequestContext::SetChannelIDService( - std::unique_ptr<net::ChannelIDService> channel_id_service) { - channel_id_service_ = std::move(channel_id_service); - set_channel_id_service(channel_id_service_.get()); -} - void ChromeBrowserStateIOData::AppRequestContext::SetHttpNetworkSession( std::unique_ptr<net::HttpNetworkSession> http_network_session) { http_network_session_ = std::move(http_network_session); @@ -468,11 +461,6 @@ delete this; } -void ChromeBrowserStateIOData::set_channel_id_service( - net::ChannelIDService* channel_id_service) const { - channel_id_service_.reset(channel_id_service); -} - std::unique_ptr<net::HttpNetworkSession> ChromeBrowserStateIOData::CreateHttpNetworkSession( const ProfileParams& profile_params) const {
diff --git a/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.mm b/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.mm index d5ba9a96..724e5c5 100644 --- a/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.mm +++ b/ios/chrome/browser/ui/tab_grid/tab_grid_top_toolbar.mm
@@ -32,6 +32,10 @@ #pragma mark - UIView +- (CGSize)intrinsicContentSize { + return CGSizeMake(UIViewNoIntrinsicMetric, kTabGridTopToolbarHeight); +} + - (void)willMoveToSuperview:(UIView*)newSuperview { // The first time this moves to a superview, perform the view setup. if (newSuperview && self.subviews.count == 0) {
diff --git a/ios/components/io_thread/ios_io_thread.mm b/ios/components/io_thread/ios_io_thread.mm index f8187073..5fa5d9b 100644 --- a/ios/components/io_thread/ios_io_thread.mm +++ b/ios/components/io_thread/ios_io_thread.mm
@@ -59,8 +59,6 @@ #include "net/proxy_resolution/proxy_resolution_service.h" #include "net/socket/tcp_client_socket.h" #include "net/spdy/spdy_session.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/default_channel_id_store.h" #include "net/ssl/ssl_config_service_defaults.h" #include "net/url_request/data_protocol_handler.h" #include "net/url_request/file_protocol_handler.h" @@ -262,7 +260,6 @@ // TODO(crbug.com/801910): Hook up logging by passing in a non-null netlog. globals_->system_cookie_store.reset( new net::CookieMonster(nullptr /* store */, nullptr /* netlog */)); - // In-memory channel ID store. globals_->http_user_agent_settings.reset(new net::StaticHttpUserAgentSettings( std::string(), web::GetWebClient()->GetUserAgent(web::UserAgentType::MOBILE)));
diff --git a/ios/web/shell/shell_url_request_context_getter.mm b/ios/web/shell/shell_url_request_context_getter.mm index fcea7d6..347b502 100644 --- a/ios/web/shell/shell_url_request_context_getter.mm +++ b/ios/web/shell/shell_url_request_context_getter.mm
@@ -31,8 +31,6 @@ #include "net/log/net_log.h" #include "net/proxy_resolution/proxy_config_service_ios.h" #include "net/proxy_resolution/proxy_resolution_service.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/default_channel_id_store.h" #include "net/ssl/ssl_config_service_defaults.h" #include "net/traffic_annotation/network_traffic_annotation.h" #include "net/url_request/data_protocol_handler.h" @@ -112,8 +110,6 @@ url_request_context_->transport_security_state(), base_path_, base::CreateSequencedTaskRunnerWithTraits( {base::MayBlock(), base::TaskPriority::BEST_EFFORT})); - storage_->set_channel_id_service(std::make_unique<net::ChannelIDService>( - new net::DefaultChannelIDStore(nullptr))); storage_->set_http_server_properties( std::unique_ptr<net::HttpServerProperties>( new net::HttpServerPropertiesImpl()));
diff --git a/ipc/ipc_mojo_bootstrap.cc b/ipc/ipc_mojo_bootstrap.cc index 63193145..a2e24f4d 100644 --- a/ipc/ipc_mojo_bootstrap.cc +++ b/ipc/ipc_mojo_bootstrap.cc
@@ -839,7 +839,7 @@ mojo::InterfaceId id = message->interface_id(); DCHECK(mojo::IsValidInterfaceId(id)); - base::AutoLock locker(lock_); + base::ReleasableAutoLock locker(&lock_); Endpoint* endpoint = FindEndpoint(id); if (!endpoint) return true; @@ -870,10 +870,16 @@ return true; } + // If |proxy_task_runner_| has been torn down already, this PostTask will + // fail and destroy |message|. That operation may need to in turn destroy + // in-transit associated endpoints and thus acquire |lock_|. We no longer + // need the lock to be held now since |proxy_task_runner_| is safe to + // access unguarded. + locker.Release(); proxy_task_runner_->PostTask( FROM_HERE, base::BindOnce(&ChannelAssociatedGroupController::AcceptOnProxyThread, - this, base::Passed(message))); + this, std::move(*message))); return true; } @@ -882,7 +888,7 @@ DCHECK(!message->has_flag(mojo::Message::kFlagIsSync) || !message->has_flag(mojo::Message::kFlagIsResponse)); - base::AutoUnlock unlocker(lock_); + locker.Release(); return client->HandleIncomingMessage(message); } @@ -973,7 +979,7 @@ scoped_refptr<base::SingleThreadTaskRunner> task_runner_; - scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_; + const scoped_refptr<base::SingleThreadTaskRunner> proxy_task_runner_; const bool set_interface_id_namespace_bit_; bool paused_ = false; std::unique_ptr<mojo::Connector> connector_;
diff --git a/media/blink/watch_time_reporter.cc b/media/blink/watch_time_reporter.cc index 52fe5c4a..1579edc3 100644 --- a/media/blink/watch_time_reporter.cc +++ b/media/blink/watch_time_reporter.cc
@@ -41,7 +41,7 @@ WatchTimeReporter::WatchTimeReporter( mojom::PlaybackPropertiesPtr properties, - const gfx::Size& initial_natural_size, + const gfx::Size& natural_size, GetMediaTimeCB get_media_time_cb, mojom::MediaMetricsProvider* provider, scoped_refptr<base::SequencedTaskRunner> task_runner, @@ -49,7 +49,7 @@ : WatchTimeReporter(std::move(properties), false /* is_background */, false /* is_muted */, - initial_natural_size, + natural_size, std::move(get_media_time_cb), provider, task_runner, @@ -59,7 +59,7 @@ mojom::PlaybackPropertiesPtr properties, bool is_background, bool is_muted, - const gfx::Size& initial_natural_size, + const gfx::Size& natural_size, GetMediaTimeCB get_media_time_cb, mojom::MediaMetricsProvider* provider, scoped_refptr<base::SequencedTaskRunner> task_runner, @@ -67,9 +67,9 @@ : properties_(std::move(properties)), is_background_(is_background), is_muted_(is_muted), - initial_natural_size_(initial_natural_size), get_media_time_cb_(std::move(get_media_time_cb)), - reporting_timer_(tick_clock) { + reporting_timer_(tick_clock), + natural_size_(natural_size) { DCHECK(get_media_time_cb_); DCHECK(properties_->has_audio || properties_->has_video); DCHECK_EQ(is_background, properties_->is_background); @@ -100,9 +100,8 @@ display_type_component_ = CreateDisplayTypeComponent(); } - // If this is a sub-reporter or we shouldn't report watch time, we're done. We - // don't support muted+background reporting currently. - if (is_background_ || is_muted_ || !ShouldReportWatchTime()) + // If this is a sub-reporter we're done. + if (is_background_ || is_muted_) return; // Background watch time is reported by creating an background only watch time @@ -112,8 +111,7 @@ prop_copy->is_background = true; background_reporter_.reset(new WatchTimeReporter( std::move(prop_copy), true /* is_background */, false /* is_muted */, - initial_natural_size_, get_media_time_cb_, provider, task_runner, - tick_clock)); + natural_size_, get_media_time_cb_, provider, task_runner, tick_clock)); // Muted watch time is only reported for audio+video playback. if (!properties_->has_video || !properties_->has_audio) @@ -125,8 +123,7 @@ prop_copy->is_muted = true; muted_reporter_.reset(new WatchTimeReporter( std::move(prop_copy), false /* is_background */, true /* is_muted */, - initial_natural_size_, get_media_time_cb_, provider, task_runner, - tick_clock)); + natural_size_, get_media_time_cb_, provider, task_runner, tick_clock)); } WatchTimeReporter::~WatchTimeReporter() { @@ -280,7 +277,19 @@ secondary_properties.Clone()); } if (muted_reporter_) - muted_reporter_->UpdateSecondaryProperties(std::move(secondary_properties)); + muted_reporter_->UpdateSecondaryProperties(secondary_properties.Clone()); + + // A change in resolution may affect ShouldReportingTimerRun(). + bool original_should_run = ShouldReportingTimerRun(); + natural_size_ = secondary_properties->natural_size; + bool should_run = ShouldReportingTimerRun(); + if (original_should_run != should_run) { + if (should_run) { + MaybeStartReportingTimer(get_media_time_cb_.Run()); + } else { + MaybeFinalizeWatchTime(FinalizeTime::ON_NEXT_UPDATE); + } + } } void WatchTimeReporter::SetAutoplayInitiated(bool autoplay_initiated) { @@ -332,8 +341,8 @@ bool WatchTimeReporter::ShouldReportWatchTime() const { // Report listen time or watch time for videos of sufficient size. return properties_->has_video - ? (initial_natural_size_.height() >= kMinimumVideoSize.height() && - initial_natural_size_.width() >= kMinimumVideoSize.width()) + ? (natural_size_.height() >= kMinimumVideoSize.height() && + natural_size_.width() >= kMinimumVideoSize.width()) : properties_->has_audio; } @@ -435,8 +444,6 @@ } void WatchTimeReporter::UpdateWatchTime() { - DCHECK(ShouldReportWatchTime()); - // First record watch time. RecordWatchTime();
diff --git a/media/blink/watch_time_reporter.h b/media/blink/watch_time_reporter.h index 19cb9ff4..021f76c 100644 --- a/media/blink/watch_time_reporter.h +++ b/media/blink/watch_time_reporter.h
@@ -80,7 +80,7 @@ // TODO(dalecurtis): Should we only report when rate == 1.0? Should we scale // the elapsed media time instead? WatchTimeReporter(mojom::PlaybackPropertiesPtr properties, - const gfx::Size& initial_natural_size, + const gfx::Size& natural_size, GetMediaTimeCB get_media_time_cb, mojom::MediaMetricsProvider* provider, scoped_refptr<base::SequencedTaskRunner> task_runner, @@ -136,6 +136,9 @@ // Mutates various properties that may change over the lifetime of a playback // but for which we don't want to interrupt reporting for. UMA watch time will // not be interrupted by changes to these properties, while UKM will. + // + // Note: Both UMA and UMK watch time will be interrupted if the natural size + // transitions above/below kMinimumVideoSize. void UpdateSecondaryProperties( mojom::SecondaryPlaybackPropertiesPtr secondary_properties); @@ -154,7 +157,7 @@ WatchTimeReporter(mojom::PlaybackPropertiesPtr properties, bool is_background, bool is_muted, - const gfx::Size& initial_natural_size, + const gfx::Size& natural_size, GetMediaTimeCB get_media_time_cb, mojom::MediaMetricsProvider* provider, scoped_refptr<base::SequencedTaskRunner> task_runner, @@ -195,7 +198,6 @@ const mojom::PlaybackPropertiesPtr properties_; const bool is_background_; const bool is_muted_; - const gfx::Size initial_natural_size_; const GetMediaTimeCB get_media_time_cb_; mojom::WatchTimeRecorderPtr recorder_; @@ -213,6 +215,10 @@ bool in_shutdown_ = false; double volume_ = 1.0; + // Updated by UpdateSecondaryProperties(); controls timer state when + // transitioning above/below kMinimumVideoSize. + gfx::Size natural_size_; + int underflow_count_ = 0; std::vector<base::TimeDelta> pending_underflow_events_;
diff --git a/media/blink/watch_time_reporter_unittest.cc b/media/blink/watch_time_reporter_unittest.cc index d1b54e3..06d2a05 100644 --- a/media/blink/watch_time_reporter_unittest.cc +++ b/media/blink/watch_time_reporter_unittest.cc
@@ -22,6 +22,7 @@ namespace media { +constexpr gfx::Size kSizeTooSmall = gfx::Size(101, 101); constexpr gfx::Size kSizeJustRight = gfx::Size(201, 201); using blink::WebMediaPlayer; @@ -808,6 +809,51 @@ testing::Mock::VerifyAndClearExpectations(this); } +TEST_P(WatchTimeReporterTest, SecondaryProperties_SizeIncreased) { + if (!has_video_) + return; + + EXPECT_CALL(*this, GetCurrentMediaTime()) + .WillRepeatedly(testing::Return(base::TimeDelta())); + Initialize(false, false, kSizeTooSmall); + wtr_->OnPlaying(); + EXPECT_FALSE(IsMonitoring()); + + EXPECT_CALL(*this, OnUpdateSecondaryProperties(_)) + .Times((has_audio_ && has_video_) ? 3 : 2); + wtr_->UpdateSecondaryProperties(mojom::SecondaryPlaybackProperties::New( + kUnknownAudioCodec, kUnknownVideoCodec, "", "", + EncryptionMode::kUnencrypted, EncryptionMode::kUnencrypted, + kSizeJustRight)); + EXPECT_TRUE(IsMonitoring()); + + EXPECT_WATCH_TIME_FINALIZED(); + wtr_.reset(); +} + +TEST_P(WatchTimeReporterTest, SecondaryProperties_SizeDecreased) { + if (!has_video_) + return; + + EXPECT_CALL(*this, GetCurrentMediaTime()) + .WillRepeatedly(testing::Return(base::TimeDelta())); + Initialize(false, false, kSizeJustRight); + wtr_->OnPlaying(); + EXPECT_TRUE(IsMonitoring()); + + EXPECT_CALL(*this, OnUpdateSecondaryProperties(_)) + .Times((has_audio_ && has_video_) ? 3 : 2); + wtr_->UpdateSecondaryProperties(mojom::SecondaryPlaybackProperties::New( + kUnknownAudioCodec, kUnknownVideoCodec, "", "", + EncryptionMode::kUnencrypted, EncryptionMode::kUnencrypted, + kSizeTooSmall)); + EXPECT_WATCH_TIME_FINALIZED(); + CycleReportingTimer(); + + EXPECT_FALSE(IsMonitoring()); + wtr_.reset(); +} + TEST_P(WatchTimeReporterTest, WatchTimeReporterAutoplayInitiated) { Initialize(true, true, kSizeJustRight);
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc index e8e6f90..9184753f 100644 --- a/media/blink/webmediaplayer_impl.cc +++ b/media/blink/webmediaplayer_impl.cc
@@ -2124,9 +2124,6 @@ // in CreateWatchTimeReporter() that guesses the existence of a video track. CreateWatchTimeReporter(); } else { - // TODO(sandersd): If the size changed such that ShouldReportWatchTime() - // changes, |watch_time_reporter_| should be reinitialized. This should be - // internal to WatchTimeReporter. UpdateSecondaryProperties(); }
diff --git a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc index e98256a4..73b98a0 100644 --- a/media/gpu/vaapi/vaapi_video_encode_accelerator.cc +++ b/media/gpu/vaapi/vaapi_video_encode_accelerator.cc
@@ -212,7 +212,8 @@ AcceleratedVideoEncoder::EncodeJob* job, const VP9Encoder::EncodeParams& encode_params, scoped_refptr<VP9Picture> pic, - const Vp9ReferenceFrameVector& ref_frames) override; + const Vp9ReferenceFrameVector& ref_frames, + const std::array<bool, kVp9NumRefsPerFrame>& ref_frames_used) override; private: VaapiVideoEncodeAccelerator* const vea_; @@ -1231,7 +1232,8 @@ AcceleratedVideoEncoder::EncodeJob* job, const VP9Encoder::EncodeParams& encode_params, scoped_refptr<VP9Picture> pic, - const Vp9ReferenceFrameVector& ref_frames) { + const Vp9ReferenceFrameVector& ref_frames, + const std::array<bool, kVp9NumRefsPerFrame>& ref_frames_used) { VAEncSequenceParameterBufferVP9 seq_param = {}; const auto& frame_header = pic->frame_hdr; @@ -1267,11 +1269,17 @@ if (frame_header->IsKeyframe()) { pic_param.ref_flags.bits.force_kf = true; } else { - // use golden, altref and last for prediction - pic_param.ref_flags.bits.ref_frame_ctrl_l0 = 0x07; - pic_param.ref_flags.bits.ref_last_idx = frame_header->ref_frame_idx[0]; - pic_param.ref_flags.bits.ref_gf_idx = frame_header->ref_frame_idx[1]; - pic_param.ref_flags.bits.ref_arf_idx = frame_header->ref_frame_idx[2]; + for (size_t i = 0; i < kVp9NumRefsPerFrame; i++) { + if (ref_frames_used[i]) + pic_param.ref_flags.bits.ref_frame_ctrl_l0 |= (1 << i); + } + + if (ref_frames_used[0]) + pic_param.ref_flags.bits.ref_last_idx = frame_header->ref_frame_idx[0]; + if (ref_frames_used[1]) + pic_param.ref_flags.bits.ref_gf_idx = frame_header->ref_frame_idx[1]; + if (ref_frames_used[2]) + pic_param.ref_flags.bits.ref_arf_idx = frame_header->ref_frame_idx[2]; } pic_param.pic_flags.bits.frame_type = frame_header->frame_type;
diff --git a/media/gpu/vaapi/vp9_encoder.cc b/media/gpu/vaapi/vp9_encoder.cc index 41d53675..60f72c6 100644 --- a/media/gpu/vaapi/vp9_encoder.cc +++ b/media/gpu/vaapi/vp9_encoder.cc
@@ -112,8 +112,12 @@ *picture->frame_hdr = current_frame_hdr_; + // Use last, golden and altref for references. + constexpr std::array<bool, kVp9NumRefsPerFrame> ref_frames_used = {true, true, + true}; if (!accelerator_->SubmitFrameParameters(encode_job, current_params_, picture, - reference_frames_)) { + reference_frames_, + ref_frames_used)) { LOG(ERROR) << "Failed submitting frame parameters"; return false; }
diff --git a/media/gpu/vaapi/vp9_encoder.h b/media/gpu/vaapi/vp9_encoder.h index 60e2cf2..2ba6094a 100644 --- a/media/gpu/vaapi/vp9_encoder.h +++ b/media/gpu/vaapi/vp9_encoder.h
@@ -59,12 +59,16 @@ // Initializes |job| to use the provided |encode_params| as its parameters, // and |pic| as the target, as well as |ref_frames| as reference frames for - // it. Returns true on success. + // it. |ref_frames_used| is to specify whether each of |ref_frame_idx| of + // VP9FrameHeader in |pic| is used. If |ref_frames_used[i]| is true, + // ref_frame_idx[i] will be used as a reference frame. Returns true on + // success. virtual bool SubmitFrameParameters( EncodeJob* job, const VP9Encoder::EncodeParams& encode_params, scoped_refptr<VP9Picture> pic, - const Vp9ReferenceFrameVector& ref_frames) = 0; + const Vp9ReferenceFrameVector& ref_frames, + const std::array<bool, kVp9NumRefsPerFrame>& ref_frames_used) = 0; DISALLOW_COPY_AND_ASSIGN(Accelerator); };
diff --git a/media/test/data/resolution_change_500frames-vp8.ivf.json b/media/test/data/resolution_change_500frames-vp8.ivf.json new file mode 100644 index 0000000..a405aee --- /dev/null +++ b/media/test/data/resolution_change_500frames-vp8.ivf.json
@@ -0,0 +1,511 @@ +{ + "profile": "VP8PROFILE_ANY", + "width": 640, + "height": 360, + "frame_rate": 30, + "num_frames": 500, + "num_fragments": 500, + "md5_checksums": [ + "cfc7c8c01df5d173891acfc81fb5cdbd", + "fea732acf6cab7985ec9f4ac4ffec918", + "028664e576624651d9772d9e6a5a31f5", + "3c7fb02a0a8908a0d3b587d67e593b39", + "f625ff74a0150d7f75fe7e7753ceca86", + "5a7fe7a90970311008cd8138ac55c337", + "7366afb94f0662fd35f37c98faa1bfa7", + "85901d9e412dc73fc0cb4bf638677a42", + "67295c02ecb96c022a6305f5bbe7f7c2", + "5665e8f9766cac79198ef90830b287c3", + "6a2969a1f015ba24f796bf99f4a1b849", + "168bedb86adafac71ddad2176e674c2e", + "7f436fb2706b5dfabfa1c0d737f374b3", + "4a221f55c5186219b9db9a54cebdbd1f", + "9b001935eeb24e42f94a571c311a71a4", + "d27fcdd017a7e0a7534f7c81fe59cf24", + "9ec54967ef6aecb7cddad69bd3b0f179", + "017af3d27d8e1601758717d5fd659269", + "309b40a5e817759851cd7fef8d602b22", + "57f03c3d45086cbace89677331ffa7c9", + "0171df9aa97678652eb526d8bd46e5af", + "9a39c6d2faf857b3930fc45ba81b8b95", + "80cc512c9b6b5687f0f84a89dea523ad", + "0b183e2a88b810f16c3928de1165f6cf", + "d998f7ea2678dc3b904bd42e5bc8a7b1", + "2b85db43076cb10e63c08bcff7e05a92", + "837f9127a8891237455aedae4355b6c4", + "16cdc4d508c685d85d55f7b0e3e96ed6", + "47d992382f31cc7ee2bd437b94d8ce0e", + "8f859b3f2517e56ebf5524f25a4994db", + "e0d0ed342c4ff89cd7bb5ce49e070ce7", + "a9c0158c9d98d1b9d2d934892b914fb4", + "1d3453596cb4eca720c7a6d5cabe2e4d", + "121f7668c4ebc2ba333899e29423875c", + "f90dec1d3de5396ebce46366c80c9518", + "7d4428a04f5013d0f92832105b77604d", + "d857e66ff6615f7a2423017285474a96", + "6d32b29a8607add9e9a2bca57c106226", + "7511b584034eb29e2e1d3a046a5623c2", + "d495098dce237b46ef34b47040f74867", + "35d66eb9b7e02592959da8b78eed5b30", + "01415bf51ee7799da173d91e865f153e", + "9d6ca6c1f8f1638c86d187257c57851b", + "bd340d676d0d080ae39a7115c2c9a2e8", + "e5bb6ad71ce2e5afc92e64d2c5c782a5", + "b26b87f57ed1011fd77023c53ed072c3", + "79054b135d26f4432a122b5f0b624242", + "e1e00f4b14472368c58320190a829ff5", + "3d9ebcfe56ee1dbb3382bc1863d6256b", + "d5f28f6de5e308412f340f9b786df106", + "1e188a316defc15c473df02e6e027d5f", + "ebd1e461faa9e047c851b3d0cdb79fd2", + "705b4735e04aa7e9d10ba442b7f8ca54", + "12a4f066137682b42d521056a45c1527", + "b1653ea7d8c7f74cf30e17da8eb34ad5", + "c93a0b4c04e1ff5c561af72de7bc5fbd", + "9d75e53b6eeeea190285287793602d27", + "40589bfd5717a5c7f478f734b19444b7", + "7060138b2679ca2bcee7591ea310f099", + "d4e113568802afc2618265eaed268baf", + "0e297a3d762eaaf880b5979ad7d2f680", + "0ab971dc799d6ca90308e4a218f985a0", + "b613b0301346cbd8edb3b49134b2511f", + "cce9671968b2c18ace9a0f7a837c2e46", + "8f2e8b924dab1df1f3055a694a6dd454", + "4eba7b2e07cf77a8f6a71a32d1b262d2", + "7bdd39737dad391dae19301c079da672", + "280fad8bf781fa4da0b1b073b1960627", + "7b1a8c4c5f442eba45eddbdd68459610", + "cce1bb08fab54d4e8d20c5e6cf63ea65", + "4986022ccbdd6eae31abe1381853e220", + "fced9dd693d3cd44e9876725b316476c", + "cf1c0ace3d351e7fbf6f76b1e92201dd", + "48e760116e9d606e689f545cc04d4df3", + "3c2c02cb63f813b9956f577444907c46", + "a6505cccb1bac7da340f25df6c643cb6", + "8363005bcb46444444b58f4ee6f91373", + "ad3b9e7f3b1b3325372d53886628b618", + "fdcf1b36fd54498c158af111df66e554", + "c1103c9cb9c762c88e32a40da4f9cc2e", + "7a57f8d4ab9fb0204877bac797276f47", + "9d9404eae9dc70f00569850d10d002a1", + "51213ff244d4c84401d1248afc731f40", + "32345c6758e9d2dbaa504de567b7ceb3", + "c8a1a779aa95d72d007bdb6986430bd6", + "a46926fa0ffdca5e0be152754011f76e", + "34f6016b220a63ca98bf46c37705dcca", + "5ac6436860a0b339a7649786fb016a71", + "576c505c7c6e8e9854464d9f4063acff", + "93bb6b272c312100a308b5a93be79451", + "574f1909a1e4bfbfea7f55d2bad66ccc", + "ff1d7d95b71b1a6429af8e9012bba26d", + "dc06ba1e7d8778f6aec4e07cb618d5d5", + "60f0e0ac9098b679c1ff4eef5b31e16b", + "1d9653e4661357ab025ffd0a498de895", + "f61f84c50ddfb0bbf47b16226ac79cc3", + "91780dec7ca43546ba40cd97a65762af", + "9a42f2c07787587f01da51b04c188584", + "84694cdca05d65ddf36a3deed878df01", + "ebe2033f60e9842090fba95f0470244f", + "b4135c08c3e9c61ee47df38579b36f1c", + "5745aab5efa76098d59a798cf544dcd2", + "3bea433364971624b6ce12712c20341b", + "115496aa4266fd1953503e87437cec2b", + "64aeb343b868044278225a71f759cc18", + "756de63e61d4ed6a41fde0d81dd850c6", + "8fa20e70c60c2524cceb516b1ef79373", + "858805d6f7f3d92f4f4dd0e3cba9d0d9", + "dceaa1d81c3109e5bad2c0b9a12b7df7", + "e046f3d441fabc97a07218f6272f97fa", + "d7fabc670307bf4f7f82265192fc27d1", + "a8b7227bf11303bf75796c2e6e3089a0", + "a20495dc1548bf6818a3a5497cf8886a", + "a7f9a348a36a275888ad222d590b536a", + "ec39ea57e6cf135c35ace2bd8b1c5c23", + "21b67ecf11ee5f5114e3d9f387b31697", + "16ab8aee9a575344beb53a9f65565b93", + "5f98ec9538dad1538e786c789b40becd", + "ae85b8d0925bb4a79f7342b22b386615", + "465855a9ad479ca1f05177c9e122c62d", + "77cbf0583669a9cabfb1f0a888ab89db", + "7fee5cd180cea04b1801b1a18206b315", + "3fe10ecbb689fcfc100c18114d9fa25f", + "e69f8075a08bbb997ec6dcc635a21e7c", + "270c65f7948545befd09e0acc5fab306", + "f41e96447756435a822f46436a209b9d", + "89223bdd46290c122a5a0627bef09d43", + "59125040593568d2293ef68863dac4f2", + "d359db7ddde8ce90b5d219793b4c85b6", + "a92754513a02b3a175afa61450667ba5", + "ac967c9237f646c9e172be68c337c34c", + "7a84eeb2236b2a8ccd034245a25324c4", + "27cee3f9e6d59ac804d3560a68a0aeeb", + "fe3d52382dd8bec3816556555b5b5069", + "105e3337c4eb14c91e7e090552f1033a", + "28dc289562e55cddc4262e8383d08400", + "96244f9c3a04d195a1032437cef6aa32", + "2450634555cc552a15a2c6f6fc76163a", + "44110b9cd4e504d6c8725218fef4841d", + "f8c6b1d84aa5bc7a88a5ab6eb6f26e0b", + "0ee9e1c60b0d724c7fdab4e7ac199763", + "cfe98dc0ef6f9103859df3756c2e9ea2", + "95ca65fc7df2e476e1e9cecfc28541a1", + "26f3ba6992793e1103c0b929439bfe44", + "acbb801f7a0d55ba167b3584d5b2cb6b", + "2ab69298ec14d612c2f64645651e2a3f", + "074ad6a90120ed03a89b02593feff5b5", + "520cd18577da34204aacfeb99415a0d0", + "1b957bbaab8c9d40891a0c8557f6a3c9", + "ddfb045abfa17aaba0edbdfe67da3ebf", + "dbcd112581731ea96fb3a7240aa8330c", + "ce8c7498ad136505389ed7e03422ac04", + "ae75753b310473b468f2121274e36978", + "2d05d338bc1904f43420765d2c322ee2", + "535fee70e62e22a33267c53309d1e1c4", + "013d39c3e01f457c6d8fd6fedf5117d7", + "b934fcedb0ba5d29d539dc8180d6e9c8", + "f83fba6e8b00b33170e6d0b5d02b6ac4", + "4c8ef856871a3dee87962982f493c2bb", + "ef2ba3c66d75e9f90e707e6457641359", + "15f7f5d9ee2e75b82a6c62685aa4cab7", + "d8a6dafeb430da5e041cdf50c86b7df3", + "cfc7c8c01df5d173891acfc81fb5cdbd", + "fea732acf6cab7985ec9f4ac4ffec918", + "028664e576624651d9772d9e6a5a31f5", + "3c7fb02a0a8908a0d3b587d67e593b39", + "f625ff74a0150d7f75fe7e7753ceca86", + "5a7fe7a90970311008cd8138ac55c337", + "7366afb94f0662fd35f37c98faa1bfa7", + "85901d9e412dc73fc0cb4bf638677a42", + "67295c02ecb96c022a6305f5bbe7f7c2", + "5665e8f9766cac79198ef90830b287c3", + "6a2969a1f015ba24f796bf99f4a1b849", + "168bedb86adafac71ddad2176e674c2e", + "7f436fb2706b5dfabfa1c0d737f374b3", + "4a221f55c5186219b9db9a54cebdbd1f", + "9b001935eeb24e42f94a571c311a71a4", + "d27fcdd017a7e0a7534f7c81fe59cf24", + "9ec54967ef6aecb7cddad69bd3b0f179", + "017af3d27d8e1601758717d5fd659269", + "309b40a5e817759851cd7fef8d602b22", + "57f03c3d45086cbace89677331ffa7c9", + "0171df9aa97678652eb526d8bd46e5af", + "9a39c6d2faf857b3930fc45ba81b8b95", + "80cc512c9b6b5687f0f84a89dea523ad", + "0b183e2a88b810f16c3928de1165f6cf", + "d998f7ea2678dc3b904bd42e5bc8a7b1", + "2b85db43076cb10e63c08bcff7e05a92", + "837f9127a8891237455aedae4355b6c4", + "16cdc4d508c685d85d55f7b0e3e96ed6", + "47d992382f31cc7ee2bd437b94d8ce0e", + "8f859b3f2517e56ebf5524f25a4994db", + "e0d0ed342c4ff89cd7bb5ce49e070ce7", + "a9c0158c9d98d1b9d2d934892b914fb4", + "1d3453596cb4eca720c7a6d5cabe2e4d", + "121f7668c4ebc2ba333899e29423875c", + "f90dec1d3de5396ebce46366c80c9518", + "7d4428a04f5013d0f92832105b77604d", + "d857e66ff6615f7a2423017285474a96", + "6d32b29a8607add9e9a2bca57c106226", + "7511b584034eb29e2e1d3a046a5623c2", + "d495098dce237b46ef34b47040f74867", + "35d66eb9b7e02592959da8b78eed5b30", + "01415bf51ee7799da173d91e865f153e", + "9d6ca6c1f8f1638c86d187257c57851b", + "bd340d676d0d080ae39a7115c2c9a2e8", + "e5bb6ad71ce2e5afc92e64d2c5c782a5", + "b26b87f57ed1011fd77023c53ed072c3", + "79054b135d26f4432a122b5f0b624242", + "e1e00f4b14472368c58320190a829ff5", + "3d9ebcfe56ee1dbb3382bc1863d6256b", + "d5f28f6de5e308412f340f9b786df106", + "1e188a316defc15c473df02e6e027d5f", + "ebd1e461faa9e047c851b3d0cdb79fd2", + "705b4735e04aa7e9d10ba442b7f8ca54", + "12a4f066137682b42d521056a45c1527", + "902c3f8b6e6c164a1f1913cb21d04b9a", + "dc69591e53c23d90896a397f282750a6", + "728ff238efa9d5af3c2e9227ab88fc06", + "2f780a3eb220c9317f155e964ea22b23", + "2c1dfc5f53f995826c22fa5304cdd986", + "9e5233c231f08f6334b43f2778c06ddf", + "0b049a62a015a63cd7ecf0f838524c89", + "3bb744884618842de46cb7d74757f331", + "0964a2ae89efa1d91f1a1aaf9de9c283", + "68a0369624cda3cf1e2a57cb508dd942", + "e977cd7b58c362fb34868bad7160a3d9", + "8c27d62a07eb154a9b06bd80cb28d8e0", + "1c18270fe6eb7377bf8d66a109bf8aed", + "6d22d39464d266b12b1fb7e6f0d6d3cc", + "3a118914d8f8335d39fdde035d2f6710", + "072bf61441ab279f1faded06532e8de4", + "93482a0f2e62a2c8fc7a05864f63cab6", + "4bc7264f37a668b4b1c007dc402081b9", + "7a3bfea3691fd5b1785c13d0c9adab62", + "306317e5efce2e1fd433a8cb447408f1", + "99b1ac32e92e06c7a18ac788a6c0a38d", + "1f82f4b638aa8dfefb244b1f46504426", + "6548b0d17d2c11273b59895d253a615a", + "04efd15bec2e5b0987f8b2ccdd1fef22", + "bcf1f437a060058527316359f8b1be58", + "c42f55cdf4249b9a3c7899482b9e38dd", + "432485bfc54915ec5fed0d1d146e9ea0", + "42de4afb22eb44bce66cec02cf8cb5f8", + "0f201d5e989964ef744329887eb6d6b5", + "1d9037f52927d3b3dc3768aba8739fc9", + "739829890ad20f2717199e8b223157ed", + "083ee75c904c4b3300955053af37341c", + "20bbdcf90e3f6a8def7532e541c32c81", + "cc9a644c37ae199e20bbce5be7839de1", + "804e9d4d21aae080d4c36cf0cab408c9", + "cdb50250e45720c86e7f4d87d37d6174", + "aa580d44950a761f755fdd9469e5704d", + "8c3c039df6af04ba6fb0baae1a8c8b09", + "895d82addb2dc11c36fb646bccb38c5a", + "36cfc5de53e2162e3a335e088e7cc265", + "a36960488e65a7cea0c7e72aafc9d3fb", + "2fd5508879019ef4b7594fa2ce980a73", + "593ccdab5d7e41a508e5769dd0401dbf", + "40e7f02535091da5696f437f466f7d98", + "7b98d3e21e287e9577e6e8230d30b249", + "cf92eb5301c628f144c19dfd372a63af", + "ec306b12eac6c06a1b772d5f4989c3c7", + "f94472e283a8aa817456aa407b7ebd53", + "436453c83fb7ed25865e467172f2a6ca", + "7fe23e53eda51155252a08acdd5e6840", + "0a9f76e4ec8908ca6dfb7b8387484905", + "1dd6bd965c539cf759ff512c91743769", + "3e78aa5e0dd3b5024d09675a542ee184", + "6e2ee5730844ed90032b9090e40f941b", + "b211fe95cc15f2711347f6df3c8dda4d", + "e71b47948c9c529d7844ff8e3d80bfae", + "b37764fca14d0c95a7937ed76c111ebb", + "1c06af05e2ec6eb9dcc56b462ca2f5b9", + "62968cb5dd2d92344433dbf91410a763", + "4b993e45b7408c193c1ade52cb895bc0", + "5a9051dcf1393fb6d281839422466b76", + "53dca69f9cf609f2f0278760dfe1a1f9", + "45de94cd741f4e13774c48281aa9d088", + "9c74392eea89fc4dec2850a490577139", + "c6c5f86967795370722f419ca4e1a785", + "a5dc27026375f0fe5976aa5968df5de9", + "5b3a41441a1a3aed34da1c28886fe8bd", + "ac2ad9e7dc19ac5a29e02005133eaff0", + "ad2d22a58afd8a8fa0b8590bfe813a74", + "69fb11d03d939a371712af802fa31f26", + "420e2a5aa83e44a951c2b665ea3ef8f7", + "9bd2b8f96345ac614bb8df9dc52e2e2e", + "119e88a2f9aa54506d9141a719ffa48d", + "4df4c3fddc37b50aafbcdc38fef4f817", + "58dada59259063f202fa939dd1f700a9", + "38cee2c2788dd3c0d5f9d095f21472ce", + "6f4d8e631f548b53d325f3486b2d925b", + "915cc2833dc9d9ef4e305f309c74cf96", + "315775b58d74e0578bbd3d2f56c446c8", + "86ac0fc851764fafe05e8c1451e4cdcd", + "af766329bdfcabee6f97f62ba8d435b3", + "1a8af7a329c279b7026a6506a146770a", + "eb8c11fa949e2fa9bed2b10a459001b6", + "2af81c1855e18aeee5ac31d5f704ee4e", + "89605144460f859a2140f7190dd5667b", + "0a40134baf3682fc75294d9bb81d53c2", + "db134413fe240a140ad05ed1c6821d87", + "d77673588b13733d72dc14e21a81932a", + "ff1c572d720225af24c5378d5a1451ec", + "dfbbf4d32cfef4230b1b78f12d25358c", + "53820e071739d4742715fe8cc74095c6", + "aa4a393de1566d4318a5fd860f8569a1", + "dcb6cda045a72b05705a0148fd222285", + "f5343627b67183d6ef7e5ee97a4fdba6", + "ecc022e3362cf36622725c1350107d56", + "8a5420905f02fd32a28b38cc2379b45f", + "f1e3be4a6e6c91430742fcdce9c8da75", + "303958e5bed76ad0134eff41594fac1e", + "c21a8fe6f5e71463c0a17a8b0a56ce0e", + "5ce398ad3e96ccacb9829c8868ad155d", + "ded9cc77d36e3c4a1ec6c38f4929f649", + "8391e338b2d9cb60ffc4b9e58cd5a547", + "a10ad67b46116bfa8c5dddf277463f20", + "47f0e14bd61beafef27b5a487e1e3214", + "f0c60d6176fbf141c0af734c101f62b9", + "50de7ad45c8e308b02b6f3d542aa0889", + "5df77ade2f05eb3be076d7f93f60b251", + "16e4955a7a691687842702d09d794eb9", + "e2b748be727d28132906c3e93ffdadfd", + "13cc2669f2c7ec1579d427eaaa777da5", + "9a23be5ba0e4a60281337861c24dcfda", + "f2686549195a08362afa1d0fb2045aa1", + "ef11d03ad6cad92a26e68b793c32496c", + "82125b8f9374b1a0c46e9515324bdf92", + "1fd635622f8693babf32adf80faed258", + "2772107ba7454a91058ea980146dd9fe", + "3b40e5f2b66b8aaf55a680a4012e39a8", + "2fba9c70376d01b4142a8f0d8550c00a", + "38505a7e5549fd81f2a28e48d91b68cf", + "872c26e36110d034577125780c74408d", + "03127f5a688a93adaf6fa7e04df3446e", + "7a9a73f814baa01fd448fa7440e8bd92", + "fbcd2f1e882a5b6b15540de8a569a972", + "23e80d85b919a20492f4151a8bce5445", + "0e8281be3188ac5045ea71c122f16ffa", + "33b0fdfbd027670c7e9d93c32841631d", + "4c20f0c8f288d24c6ac381ecd060cb7d", + "23d108f294b8671415a307d9274f0e6a", + "dc84d32b3c30c29b168df785f4c26358", + "452779f536a1ec787d3e127b12c2a006", + "7b7e2d5ac694d23dc3f1c9171fbc32e6", + "37ed5d932a0fafe688c738f8ddcaa888", + "a3399bdac31d5b0524df1bf87f9e3e89", + "990dabaa89e2022e4e16155e38434779", + "bbf5a23d0ae5f48855e74a4c22635313", + "ba99b9966b511ed4222ba70c501689f9", + "0a95268daab9cc070f7ac53f30a79ba6", + "a7acbfd9b1b37f19debefb260e6a54e6", + "1c61c151baed5e2d5f5f167eef42a4cf", + "6ef7ad1498aea10e2a560ed705bf693b", + "17d9820be52c10236d59fd951ba59043", + "fcee45789fc2c821ac389676fa6a857c", + "e44be0e708654f68b372337ecd859bbe", + "c57745ec1fbe4682b95ce45d6d5ce7e2", + "248bac601fea231d117c797d8301dfca", + "f4c0fc578f391191c78ada804e1ea281", + "ccf1e240ca4e8b32333ced1e49c9602e", + "97430e9b49696e72f7ec8c4185622441", + "0ab5d731a03ddd1fbbc506d5d1115103", + "0a4a6c26b74db3302831d4a25431caa3", + "189c8901904aa4056e887d2b55d7d364", + "1b4d4a0b0a78c29e0548347fcfd09f2e", + "9e76e5c2a413d5662388453dbfa03af7", + "f458c43b17fa9e3e0c06320439bb9f15", + "541888ad21f32fcdda99e0f73d3180bd", + "9012f7990526e055c340e6922e20c417", + "bdef87ad198620e0cde8316c26ed938c", + "3943beb7a912a206dbf5aa8b75413983", + "157f81c3f5e3720c171d7fdf4985ead9", + "27ebf56cb58a12bf928d41f4b7e0d1ec", + "ff8cb8ec21ae3cc0fe767b3a652d477c", + "b65fad736d43d304090f96d4babe3b0a", + "d0104662f99e1c1331931f6b8230cbdd", + "4abd720941dc5bf1135a5448b165403d", + "084de12c74571e3c9c78fce3e0e85671", + "02ca33a57207d254d7fbfa6e52302df8", + "e72629b773a829a1962621b2154c854f", + "fe842ece48caa4a157d73bc7aa02bfc9", + "20946b7ebf8fdb0e42c9b30ed3d90115", + "4d6e816afb6fdb31899f6a49b39790ce", + "e790c79cf61b46c037519fc1dcd27624", + "71a8d6e906ca60ba65734166b16de010", + "f644fb7ab7cb8a07b3ffcc660ffbb699", + "b74af853e209681d5e0aa0f5f710dbd5", + "7edd0cee3f8e1f3b7636b420ec239fd3", + "65474278cb1eb048b62405f82589f576", + "c3fb2f8c1798721353453a593328727d", + "4ebf46878de5db067e41de50de6a9921", + "f0daae57ce046a715a54c159467d82bd", + "881818bd394cdf032c27578fcac08761", + "9bdde399128b0b6f04ae4c64424d89e0", + "a15482bfcb23ef2d022c048a342cb777", + "d6c7fc3a5ff018ae3ad975855d3ef26e", + "c434cfa0808a34632191a640966d5213", + "afc874fa8fc1c951cd8fae0b56d5b58f", + "8c8d25f0742a6b07afef1c2eb20f93b5", + "4c629f6a8c9dfd73e6a3356bcb24aa8c", + "ddc2aff543ad980dd9be704d411dfb57", + "b1c6d4171cfbe7d97a8e3b2783126474", + "0d11048e06d4610750d0d204b243addc", + "731ea6f6a81b428e0a0fe704a91566f9", + "ec3f89d19084169febf58088bd68a7df", + "eb92025a784b1b8e6290426fdf5d1443", + "21175071a466051f180747832eac7afc", + "93680feb28f725a068139bdfa4aad071", + "a35acb13bd9c12b711cc082e55a96b19", + "62aaa7a9521d3d2384db463d257d3a7f", + "74b4ffd3b271b9701a849c338059b2a3", + "be484ef1eb8afbc4aab6d83a63323f72", + "f8c2252224f18fb0a8038d84bfbb94ed", + "ce878159640e29ad5d83709eb162c12b", + "03dbf0f777ef5802a57d7183afe19a1d", + "80cfa7160b1ee910a868cb7d8063b97e", + "1f55cc11af9f204352fbe05a65c3f176", + "dbc55e50be8aab58023c55f8eda432af", + "18234a13e9aeb426983607660a342383", + "f5b5b5f9013edb066d2523f09e74dddf", + "41c49fcfa0d2e1b37d56da1513d6a783", + "6edf01bda06214d5cccdc6aa77c9613c", + "5509db757c567bdebcc8c89626d53bb3", + "754216b785549bf168a09834e43450cf", + "9c8e872b695dd439db70527cb8a51bf7", + "b3354769717dad5ae299a2b9a5e5e4dd", + "217772393562065c1898f4e3c1d497b0", + "5f4b07e2f431b498c5fba8a27d0ae4f8", + "26d967cc3a313743aa4c645b6f758b7a", + "52fd4ee6f4cb2ef7e846a8ce00c833ce", + "831a7dbbf364f5695c1e6b5ffd7a598b", + "0ed3412626a074960f755de9cae88f36", + "35d0e8ea7ef30d1d5e0256fb5fc1508c", + "86fc72cb12a7fdf4469374414574869d", + "a51decc104eb1bc922060acc126e5d72", + "2b6ecef4925e482efcf84c27ed0e7b93", + "07b369c517b7dcb32cd23cbb0444aaea", + "446f6213fd7412c5d76d97527a91f3d4", + "e276c878927f74e0da3fe0d716ae6746", + "569868413e4e426c15a3621e988d60f0", + "f988ae602ed9344106a02387a05ebb2d", + "e861f42357f609c4e0c6d551b25d2101", + "f37977cd6cd50fab1007256882b9d159", + "485de62c60818b7b87f7e95702f67d65", + "1c60ef1f1339d8f825dd3d68a0c49ebe", + "f92c140b6541f271e090158649e96720", + "1f0e901582271380f281c64ed411507e", + "f5e47f01095292f013259754779886bb", + "b56c6c39b81b8d5fe2fafa1c6781e42e", + "e50fff16d042df5323fa6ce4a7896880", + "5b13dc530c7d0151cf48efd6472c7ffb", + "14f1fbdf8bd32bd9d7f1d259500ee92c", + "73bd236f7146fabb60ef417469e3bc13", + "76e2ead478bd57ee8e0b649237ce1700", + "1b3837d69ccd753dda93a10d0a549522", + "ef42fac390f41d0e8459df62bfff1796", + "181b99163c9a792590858bb8e12c65f7", + "bfb16a458f1d094f75393c262e62b29b", + "0f16e76475510c096c5a7ce8b4c1baa9", + "4d240c7b7c75241096c4e51bc3712bf8", + "3cc9756f9150f4a2ef0bca5c353ebdd4", + "621d8ae04d6e60c6180e6edf8a34343d", + "fb5e7a3a6cf8b34410fa29a22e3c8ca9", + "26114078980d6620e9b46e23226bbe45", + "ab203ce0e4ffc0df848e1fdd70c48256", + "c141cd0e5c2dcb70ff4d8b90edc3c87b", + "46166205aa6704bfce88eb52643c6efa", + "81ec211dda25377af34cf1b20f1c1db5", + "55d8bcffa8b9da2f9f5f176d3c45110b", + "e46edf0c4302a08b8bc5c5f6ec9452d1", + "56f07d54b23f6bc541def43f39e22e72", + "713c54b4daba154aba01df2a4d873c55", + "a71ef6f255008c7f9947bb1407e01a04", + "1fca8a7f306c61e9331b5df2a4410c7f", + "26ddad1f8ffba7a2912e540e1fc0f761", + "ca04c80483ee9af38dda331b13fab89b", + "b08e30b0b2ed465feef4a84fe2ac7f43", + "fbc22a4cdd447cb846f7d18f2f33dc08", + "0679834064187259281f82a7b7cdcd2c", + "7779360fe115997464806f67e70ce8ff", + "8b26f4c6ba77dc54312564d4528f0194", + "fae4f16afa9b38fa73d97ecb663cbbd1", + "d5331a50c5e321be5cf39ae610b81014", + "dbb42ef3be7cdbc142bdf1408d330b9b", + "beb7c246e35257d60ea10b61ac76773a", + "15e84636f69f15e964a76cebb4ac59cd", + "3e7b8c9f23d607a550e7c9cbe05c3f18", + "e73f61bb02b76c75f85a81dcd3efba23", + "3c5a46c6f1a552ce10ef9f7c03285355", + "03f8b0005c372f050e4ffae20dfd5654", + "3657cdccd02beb5aa3321f640f6745e9", + "d13233c2227d842f5ba3928517f3321e", + "8957f452b7cc4634430006d91681fa1c", + "10861e2b072783f797fa5cf4dde6f1c7", + "1c9c21ca703b58db175ba319db2abd9c", + "19918fd622cd980b8ecdf16e48e839b5", + "f37508b6af61a05f8f65f23aa34519a9" + ], + "thumbnail_checksums": [] +}
diff --git a/media/test/data/resolution_change_500frames-vp9.ivf.json b/media/test/data/resolution_change_500frames-vp9.ivf.json new file mode 100644 index 0000000..7a36212 --- /dev/null +++ b/media/test/data/resolution_change_500frames-vp9.ivf.json
@@ -0,0 +1,511 @@ +{ + "profile": "VP9PROFILE_PROFILE0", + "width": 640, + "height": 360, + "frame_rate": 30, + "num_frames": 500, + "num_fragments": 500, + "md5_checksums": [ + "e3cad482d335f56944a14fce16d4a94a", + "5d4e15318f41dfe23aa2f44780b6e390", + "60042d1f682794a4e450337bfb930894", + "735c196a941276b453ecbeb119c28b61", + "33f38a046d682386f900bdbc5ae010fa", + "0fc5ec85b302cdc993fa986d6252b1f8", + "c3eeaf51e637cb2bb6dc91f2047b30d0", + "ccae76e6f3d044bdc4fd2b710c7eb99a", + "53fb804b21096123850818fc1b629c27", + "2b94e5e06154464f44301ab5b9fc6441", + "7fe3696e2290abc1553705643cc286ee", + "2eb7b0b62f95ef49a08a4728003ea578", + "4a09401f7eeee8a10ae3db1b19dc20d4", + "49cbe29180f83db97bb61d5b215eb042", + "21527bfff932d6d0ca43fe258bd329e9", + "f907ec1d7f78f4f6570aa44c7998d419", + "b3c6717597af3746d2d2e2bf9ea7477f", + "071bca36c03c84b4cb73d9529bf949c5", + "a7560eaf19e528a89fdb703ddee125de", + "c59e6ea9a88810a2e0963c08e06453ac", + "b8f561cbe3b443fccd040ad618b18961", + "ebbabfe158de7225def1dd19e46ac016", + "fa96a5de6a59e59e2d9fad61e0e57426", + "fa04cfdf1503f2ead1c11d6b6b7850ce", + "8f6f1af2779e36140964d81915e1f995", + "3f59073ee8bf07e53d90b019965f58a1", + "4d70abc5a8534b7435860011ca8b01b1", + "ce2301ac1680ee87b36a2b9134422df2", + "0c9e16cd6f23158f886bb9e6b3405391", + "b562f0bf7c142b02628b187aed8aa3df", + "d47c1a77bc9d53af4ab732b2d9014624", + "bbca0815fdfa19a9410cbb9e99ff66df", + "07fbf8688c9a1f86c85e4062ca75cbf0", + "94293234b797f090b233331aa8d51adc", + "5c61a24613a05d41c122ed9c92f97752", + "a278dac9c38842c463831e146307b37d", + "b0091cfe727265e3bbc22b5ba9391ab1", + "3d6b49d9b3b86da681a4c62b4e2c0195", + "41c330be036be702d292aea609f11d3b", + "8e4539ae477b05d6cee6fefcd827517d", + "e47e9f5e1c9e25cc325d27f231509ceb", + "413082fea1cf144125f3d244ee801971", + "34870bc7d6cdd37a735082d5c6db050e", + "80f3913096c1a107405973022bdf03c0", + "9aa7351b1123bc7376256b020049cac7", + "4f49524c6efe4d9a1279527053579fae", + "91010b66e3fba877776096e2dda86a6b", + "b260fc64e440d2d4e62b5c809a1ce78a", + "224711b4abf0c0483d3f745f4a0d6f49", + "433573f679eece2371c01f8d8aafbdc9", + "e21e7fe955f349c667272f9804d2a08b", + "aa75f0d0f64a7cdf2ff0a0ef2c86fbc6", + "303b23eddc42a2799fb50bfe19683baa", + "ed4e3f45225385ebf0d4eb92e28f24e5", + "b8bdf5fac272d062acb28c88b2099875", + "cde0e122c43b9a4a89c66bb81329e4ae", + "cd8b44f34a32ebacfd96597968bbbf39", + "23d3bf73b0f7101c2423173def24154f", + "b248e43efadd0945fc23495ad08f681d", + "e3564bcecd99a8208792801d7675ab7f", + "0f4b4b9c2908ff0496301de75ab8f64f", + "eb06c3ec2587808838e9b8553422fe62", + "a4df3bd058b8fad94a6788c72c6fe2a2", + "0fc8cb8ddefc196c0c0910c5b0203f94", + "672725a65fa824a24b29134f3e30415f", + "2dd199c2255e86dbc8df24f7a5df6bb0", + "90c876950798645a602987fd46db3ee2", + "6ae98c70874ac83c86ba4cefac8bff51", + "aeeddb41caaeff7f10fe0b49855e3d35", + "582000a17e8cb11d3db21b1e870d27bf", + "3bf96640bd7cdd6c84ccc8fe7637b783", + "c573b801cd714b9c91c47d35b4f6b52a", + "794b0f50281b3f94e9f6c52958fff32b", + "9a202428aae5181a27329e7b0ed9e99b", + "2086a740c30f299fc7699352b6e68c09", + "72762badeaa8a82b2f50692b7d219b59", + "423d5492ada3094e2fe704dff3c103d0", + "bd781c15c2701949f31b8e83bfc09a42", + "1ffbaa0296033a53c6dc9812c4d9902d", + "29e6927eb6d6803630f90f835a3f66b6", + "024acd9ddb647d3527d05ba5f651a797", + "b456d1b85550dbd492454777a8506924", + "6c2039f8ea66298e8fc66832be805308", + "88e58a4277c2d6d98be5e1891cc7b89d", + "4ccf371ad78d7062e0cd439d7feb0e81", + "37c6a6f4edbb2952ed7e041fdaab7e78", + "5d9b98302fbe6b19daaac2a207884811", + "60f880036a935bdf9cd925889c79f0cb", + "7b5c52c78e85c7cb7b92b2f24044fd92", + "d4a50c8d331291e816bdab422aeaf558", + "89a655be0d30fd11c6a93af30c77950b", + "07edbaeaa97eb2fc6fa066f96086dfcb", + "db8a7a03cbe027e59771cba6637289f7", + "fdee3be8c04c07fd233938401699aef9", + "68d1fc71c1997e6b4edf61e9a706adb2", + "c279aa34ee386128443f3144fdf8a74f", + "ec2e1e6525189b16d2378663f127e6c2", + "cae604f7ea0825a9e712d8eb5adfc904", + "7a5856e76a20c96b51da2e4c5a60db8b", + "3ebf396e962ea50e64c95e267d29ab4c", + "420467727f319bebc88f3a0ebdcb3eb0", + "12c7fb0013d2291810539c0158012471", + "af2da339d317592c858881031907f48b", + "99b6704e1abd6d79608791eab964768f", + "2b1af5c369ee0dda582ad1faacd80147", + "44efe4a149faf50a5c8274c819d5b0e4", + "a330ff9e40d75a3b4e541a8f427a6eed", + "a9bc6bc9ab67c549e98cff2fb04abade", + "743e885b53978fb3405be01d9243fa52", + "fab6cc95827ffa28a918e90999491551", + "0084e4402d82d39813a2e6826bcfd54e", + "e7484bc1c5f6c18cc250ee89183e6da0", + "6d0b23d398c977991236c458b40a5511", + "13d17c6209137cf7d7529aeabc72fa90", + "1da7fc5fee2a55355093f4cb6e8856fe", + "81a81591ecfe531ca05d7b7573a0c1e2", + "2ce4caf7b299c0e2ea223a817a2707b9", + "ea3398fc2003b707993b3a9134b15227", + "7515235a1736dbc620bad17097c70661", + "06b8f5e2c7123cbd61b3318d43af7021", + "cae379b82859e2952db3061e1341e23d", + "447970aeea78f9608219d8b4d9dd39f9", + "56fac843d69473d1d1d5b3db4d099267", + "d84c5d67606bff1aaedb823a1282650c", + "dcbb1f0deca158f8839a29b6431e7ec9", + "62d68a69d48e8f81d159664e35d7dc5f", + "e7b9a9f8b0189c526fd123238398b1e0", + "463268fe364df91f1f697f450516147a", + "224565c215cc785dd57e52bb94faf333", + "42d93886d8cf8dccddaa8b76d6d88eef", + "beef9c65807fd3751470d68cc5d3c3ee", + "61f3c89c07d3c08caa714d0bab7d7503", + "228a9f19438bb2c761a8ab81ae1f8da7", + "728a3f1478904df2374577eb6c68e9eb", + "93a07e330d731f7691992e3f03c81f10", + "1b9b37a49267e689fd765860f5a7b1c3", + "c62d6e7326324a7242cba14f3f930c3b", + "ed5a49a7b588807a6160df3b379aa0a8", + "1158a5a289013efbc3b359440710c1c9", + "705b92edf4f8172c21702283aecfd4cb", + "53e1bd166c956f9b85e8a6d40c9e1d2e", + "97433314f057d9c2041cf0bf855128ca", + "bea08496e622dfecb7b36268f429ee3f", + "49880f5e7b3ed2954959e8fe988ac92b", + "72f3946aec15c85f807a1c441d22da5a", + "35c90be6bccf29a49f9b91529a148929", + "47fa9f0e03cf726e5ff44f88d3c79787", + "75fc93b60496b8c21f8a922884bec630", + "2b37a9c0a6bc88a6fd1fbe4475b7c8a4", + "0dfced1554844dd7fc46401ad27afa82", + "fff0d0536af0250973fb5c6e4680c01b", + "302e4d3249eb57bd7f24f504533f2233", + "cdbe4fa119f6bc98c507e65e86a5dc23", + "c55c582a7995d48f42e081e2071307fe", + "4767cd600153dcc2178674097efbc057", + "3955d2878fb4c57cd30afffb6b387f78", + "8efe7549d42ca848c5606cf826e496ae", + "0502bcd93b0cf5312e1e32cb9ad90329", + "e3cad482d335f56944a14fce16d4a94a", + "5d4e15318f41dfe23aa2f44780b6e390", + "60042d1f682794a4e450337bfb930894", + "735c196a941276b453ecbeb119c28b61", + "33f38a046d682386f900bdbc5ae010fa", + "0fc5ec85b302cdc993fa986d6252b1f8", + "c3eeaf51e637cb2bb6dc91f2047b30d0", + "ccae76e6f3d044bdc4fd2b710c7eb99a", + "53fb804b21096123850818fc1b629c27", + "2b94e5e06154464f44301ab5b9fc6441", + "7fe3696e2290abc1553705643cc286ee", + "2eb7b0b62f95ef49a08a4728003ea578", + "4a09401f7eeee8a10ae3db1b19dc20d4", + "49cbe29180f83db97bb61d5b215eb042", + "21527bfff932d6d0ca43fe258bd329e9", + "f907ec1d7f78f4f6570aa44c7998d419", + "b3c6717597af3746d2d2e2bf9ea7477f", + "071bca36c03c84b4cb73d9529bf949c5", + "a7560eaf19e528a89fdb703ddee125de", + "c59e6ea9a88810a2e0963c08e06453ac", + "b8f561cbe3b443fccd040ad618b18961", + "ebbabfe158de7225def1dd19e46ac016", + "fa96a5de6a59e59e2d9fad61e0e57426", + "fa04cfdf1503f2ead1c11d6b6b7850ce", + "8f6f1af2779e36140964d81915e1f995", + "3f59073ee8bf07e53d90b019965f58a1", + "4d70abc5a8534b7435860011ca8b01b1", + "ce2301ac1680ee87b36a2b9134422df2", + "0c9e16cd6f23158f886bb9e6b3405391", + "b562f0bf7c142b02628b187aed8aa3df", + "d47c1a77bc9d53af4ab732b2d9014624", + "bbca0815fdfa19a9410cbb9e99ff66df", + "07fbf8688c9a1f86c85e4062ca75cbf0", + "94293234b797f090b233331aa8d51adc", + "5c61a24613a05d41c122ed9c92f97752", + "a278dac9c38842c463831e146307b37d", + "b0091cfe727265e3bbc22b5ba9391ab1", + "3d6b49d9b3b86da681a4c62b4e2c0195", + "41c330be036be702d292aea609f11d3b", + "8e4539ae477b05d6cee6fefcd827517d", + "e47e9f5e1c9e25cc325d27f231509ceb", + "413082fea1cf144125f3d244ee801971", + "34870bc7d6cdd37a735082d5c6db050e", + "80f3913096c1a107405973022bdf03c0", + "9aa7351b1123bc7376256b020049cac7", + "4f49524c6efe4d9a1279527053579fae", + "91010b66e3fba877776096e2dda86a6b", + "b260fc64e440d2d4e62b5c809a1ce78a", + "224711b4abf0c0483d3f745f4a0d6f49", + "433573f679eece2371c01f8d8aafbdc9", + "751352b4709d4356755454786b5bd92c", + "52841d8701fcab7877e6417b18547764", + "5075d62f9d82c37bb023529d46990c47", + "17af5e9f5b041df7b14422bfbe31f28d", + "f2f69c1023351221fb40d06e257adeb2", + "7def5f5ef26424e060f9319a2bcb2b43", + "b62c49a2e2fc388f0c98926dfa9ad887", + "a7d1a65265f373dfda3b8c303e66b793", + "5b9e5e7f0e0f9d455f4ad5af7f8c1bbe", + "ab890301f3ad2f76996b13a1c42dbb7a", + "2d4d7c8d2bc389b00c7cd80732bc6ef1", + "0c3d0abdb947f440ce5b6cb3deecc485", + "6e0ba7c3a3a27401cefb01e6e238414e", + "7f8b9e211c217a40f0c1d065ec38e66e", + "5d2eda3dcb29f1fb77cf90cef2843dd9", + "c0da16c42d07ed4fa374bdfa8cc1bc53", + "fda7b7c69c8ed378c3bc40987965c29a", + "8e7dd0cfee4b37deba5fe53dee031b42", + "21d1ecf1f76c82e6402a2fd7f56f9048", + "5bd664d01434ddbc7488d0a1dc7d9993", + "57441fb5800ae3babac222cd075d09ce", + "5cf9b20ee90880a33eba103cfa5aa4e8", + "031c31b2d51201bab51b90f6e23be921", + "925008809216c4d8fac39db638abc3e4", + "242b6b1ec0720475d0561cc27225e0c6", + "5d9a215d81dd034784948b8a6c13b004", + "eb4591c1ec909d1f2872f101c08520e0", + "bcb01393836f745596f50ce16330cbbb", + "5dd79e25cd313397a82583e03a149778", + "35ff6dff62dd50869fe5646a89a2d206", + "1e24b39cdb75a95c26a9cdd02a693c10", + "a7adda70776bf6653f87a1ec5b0b6552", + "d68998b2a24b028bf28ac5b18e082d23", + "60021be19a0534076da9b47ea31645f1", + "8818b93dd61a5414020225b9cef07fb8", + "a5f1f154e68f09404d6bd5dd1db02012", + "44857e0f0b852054544bcf0ecdca118f", + "e49e7f1d604a0ddb30bfcf7a68d39222", + "4ad0e09867eb900a75c71461c8ee3862", + "6d0c32149528179fb79e336a879f4015", + "1ec61b37834976d4212dd7634c44814b", + "d176de4981c293fb9175595e11050dfb", + "bf25bf129fead6fc047c9da1f56401b9", + "5abfa4a1c4161f565732f58f1e1a0de7", + "6f8a1d79240ba202b5d48f8f02f1cb4b", + "678eb104822b56598ea2749f4588b4e2", + "19496daa40097a6db997763702401cbe", + "2915d82b632d6c5303c8994bfccbcff7", + "199b994743a9679abd0cc07e81302cc1", + "d6a863ef3ab09412d3911e9717f4ea28", + "95fede204bed8af714d22684e964d4e5", + "c182b5bfe71bde3eeb179cf582edcc9e", + "b5e0026bab80e6ea12f8b9a548debbab", + "0e15e66731f633c1967a6d613b11d4ce", + "8f792d25d1a309a047bdb57611be2eb1", + "c508e27deacbe09f0a2e55c5aceaf3f0", + "15be957910f541a097725b9d26a61e51", + "7b9e01b65326d406dcd3e2eaee21150d", + "a0e11a0e40c11d7c4a4fe9411487b880", + "06bcdb213bd33936c3a4d3ec8324d5ab", + "c09997a266b69a34e58cb1296797ca1e", + "5d2821998597f8a3f2fbb77d10f70007", + "fcb6672b878708fad4689d1cfb12b79f", + "1d89bc1ef5a2ad9189629ab34b3fd698", + "b43a5b2a075bd639db7e5c0607e9dc6c", + "261c8ef406ead770226964c6ef1a0ff9", + "538844ac4d2b892767b0f069d3b18d84", + "ca7287561ae8b21866618976b63ee600", + "58de7fc89296dbb43a1ab07b7720d18e", + "2d3b2abba15bb38d390ee127057d3a58", + "8c5fd7a3f95806e1c1e42be00815f35f", + "192be12e85f8b26b179d7e750864991f", + "a02566704cefdd8d27902acbc3a0aec8", + "2de0dc68ac1c00205880b68fe4616b51", + "0c32ca8348c3a90c322e6fad7942ea26", + "f99f687c5cf3ad43c47370b34c8d4941", + "3c937edec967c00164474e567275d69b", + "a9a30b7eae8e0badf42dd9e35295846b", + "f81cee5bbb174aa51ba094488e7498d5", + "91cbcf9d02a0ae3d3b2d86f41a5076fb", + "ecc148b9036303203d0c2d9f5fcfe7c5", + "78cb6ade1cf42f829bfb14b5ee3e0800", + "0e823664d12d12eb23f76783845a6e68", + "3836c051063ba12cf7a6f2e5f474da1c", + "c39115192276e295af1fd998c58a57b2", + "c51cd15d075afd56d92cd68ca3e90f42", + "1621a08c6505ef1e9d0e2171e8c2d50b", + "aeb4d182d7a3ce8259bc548b4d29ce22", + "64c93459d4c15146dfa23844df89a972", + "e80232e7aba1d160d30098b266d4b652", + "16c00fe8b96d19b451e91e09835c0a8d", + "fb5c4fe26b13e67e794a81fa214f8b5c", + "5a933a39e95af21827f21619076e5e07", + "324d1cdb78ee64af86dd4c4f1f3c7018", + "e48bb722b270b96db32ea3b49cd3c278", + "5fa3c3be683e2b6fdc644593b38a87d7", + "916f8466fcd14b3d18da6ef27576312c", + "c20a58c8d78fe40712525aee81cebf4a", + "5f205f09a823f62df6c981772f699dd3", + "3e1de1f8625666827bf333aa7846f0c3", + "fa1c0424e1377fb1dcc37e95dc5a7d9f", + "2e7756ca6dca5715a0c9682fd266cd49", + "7bc74e408ee7938ff9a0a375c0bcd98a", + "e5eaf54cee6d8a068604a42333a1c07b", + "569fe18452e5c39758ac36f575f6d074", + "0a98cee682845d782ed3da0f44a3ce73", + "d1be199f50237a918cf39f2347705233", + "60a8b5a7db34d1f81b6f0b0f9f433cb8", + "05681f157533d10224cd3ec9387f41f4", + "0963117fcbb63e72cd3f3f96451a1e94", + "1f844060800ede43f1c24c0be73a5170", + "8fb9845d1dc10ddef4e54815ae878e83", + "5c382dff0f2cca206d45e5354fb33a38", + "8d25f56f86f43892eecc5f2ff24d9d36", + "6c7a45631b61b9328e0e8cdaac7e965e", + "53750500620a41ddbb1abb7e1c92281a", + "7be9135edaf7296a82c0c431b86ce878", + "9a67d4e4e5801225a9d19a664cf5d3ef", + "e6b9cc80ec3adb53f535c1a1c7076b25", + "a0f5bf6e23aa734fab191d7cde8014a6", + "54a6a442894287de8079ba1a72b84bc1", + "b4a947ca4cd0060d6990ebfa0907df45", + "7a4779409d2d125e997c5ad19c045da6", + "1e6da7aef9590e6387eedfe99c34db53", + "4afaa3c239e1fedf902c2bc6969177aa", + "766a44a33fb7c33a0682d00d71b40116", + "501d8f216421b7fab66cac06c29dbb5c", + "3ef59272bc4bd3f8044def4743194c1d", + "b5e6ba14cd574116ea71491969a8f530", + "0e682ec78254f9d2752b0af42cf908fb", + "57ce13d1bbca4c3bdcb225bd92f89f3a", + "b0263b46f8a969e02a38bc8b15d2fbc8", + "c027721d81be9cf39dd1f988421176f7", + "ec71df323b6e23afdf0f85dee68cf1c0", + "4bc5de291fc6a9e2ec6795de650d092c", + "489b09c246f76719d1e36aedef809c80", + "14b3bcdaebe45cff39c6f009089412de", + "b4ca2f983cc5fb009badf3cd0d598145", + "2b48ed136a8870185158e04fcb865b21", + "db56c50fc5a6de1d9a235d4f8a773adc", + "1a352d75d8e8fe3fa05b182aabe31249", + "9493eb7698906b87aac54dd8bca1220a", + "111c49dc8680f440e8bf0329a4528aa3", + "8fa3759b6537db74be8f7dc25d5979f0", + "b4e4de225d2d587a1036a2f18954156a", + "c3bd89b7dc6349f27ed80128714712d7", + "096f6b94532ea6df6142fd3d218d0af8", + "da3109d886b6fca0388d0156fda90017", + "ea7b8a8595fdb0c885239581a476778a", + "a1f1472e631de4805e51c216747da1dd", + "d2408ead6b2aa2fc441f2c4f96ec78be", + "2b3a61f90a80a598f9e69df1d115b52f", + "de2c90459c98407f676f72dbd9857f4b", + "a757de9f214c662c855fa9f83e88fd15", + "7618cef74cf86b62a0ab9fa55a357f7a", + "25f11cb73c13e68e5f1d3358afe5e377", + "cfe488e87da41d7f8d6eb574031aa65e", + "8d07f5b85f2941f39d6b6c49be02301b", + "16477e4e0c5c630d4d18d723d15e684d", + "48bf583d5fedb44bbc90057d84133fcb", + "8c8f9de2fbfef006cf6b064e4a8b6e4d", + "1853ce4e43cc0da2974703627cee2e86", + "2c686c0e686b352915cb2a4bbf1985b6", + "d91a9c964a236c759abf63c0bbad0fec", + "c0d49c8e867e1527b05b6af9935263da", + "3342624b6e8e9e60c55dbcac46b291e4", + "6be8d957f0e00584858505ac7a7c10a3", + "916f3044b62cc267d1d5ef8dcfbcf844", + "2c86e086b8eaff011ec98cc560fa50f8", + "7c5f6237c5bf2b7c178699d6f3cc4feb", + "52eefb9368cfdff20bb537cc24e00da9", + "c9e8bce39fbfb00aff8edc4067694ce5", + "56aaea1aae505ff798da811f59bfea59", + "b9f8cc7bf57cb300ecca31bb98a73350", + "9f2ed95aaf1b7519f7ac8d42ed07379b", + "f00c0b446cedbddb6fb7e0f77c6720cc", + "4405b513707c87bbc90ab3205172b806", + "3889f3e01d716d12ca67158db9c2618e", + "c76936bd234c4ad6adcc8c6bf93e1e91", + "777d846f8c4bc67a7cfd85767d74f2c7", + "b6ab7c7ad2c0707152a9fd67b38cb2f3", + "bf96e09d63b7bca67a196c40e9a15f8b", + "57eb1c0ff8aee038cb435019acac3153", + "de88d01cf7fa4972e506d61e4fab1ad2", + "867ce397b334c00c9c576940a5036d39", + "ef0c14c2362fc75109a35083249d9bcd", + "4926d9d9b4fa082a5fe8b7e6236e197f", + "a3441b411ac86dc06e27f282d4ad7ca2", + "2f064d6f1edbe537dc2644fbc3489953", + "e3d860a676ac3b880a210b0bb893f0e7", + "07038a65774cbffc6876701ef74dccce", + "31b48ae575c09cbd6744a809de054931", + "23413e3251684618c8138f95b4275711", + "35261da841e4d7e044807d051e25d61d", + "13f091b4c08c49b8b0e2b74d883f860a", + "0492b830494c50215e853d2fdac3dde6", + "e723c73eb1fa6f660f7431de7bcdf9a0", + "6232954eb0813e993f3e5264907bb119", + "278edcec70411a4bcd18df5efb9d72cb", + "3a5b217b5e24f74d3be14596fbe301e0", + "7031233adfc6c1d424f90e018c83e256", + "0f2200acbbc07d32d3edc87a96260c06", + "9c10e6ea7304c3ce5bdd71513f13c6a7", + "c3d4afd1fd68662c534e38efe9c0d62a", + "e5f034d18fd7d59afc4ed721c6ad8453", + "0d636a5af7afea749d89583e0a742972", + "54fb740cb3dead65f632639446b1f170", + "b20a0b12965aca943d0b69b02bd01e20", + "6f5195f4a526b61b4ee7db0b3552dac2", + "6fee1d0599292e17af6eecb61dbb8be0", + "45f872edb61ec87ae33af4e6c53e5091", + "644cf2063e44ae8a70045e74acd8bcf0", + "53ae29c1210dc1e0f9e6d49cda8cbea3", + "c4a0a6855bfefb465f7a17591316e5cb", + "8555c341ef26983ee6f7305ae1b3b8a2", + "1f3a24c4a66b2622885c2c89153de366", + "cc924d790d96d7605a58d15e29fc1c51", + "31b0c7fe1cb925e918ba41e2ea5b755c", + "e86b5ba811be91733d0d2563695829d2", + "73ff3b6a098a89d7886903be676db792", + "11d4b625832ea86b36cddd9cbef562fe", + "dce54436f7f1fcccb38e53fddcac8e28", + "a6eae43a7b8bd1dc80d0e4a8b58e7f37", + "e03ca0730a569f3613a5e3e03757aa9d", + "b1c302f06fad99551d556c9bd577b9d0", + "2ad705b697ea39603e54f943eaedb6f4", + "ac64e589496409c804872df62e2be842", + "3c2124051cab749ab9ac366e97952bbc", + "2944f016249f8dcd38c06cf6f979b023", + "1f61818aeb1deee322cb9f3c0709224b", + "88664467d65eb5b412c46b0f2672068c", + "1ce7d6197e1ed52135c9f4b59d54c1ab", + "e0025cf5c236fb581174283f172b2297", + "961bca23177fdbf44daaeaebbb690b8e", + "ac39a49a9c7304402f33f7f07d6338c9", + "7d89d01e7d6bc6c9da35c7ffddf8d7bf", + "d1201e62ce0f43d3435eacc4d591d209", + "aac79ea176804761c7f2251cc0ad566f", + "c8968cd3e036a56ffb660eedf5ef0c83", + "e0e48bc56fdb3a290265a1bc40817190", + "0e808320792b4debf678f7bbf31b17dd", + "0ac0d025aa3672a6239b6343183b6cf4", + "9d88ebe3b695d7d4656b43efd7de6ea6", + "c627509529624d873afd77d916761419", + "085067aa414370255a23ec7b36d14be9", + "e576fceec164cd181a1622987af8ba8b", + "11729b0f1936cb1df7104b9931a3f5ea", + "8014602345a47c11a0e3d7645fecf4c9", + "b26b15019b1a40bd84d2dd994d201822", + "f09a081d24a529e7331f99597ed96355", + "2c8dfd97892f06d6fd33f11f4d0e3cb4", + "8ef7aefe71a06a290fc6a45a3bf560e8", + "0d5cf11017a7677062849a4e714c2350", + "2a0219950d0e0077101e6fcc0fe09d53", + "01978f3e90d1061c457d48064779c8c8", + "edc3910b25dfa389e9a3c0eda8b4bc3b", + "a38929152d522bcff411ee9f4bfe48d5", + "f5b41c79d4f1d5c10f96fb6c49f05b4c", + "c935226e4b251d7e4a752ac0a14169df", + "c9a6c6a97965dc7311ce5ced63359a69", + "3529fbfb828368566369eabb5505b8cd", + "74daf46e23aa023ea57c93e742e9927a", + "eee1aad9e41242212a11ec4839f4a1f8", + "8d7c7ceaf7b6eb6e501f93d95f9d9296", + "6ec33cf894a3a9ee7a45ac39bfffc715", + "4eb8b5651ab2581fab76bcf9b36065cf", + "347b0a1ef0874d5675dc890c6f016282", + "080f7d8f121cf7a0c28afa92b5f647a8", + "96862a399278b720d55e21fd3e25b7a1", + "04386ed29544de8d47c19f441e0c4b1d", + "9f2607d150270b325148918a3e9122f5", + "8bb40694fcc3fccbbb08d412eb11b60e", + "d033c0c8d82da19b957ee78a103e4019", + "84d4c732f782b6127f2908cfed490d39", + "7841497768a4816569dac142aa02a9e5", + "1a2ec0bcb6509ea93fe19afe7ddd6872", + "2fbed8e3c48b2d6072101e8bc15cc80d", + "c1050dae4d53b27d7c51a18ddeeec2ea", + "36f5a87cff55a80b12bf78aac9ee15cc", + "b2d9554ff58aae943a612d427cafc1a3", + "6d4d7d465d4183531959d7c01c8316af", + "d217b5242e611bcd3e89064cbf2091fa", + "f1d12b6a38b6953f49fd351a21bb9cee", + "6dcd36b4ae9491e4f051c687b7877f20", + "0887ca156781f4022e57628b3951a38a", + "b853120ae8cc5b5d67bde0b8e640e4e7", + "f82b6a63d7a67a1a65f1bdd6fae91384", + "0132e5eb6bd6733b9f29e0077626dbc2", + "29009dc25c3d1801bf96d615c1ce9132", + "7eae660c7d1212d804afbb81ab833f28", + "b46b47c290b7ac46bd346a94cce9854f", + "8b8fda36c5fa3f1057fd1e180ef65902" + ], + "thumbnail_checksums": [] +}
diff --git a/media/test/data/switch_1080p_720p_240frames.h264.json b/media/test/data/switch_1080p_720p_240frames.h264.json new file mode 100644 index 0000000..f80a1193 --- /dev/null +++ b/media/test/data/switch_1080p_720p_240frames.h264.json
@@ -0,0 +1,251 @@ +{ + "profile": "H264PROFILE_MAIN", + "width": 1920, + "height": 1080, + "frame_rate": 24, + "num_frames": 240, + "num_fragments": 240, + "md5_checksums": [ + "1ea74d81500947d6a3d34c04e9764ef0", + "7fcddae137a12f1db5fd757ba9eb4d5d", + "d2b19d292b17fa39cd2a8160bf23f95c", + "7334c16c5a19cc752ae7aa44d6a215af", + "c8bc383a8ca8d55facab7e3f1a22887a", + "e1fa116fad967f26bf7358d95fcb9053", + "7496c984d115a6ea03bff4b7f376abf5", + "71d34a7018c20f567db6d8d1ca24dbce", + "32ab770431449d3a9dffb363e07503bf", + "fd37201d4dba5aa7756dee66d720e3bd", + "feeb4764d4050552ab8c9859fad22f4d", + "750ffffd327c819671493a012f0a1d23", + "d56c0c58b4df674e45354403a259958c", + "9c5b69644c1b66319e313b5633645759", + "542d39a6a72d40765cd733b8361b7b6a", + "47353bd00d6bbaebf9e96733945fe1e5", + "2103fc9ac9daf0ddde16475044f00205", + "f7bfa94b6d64c73504bb861b344b7167", + "9a6d942b1b34a71e017f0a23e73dc17e", + "6553e4afdd0650c5b22027142a5fc433", + "e11a3c3d8b0cb55440acbe5c5e3c4862", + "1fd9fef4bd2d9d1e2a0988961b0437a9", + "d3515af1a62f13c72752d516f7116a86", + "08e9658119f10eae643df508aed35bd6", + "9136ce7e1d12c88b156cff82e7d9e9ba", + "026b98b25146f1c7cca3d471c04e74f5", + "f83732b128173676a297af6952cd1172", + "869d5c07405f389d82c4a457ba8a2b0a", + "bade767484637c644a71c54af899ec2b", + "c08d753b8c4b181139da03a2439a67fb", + "22e3028c12fc0b62e4b2034d11703e82", + "7de7753f1561f87642227a75ff0be6d4", + "45e89e7b20ffdd4554b58305fdfbde09", + "16793c85a739464e35f8e019c8d20a76", + "e80dbc2ee73f419f1499c0c86d8a7216", + "8310ee790db79433cc88afcf5efacb83", + "3e24fc252f190301b10d49b178069421", + "41a38cb67b188abd96afe562ae69f48d", + "cc8fbc9f3735e650e29cd5e8561232b3", + "caa68cc3f954dff9a1618a025a03465e", + "b73501a7d2bbd18e988b43220df4d56c", + "9ee7877d0c6dbbf26d22a6eeda957fc5", + "1d31892d4decdefc3ae777c3498a5e19", + "b6a27b8b6cac84ecfd0def7474c801f0", + "dc0a65e0c69bf8989af822d2d400a7e4", + "d2ed901723cc1e68c238768c0534e879", + "101646cfc6763c5c1b717a1714de629e", + "f18a8880cc2ba2546cc93e896bad9a87", + "c1720979103a5112b9202927839d3cde", + "87cfa6aad79afc17167ac5c095571ce5", + "54c3a2c2ebea12a31eb143c2939edfe5", + "fd869ed345eca5ec7093bd05dc30cffb", + "76d441e2f2bf3f98fa4fd7b07747afab", + "5bb8e69e1cab92119f5a7bda17c18c44", + "dfb5c7f0c85569aae61591fc8bcddd9c", + "b180fbbf8030375047372da857b75b3b", + "a7cc73956ea98e7b9362aa31a32c7e62", + "41132851eddd24c0642a106f53a15f67", + "e40b327432763928ed3493e5013576f3", + "0546b922e1230188a62df403a91d07c3", + "62568050892a31481bb97246e6ff536a", + "548e2c1efad55469487d327060df735b", + "6d562ba81b0d6a8778ec086676009f95", + "823197683e80c97db950c84e0f133efa", + "dd05cc003408d986202c62b33e2da8b5", + "c0a2757cae8897a9d373c2813bfaf477", + "724155cf93c0524fac084e870f52611f", + "282c1909a390ce744ed633448427bc0c", + "6d3915180b22d2f55ffa701da1732478", + "085571e021ab661fe0ec7e05e8d88283", + "bc83704520c594a9f961de659c75b201", + "787fd2478126bac4ae00d1682b283350", + "c18211c545cb62952ebf17b308967c19", + "14007f63879604b3073a161670bfa530", + "93fe30a376b43c40dea50e6c701591b1", + "63e8cf9019aba0c1e2381ef4081b875c", + "0b95bd17c2d956d5499be649d45db3d1", + "f3ae60b825e91c034cd0401fb17c9455", + "418c2669652af46f8c15f87907499fa5", + "09ba5798bde1ce4be91c1630647e6744", + "5f66ab52bc25c707024e4e9a815f02fe", + "bfe61ce5a7ee10bc7a101477a6e59543", + "ae281400c6d36116d346abb3c44d83b1", + "dfa36d1eab95839d3b8f3c0077756656", + "7026c42d85ecf527642b0a2dc0947765", + "9da0b5a3b98a19ebddea480a536ec65e", + "60ed0e188cbfbcf1037161819941ddc5", + "455f3a2a49fb9dc62c3ef83ce81e9a6c", + "cc9e27c7de4babc721116f9ab0e6aae6", + "1447456f47e3e0b49ebb5bfb6371e126", + "79c8c926b69a6cd65b0d3a5855937c91", + "06448e49f0ec260d46aec0ddcb262b46", + "27c4f17e65eb69761e20b6f5736232f6", + "6ffb1fb866ae111ad81b9ff45befd97c", + "5cbbac768099e6ff8c02c8ce944f9f9e", + "6b3a1df6b9e5e39cd3374d2b7903c2e2", + "3cc5c9a06be37ece4c064c29838c2e32", + "e422c0c8e191db6fb7e1387eb3c8a6f0", + "27ab37f0dbde918d9f59b36e22749553", + "a5414e9f63f52ef9c8dcecccd86b5d51", + "af4862631058c73a463a27d7f85f306d", + "a4acf60a23dfc25c4406846afe62bf47", + "2607ed239c92702c770f77b1ee5addc4", + "a95ceb88b70f04021737d30d71c90e66", + "5c5a77161330a4f8549f97dbf8225277", + "a9e3f9f8642491d5177130ca033e3e36", + "19af17b48076d43fa2a7cc98767f813f", + "f1c6cedbabd77b38f2185889f2341dc5", + "311e3cbd6e2ecd3156d9139ba42c90d4", + "f2cbc62fe87d3cdaa1104ece8731de59", + "2c82fc598535895b595a753985433915", + "ecd7ae4acb76516e5340e408915cf52a", + "6f1c00a3e25fd6ca4a43656d7630a78b", + "50e2162ff8b76ac372d8de4198ed027a", + "a55cdd309a5c088fcd8bf5b76227a158", + "d3f7065996d3611949e22fc6e9dc0ca4", + "58276f282b293af00ade1f8c3e45deb9", + "e69587d5f16a3e377f4ae85ee79ade3e", + "74975fce79a524130f99093b2eceb99d", + "110a2e3463b69bc7a6dd91089eef190e", + "1bc347c9ff00fcd0d681501468763f30", + "4c44cf7c80135163797cda5c8702102d", + "2945724c191f294f7f4d26449342a4f0", + "be17aebd9cc108f3fd1baafd566a3fb8", + "f1f9c31c7211b7d5978208921d6b2cdd", + "2f37e204ccf352f9c48ae9ec6da4a65a", + "6137dac688e82bc74001e2eaa8b49916", + "ca7fac3b95fde69beb23be7ab32ab6b2", + "c98d4af588b6233e6273a0b9e0f093f9", + "94b1e6c740775aacd4cb9f494ce5b38e", + "4861cfb25a23c46626c3983f81434fbe", + "318233c856e3b1b315311e8502c48382", + "5233e4012cefdb3d0057dc6740e67111", + "28270209864674f4146afb11088eb308", + "ef4a261a6e700561812332649a2f7815", + "de027524380d238c028ee7ed577112f2", + "cf5eda51905447a51b8967f432f78b83", + "76b8ea47a464de24a0a8b160973f6ae6", + "9da74f9767065858d001061c4e1cbcf5", + "45da554a2c183f04e5ceb8e621527968", + "206d6611783900dd3599af78535540f6", + "8ae6fa040f5e8d7dea4df2bf8f53d896", + "246b3a0a580a022cf04936c7a2aa257d", + "1ec3ce1a95caba5547205b34b7a6bf3c", + "bd119589613bdca7c6ed3777e4368a20", + "c6511ad9e8cef12a194ef3e309b145af", + "a0cc142aa0fc825b9775193c4949dc8d", + "996962e0cf4f1661a331b18a31c910ec", + "0b5719ef2680487bbc7d00a842e069f3", + "ec2aeadaaff0657aa25ccb2a594afda5", + "7a674b663009dd1651d2f177100e957e", + "fde53d5287350443c6f1f24fef222224", + "c6835ce045708c2b4d0a5e827b9a7e5f", + "f7818cbe9ddc7626f36dfa760616f11c", + "c454b8c62220922ea5bd9244b5d9801e", + "92f4c8d462f2d99629fa02be6b3c369d", + "c15663a71ef3021ca40ef08eaa48c799", + "b7560d18ed11d267ce8d9e916c6bf40b", + "41864ff938c7597e5898d19c335c3e1f", + "9d02f5b094f44ac6b5b27ad49d0da0ae", + "f9ecd165566123204c55b708a59568e2", + "1a583e857a690c4f883f7744cf73db30", + "40c11af6f0cb8800051b483cc311a10e", + "4e79a4ecfbc576719b087f3833533e47", + "5cf862b4dd62d3088f30e5c9514df2f2", + "df5aaecfbcce7aa4e2ba1a29e5b11c78", + "15dfb9c388c96756be95e8ee951048a8", + "2360da0a3f8a085512edb5a740730c04", + "fcbf68e25bc7b4dc5a16646816423632", + "95d2094ba330f2760c99f9c34c2cbd91", + "777e9bd9e2c840181fc08cbb89f1a870", + "48697b74197eabb924e1d345d0dd848a", + "ea9239e9c520fdf534d4c7ab8edceb08", + "0609d444edc2beceb7f5a73ebd55b8b2", + "70fe14347705902d199b2d9588e68437", + "62702dbf40719af11be663f9fa0aeeb0", + "0c205510a54e04993b173dd3eb966d23", + "5984415cd0cfae0aabe234c37805cdc1", + "9249d17952237f0120ed05a99fb42f67", + "9484f0dea77253ae9c9d793f8afaf795", + "800a423b9aae1bf96c04edc1d66ee3a9", + "affd94ec4cc039a47bbbfddfa6f4909c", + "4faf64dcfb1fd06af90591855a03d757", + "886957f94fca3522ec5ca5a611fb935e", + "f73c388352205eb582bea295abc73d7c", + "e64bead5c520b8f8ff9ac9ae2afe2881", + "9246090eeb41308f69b2f8bedd705e4a", + "4839fd3de7130bc511aa1534673f1a69", + "d4421e23e344f4e1eb7b90be8f469a4c", + "5c750eb19fcb11fea02d9c30eb9c32cd", + "035b6337218ee99d3c350929376682cd", + "04b755c100294daf0e81725483fe2d51", + "a493d4ef012ae27acbaa84335d404936", + "9d76553c6c7788672d0752d36485b67a", + "8f236a3d2783b86fb547dba251ca0d8a", + "b24937134659ab8e0e92764ee11d111f", + "93e8414e58b8942565ae6024d025d362", + "169e00122e16cedad574696822d43f8f", + "9d71b713284836310947f6509b380923", + "93600680f442e2a47bd4ee4331203139", + "41044e9898aa37a11cfc15f356a072fc", + "0e7d406fbf68723977822e99242d2257", + "19b4ae4e60124347d8e5d7f748819b95", + "faf875a73c78234e079b9605f7f81837", + "1a8e8b702e9aebdc40d3b77e06a604af", + "4aac35bbf8f82ebde5f5ee52f13e2e42", + "ec021d58e14960a83df6ce4a5dd680d3", + "21f511020c5387b6c4d5998def5a3229", + "6284c7a638d033cdea3968fd50f76d96", + "0f14d8949d741fd66e1d4f9474f3fd9f", + "8080e48d2f252c1954e08667d3fb455f", + "9c3e2539508ad5377a34425731e8b24c", + "3ee7a1f732f75d57925aee4fcbd89127", + "16c5e3cc4e9a5af1c21f75bffe5e4f4c", + "4a4e32c51d92bfd7afda79405d65a614", + "d301de4149929c28bd2445d8080f73a1", + "05afe3fdd001130a1419a65643cf26a1", + "20bcc937fa951e887494b7aca2741239", + "3762c139192ef392a7a8502735846847", + "83ab3d5f72220f7940d3f68fbf218c12", + "2ce2eca21506e12341bfcccb466c5151", + "44f2a1956562522a8f4da895aaaa4d74", + "e74ec20c7b304f6108c117ece3d1a18b", + "3153355bc65c8f4f459960cb01d21cca", + "af5de048fcc58f541cfd6f5830993a68", + "0f0b8bf883486fce8de5ed7bf65db77e", + "2c59f9dd02f3cb3e7acec55e2d5e5601", + "e179e3f355f7578bfca26fddc1064c22", + "f9e2143ae3b7a13ceb2257ce66962570", + "1b4512a18c885d6958ff1d08a7297a53", + "34aae7a164e6204a02d5a0c159df4929", + "6f0be6b6981ec4df1d1066b11d87adaf", + "b9f3bf9316c0153f57d7cfbd567fe0f8", + "c55ca3407b9a8be016aedfb778db42eb", + "ec72ded34398fb56a835ace447b28633", + "bae1115646af3eaab893016de8a4efc4", + "e0d94af7d4253968d473dd0da91f599c", + "d116552b47a29718b70d03dfc417ad86", + "c1236dc2a2a7da79ff7fc36c83770e33", + "24f517003f38e5848cefe52042363403" + ], + "thumbnail_checksums": [] +}
diff --git a/net/BUILD.gn b/net/BUILD.gn index aa19ec2..00a042dd 100644 --- a/net/BUILD.gn +++ b/net/BUILD.gn
@@ -330,16 +330,10 @@ "socket/ssl_socket.h", "socket/stream_socket.cc", "socket/stream_socket.h", - "ssl/channel_id_service.cc", - "ssl/channel_id_service.h", - "ssl/channel_id_store.cc", - "ssl/channel_id_store.h", "ssl/client_cert_identity.cc", "ssl/client_cert_identity.h", "ssl/client_cert_identity_mac.cc", "ssl/client_cert_identity_mac.h", - "ssl/default_channel_id_store.cc", - "ssl/default_channel_id_store.h", "ssl/openssl_ssl_util.cc", "ssl/openssl_ssl_util.h", "ssl/ssl_cert_request_info.cc", @@ -2751,8 +2745,6 @@ "test/cert_test_util.cc", "test/cert_test_util.h", "test/cert_test_util_nss.cc", - "test/channel_id_test_util.cc", - "test/channel_id_test_util.h", "test/ct_test_util.cc", "test/ct_test_util.h", "test/embedded_test_server/controllable_http_response.cc", @@ -5208,13 +5200,11 @@ "spdy/spdy_stream_test_util.h", "spdy/spdy_stream_unittest.cc", "spdy/spdy_write_queue_unittest.cc", - "ssl/channel_id_service_unittest.cc", "ssl/client_cert_identity_unittest.cc", "ssl/client_cert_store_mac_unittest.cc", "ssl/client_cert_store_nss_unittest.cc", "ssl/client_cert_store_unittest-inl.h", "ssl/client_cert_store_win_unittest.cc", - "ssl/default_channel_id_store_unittest.cc", "ssl/ssl_cipher_suite_names_unittest.cc", "ssl/ssl_client_auth_cache_unittest.cc", "ssl/ssl_client_session_cache_unittest.cc", @@ -5632,10 +5622,7 @@ ] } } else { - sources -= [ - "extras/sqlite/sqlite_channel_id_store_unittest.cc", - "extras/sqlite/sqlite_persistent_cookie_store_unittest.cc", - ] + sources -= [ "extras/sqlite/sqlite_persistent_cookie_store_unittest.cc" ] } data = []
diff --git a/net/cookies/cookie_monster_unittest.cc b/net/cookies/cookie_monster_unittest.cc index 120e04f..88505a3 100644 --- a/net/cookies/cookie_monster_unittest.cc +++ b/net/cookies/cookie_monster_unittest.cc
@@ -46,8 +46,6 @@ #include "net/log/net_log_with_source.h" #include "net/log/test_net_log.h" #include "net/log/test_net_log_util.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/default_channel_id_store.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "url/gurl.h"
diff --git a/net/reporting/reporting_endpoint_manager.cc b/net/reporting/reporting_endpoint_manager.cc index 80b1892..ec6f3863 100644 --- a/net/reporting/reporting_endpoint_manager.cc +++ b/net/reporting/reporting_endpoint_manager.cc
@@ -81,9 +81,11 @@ return ReportingEndpoint(); } - // TODO(chlily): This will DCHECK if all the endpoints with the desired - // priority have a weight of 0. Also does not give endpoints with weight 0 - // any chance of being selected. + if (total_weight == 0) { + int random_index = rand_callback_.Run(0, available_endpoints.size() - 1); + return available_endpoints[random_index]; + } + int random_index = rand_callback_.Run(0, total_weight - 1); int weight_so_far = 0; for (size_t i = 0; i < available_endpoints.size(); ++i) {
diff --git a/net/reporting/reporting_endpoint_manager_unittest.cc b/net/reporting/reporting_endpoint_manager_unittest.cc index 5c198570..fd1361da 100644 --- a/net/reporting/reporting_endpoint_manager_unittest.cc +++ b/net/reporting/reporting_endpoint_manager_unittest.cc
@@ -240,5 +240,34 @@ EXPECT_EQ(kEndpoint2Weight, endpoint2_count); } +TEST_F(ReportingEndpointManagerTest, ZeroWeights) { + static const GURL kEndpoint1("https://endpoint1/"); + static const GURL kEndpoint2("https://endpoint2/"); + + SetEndpoint(kEndpoint1, ReportingEndpoint::EndpointInfo::kDefaultPriority, + 0 /* weight */); + SetEndpoint(kEndpoint2, ReportingEndpoint::EndpointInfo::kDefaultPriority, + 0 /* weight */); + + int endpoint1_count = 0; + int endpoint2_count = 0; + + for (int i = 0; i < 10; ++i) { + ReportingEndpoint endpoint = + endpoint_manager()->FindEndpointForDelivery(kOrigin_, kGroup_); + ASSERT_TRUE(endpoint); + ASSERT_TRUE(endpoint.info.url == kEndpoint1 || + endpoint.info.url == kEndpoint2); + + if (endpoint.info.url == kEndpoint1) + ++endpoint1_count; + else if (endpoint.info.url == kEndpoint2) + ++endpoint2_count; + } + + EXPECT_EQ(5, endpoint1_count); + EXPECT_EQ(5, endpoint2_count); +} + } // namespace } // namespace net
diff --git a/net/ssl/channel_id_service.cc b/net/ssl/channel_id_service.cc deleted file mode 100644 index 6f45e09..0000000 --- a/net/ssl/channel_id_service.cc +++ /dev/null
@@ -1,423 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/ssl/channel_id_service.h" - -#include <algorithm> -#include <limits> -#include <memory> -#include <utility> - -#include "base/atomic_sequence_num.h" -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/compiler_specific.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/macros.h" -#include "base/memory/ptr_util.h" -#include "base/metrics/histogram_macros.h" -#include "base/rand_util.h" -#include "base/single_thread_task_runner.h" -#include "base/task/post_task.h" -#include "base/task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "crypto/ec_private_key.h" -#include "net/base/net_errors.h" -#include "net/base/registry_controlled_domains/registry_controlled_domain.h" -#include "net/cert/x509_certificate.h" -#include "net/cert/x509_util.h" -#include "url/gurl.h" - -namespace net { - -namespace { - -base::AtomicSequenceNumber g_next_id; - -// On success, returns a ChannelID object and sets |*error| to OK. -// Otherwise, returns NULL, and |*error| will be set to a net error code. -// |serial_number| is passed in because base::RandInt cannot be called from an -// unjoined thread, due to relying on a non-leaked LazyInstance -std::unique_ptr<ChannelIDStore::ChannelID> GenerateChannelID( - const std::string& server_identifier, - int* error) { - std::unique_ptr<ChannelIDStore::ChannelID> result; - - base::Time creation_time = base::Time::Now(); - std::unique_ptr<crypto::ECPrivateKey> key(crypto::ECPrivateKey::Create()); - - if (!key) { - DLOG(ERROR) << "Unable to create channel ID key pair"; - *error = ERR_KEY_GENERATION_FAILED; - return result; - } - - result.reset(new ChannelIDStore::ChannelID(server_identifier, creation_time, - std::move(key))); - *error = OK; - return result; -} - -} // namespace - -// ChannelIDServiceWorker takes care of the blocking process of performing key -// generation. Will take care of deleting itself once Start() is called. -class ChannelIDServiceWorker { - public: - typedef base::OnceCallback< - void(const std::string&, int, std::unique_ptr<ChannelIDStore::ChannelID>)> - WorkerDoneCallback; - - ChannelIDServiceWorker(const std::string& server_identifier, - WorkerDoneCallback callback) - : server_identifier_(server_identifier), - origin_task_runner_(base::ThreadTaskRunnerHandle::Get()), - callback_(std::move(callback)) {} - - // Starts the worker asynchronously. - void Start(const scoped_refptr<base::TaskRunner>& task_runner) { - DCHECK(origin_task_runner_->RunsTasksInCurrentSequence()); - - auto callback = - base::BindOnce(&ChannelIDServiceWorker::Run, base::Owned(this)); - - if (task_runner) { - task_runner->PostTask(FROM_HERE, std::move(callback)); - } else { - base::PostTaskWithTraits( - FROM_HERE, - {base::MayBlock(), base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN}, - std::move(callback)); - } - } - - private: - void Run() { - // Runs on a worker thread. - int error = ERR_FAILED; - std::unique_ptr<ChannelIDStore::ChannelID> channel_id = - GenerateChannelID(server_identifier_, &error); - origin_task_runner_->PostTask( - FROM_HERE, base::BindOnce(std::move(callback_), server_identifier_, - error, base::Passed(&channel_id))); - } - - const std::string server_identifier_; - scoped_refptr<base::SequencedTaskRunner> origin_task_runner_; - WorkerDoneCallback callback_; - - DISALLOW_COPY_AND_ASSIGN(ChannelIDServiceWorker); -}; - -// A ChannelIDServiceJob is a one-to-one counterpart of an -// ChannelIDServiceWorker. It lives only on the ChannelIDService's -// origin task runner's thread. -class ChannelIDServiceJob { - public: - ChannelIDServiceJob(bool create_if_missing) - : create_if_missing_(create_if_missing) { - } - - ~ChannelIDServiceJob() { DCHECK(requests_.empty()); } - - void AddRequest(ChannelIDService::Request* request, - bool create_if_missing = false) { - create_if_missing_ |= create_if_missing; - requests_.push_back(request); - } - - void HandleResult(int error, std::unique_ptr<crypto::ECPrivateKey> key) { - PostAll(error, std::move(key)); - } - - bool CreateIfMissing() const { return create_if_missing_; } - - void CancelRequest(ChannelIDService::Request* req) { - auto it = std::find(requests_.begin(), requests_.end(), req); - if (it != requests_.end()) - requests_.erase(it); - } - - private: - void PostAll(int error, std::unique_ptr<crypto::ECPrivateKey> key) { - std::vector<ChannelIDService::Request*> requests; - requests_.swap(requests); - - for (auto i = requests.begin(); i != requests.end(); i++) { - std::unique_ptr<crypto::ECPrivateKey> key_copy; - if (key) - key_copy = key->Copy(); - (*i)->Post(error, std::move(key_copy)); - } - } - - std::vector<ChannelIDService::Request*> requests_; - bool create_if_missing_; -}; - -ChannelIDService::Request::Request() : service_(nullptr) {} - -ChannelIDService::Request::~Request() { - Cancel(); -} - -void ChannelIDService::Request::Cancel() { - if (service_) { - callback_.Reset(); - job_->CancelRequest(this); - - service_ = nullptr; - } -} - -void ChannelIDService::Request::RequestStarted( - ChannelIDService* service, - CompletionOnceCallback callback, - std::unique_ptr<crypto::ECPrivateKey>* key, - ChannelIDServiceJob* job) { - DCHECK(service_ == nullptr); - service_ = service; - callback_ = std::move(callback); - key_ = key; - job_ = job; -} - -void ChannelIDService::Request::Post( - int error, - std::unique_ptr<crypto::ECPrivateKey> key) { - service_ = nullptr; - DCHECK(!callback_.is_null()); - if (key) - *key_ = std::move(key); - // Running the callback might delete |this| (e.g. the callback cleans up - // resources created for the request), so we can't touch any of our - // members afterwards. Reset callback_ first. - std::move(callback_).Run(error); -} - -ChannelIDService::ChannelIDService(ChannelIDStore* channel_id_store) - : channel_id_store_(channel_id_store), - id_(g_next_id.GetNext()), - requests_(0), - key_store_hits_(0), - inflight_joins_(0), - workers_created_(0), - weak_ptr_factory_(this) {} - -ChannelIDService::~ChannelIDService() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -// static -std::string ChannelIDService::GetDomainForHost(const std::string& host) { - std::string domain = - registry_controlled_domains::GetDomainAndRegistry( - host, registry_controlled_domains::INCLUDE_PRIVATE_REGISTRIES); - if (domain.empty()) - return host; - return domain; -} - -int ChannelIDService::GetOrCreateChannelID( - const std::string& host, - std::unique_ptr<crypto::ECPrivateKey>* key, - CompletionOnceCallback callback, - Request* out_req) { - DVLOG(1) << __func__ << " " << host; - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (callback.is_null() || !key || host.empty()) { - return ERR_INVALID_ARGUMENT; - } - - std::string domain = GetDomainForHost(host); - if (domain.empty()) { - return ERR_INVALID_ARGUMENT; - } - - requests_++; - - // See if a request for the same domain is currently in flight. - bool create_if_missing = true; - if (JoinToInFlightRequest(domain, key, create_if_missing, &callback, - out_req)) { - return ERR_IO_PENDING; - } - - int err = LookupChannelID(domain, key, create_if_missing, &callback, out_req); - if (err == ERR_FILE_NOT_FOUND) { - // Sync lookup did not find a valid channel ID. Start generating a new one. - workers_created_++; - ChannelIDServiceWorker* worker = new ChannelIDServiceWorker( - domain, base::BindOnce(&ChannelIDService::GeneratedChannelID, - weak_ptr_factory_.GetWeakPtr())); - worker->Start(task_runner_); - - // We are waiting for key generation. Create a job & request to track it. - ChannelIDServiceJob* job = new ChannelIDServiceJob(create_if_missing); - inflight_[domain] = base::WrapUnique(job); - - job->AddRequest(out_req); - out_req->RequestStarted(this, std::move(callback), key, job); - return ERR_IO_PENDING; - } - - return err; -} - -int ChannelIDService::GetChannelID(const std::string& host, - std::unique_ptr<crypto::ECPrivateKey>* key, - CompletionOnceCallback callback, - Request* out_req) { - DVLOG(1) << __func__ << " " << host; - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - if (callback.is_null() || !key || host.empty()) { - return ERR_INVALID_ARGUMENT; - } - - std::string domain = GetDomainForHost(host); - if (domain.empty()) { - return ERR_INVALID_ARGUMENT; - } - - requests_++; - - // See if a request for the same domain currently in flight. - bool create_if_missing = false; - if (JoinToInFlightRequest(domain, key, create_if_missing, &callback, - out_req)) { - return ERR_IO_PENDING; - } - - int err = LookupChannelID(domain, key, create_if_missing, &callback, out_req); - return err; -} - -void ChannelIDService::GotChannelID(int err, - const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey> key) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - auto j = inflight_.find(server_identifier); - if (j == inflight_.end()) { - NOTREACHED(); - return; - } - - if (err == OK) { - // Async DB lookup found a valid channel ID. - key_store_hits_++; - // ChannelIDService::Request::Post will do the histograms and stuff. - HandleResult(OK, server_identifier, std::move(key)); - return; - } - // Async lookup failed or the channel ID was missing. Return the error - // directly, unless the channel ID was missing and a request asked to create - // one. - if (err != ERR_FILE_NOT_FOUND || !j->second->CreateIfMissing()) { - HandleResult(err, server_identifier, std::move(key)); - return; - } - // At least one request asked to create a channel ID => start generating a new - // one. - workers_created_++; - ChannelIDServiceWorker* worker = new ChannelIDServiceWorker( - server_identifier, base::BindOnce(&ChannelIDService::GeneratedChannelID, - weak_ptr_factory_.GetWeakPtr())); - worker->Start(task_runner_); -} - -ChannelIDStore* ChannelIDService::GetChannelIDStore() { - return channel_id_store_.get(); -} - -void ChannelIDService::GeneratedChannelID( - const std::string& server_identifier, - int error, - std::unique_ptr<ChannelIDStore::ChannelID> channel_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - std::unique_ptr<crypto::ECPrivateKey> key; - if (error == OK) { - key = channel_id->key()->Copy(); - channel_id_store_->SetChannelID(std::move(channel_id)); - } - HandleResult(error, server_identifier, std::move(key)); -} - -void ChannelIDService::HandleResult(int error, - const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey> key) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - auto j = inflight_.find(server_identifier); - if (j == inflight_.end()) { - NOTREACHED(); - return; - } - std::unique_ptr<ChannelIDServiceJob> job = std::move(j->second); - inflight_.erase(j); - - job->HandleResult(error, std::move(key)); -} - -bool ChannelIDService::JoinToInFlightRequest( - const std::string& domain, - std::unique_ptr<crypto::ECPrivateKey>* key, - bool create_if_missing, - CompletionOnceCallback* callback, - Request* out_req) { - auto j = inflight_.find(domain); - if (j == inflight_.end()) - return false; - - // A request for the same domain is in flight already. We'll attach our - // callback, but we'll also mark it as requiring a channel ID if one's mising. - ChannelIDServiceJob* job = j->second.get(); - inflight_joins_++; - - job->AddRequest(out_req, create_if_missing); - out_req->RequestStarted(this, std::move(*callback), key, job); - return true; -} - -int ChannelIDService::LookupChannelID( - const std::string& domain, - std::unique_ptr<crypto::ECPrivateKey>* key, - bool create_if_missing, - CompletionOnceCallback* callback, - Request* out_req) { - // Check if a channel ID key already exists for this domain. - int err = channel_id_store_->GetChannelID( - domain, key, - base::BindOnce(&ChannelIDService::GotChannelID, - weak_ptr_factory_.GetWeakPtr())); - - if (err == OK) { - // Sync lookup found a valid channel ID. - DVLOG(1) << "Channel ID store had valid key for " << domain; - key_store_hits_++; - return OK; - } - - if (err == ERR_IO_PENDING) { - // We are waiting for async DB lookup. Create a job & request to track it. - ChannelIDServiceJob* job = new ChannelIDServiceJob(create_if_missing); - inflight_[domain] = base::WrapUnique(job); - - job->AddRequest(out_req); - out_req->RequestStarted(this, std::move(*callback), key, job); - return ERR_IO_PENDING; - } - - return err; -} - -size_t ChannelIDService::channel_id_count() { - return channel_id_store_->GetChannelIDCount(); -} - -} // namespace net
diff --git a/net/ssl/channel_id_service.h b/net/ssl/channel_id_service.h deleted file mode 100644 index 595dfef5..0000000 --- a/net/ssl/channel_id_service.h +++ /dev/null
@@ -1,185 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_SSL_CHANNEL_ID_SERVICE_H_ -#define NET_SSL_CHANNEL_ID_SERVICE_H_ - -#include <stdint.h> - -#include <map> -#include <memory> -#include <string> -#include <utility> -#include <vector> - -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "base/task_runner.h" -#include "base/threading/thread_checker.h" -#include "net/base/completion_once_callback.h" -#include "net/base/net_export.h" -#include "net/ssl/channel_id_store.h" - -namespace crypto { -class ECPrivateKey; -} // namespace crypto - -namespace net { - -class ChannelIDServiceJob; - -// A class for creating and fetching Channel IDs. -class NET_EXPORT ChannelIDService { - public: - class NET_EXPORT Request { - public: - Request(); - ~Request(); - - // Cancel the request. Does nothing if the request finished or was already - // cancelled. - void Cancel(); - - bool is_active() const { return !callback_.is_null(); } - - private: - friend class ChannelIDService; - friend class ChannelIDServiceJob; - - void RequestStarted(ChannelIDService* service, - CompletionOnceCallback callback, - std::unique_ptr<crypto::ECPrivateKey>* key, - ChannelIDServiceJob* job); - - void Post(int error, std::unique_ptr<crypto::ECPrivateKey> key); - - ChannelIDService* service_; - CompletionOnceCallback callback_; - std::unique_ptr<crypto::ECPrivateKey>* key_; - ChannelIDServiceJob* job_; - }; - - // This object owns |channel_id_store|. - explicit ChannelIDService(ChannelIDStore* channel_id_store); - - ~ChannelIDService(); - - // Sets the TaskRunner to use for asynchronous operations. - void set_task_runner_for_testing( - scoped_refptr<base::TaskRunner> task_runner) { - task_runner_ = std::move(task_runner); - } - - // Returns the domain to be used for |host|. The domain is the - // "registry controlled domain", or the "ETLD + 1" where one exists, or - // the origin otherwise. - static std::string GetDomainForHost(const std::string& host); - - // Fetches the channel ID for the specified host if one exists and - // creates one otherwise. Returns OK if successful or an error code upon - // failure. - // - // On successful completion, |key| holds the ECDSA keypair used for this - // channel ID. - // - // |callback| must not be null. ERR_IO_PENDING is returned if the operation - // could not be completed immediately, in which case the result code will - // be passed to the callback when available. - // - // |*out_req| will be initialized with a handle to the async request. - int GetOrCreateChannelID(const std::string& host, - std::unique_ptr<crypto::ECPrivateKey>* key, - CompletionOnceCallback callback, - Request* out_req); - - // Fetches the channel ID for the specified host if one exists. - // Returns OK if successful, ERR_FILE_NOT_FOUND if none exists, or an error - // code upon failure. - // - // On successful completion, |key| holds the ECDSA keypair used for this - // channel ID. - // - // |callback| must not be null. ERR_IO_PENDING is returned if the operation - // could not be completed immediately, in which case the result code will - // be passed to the callback when available. If an in-flight - // GetChannelID is pending, and a new GetOrCreateChannelID - // request arrives for the same domain, the GetChannelID request will - // not complete until a new channel ID is created. - // - // |*out_req| will be initialized with a handle to the async request. - int GetChannelID(const std::string& host, - std::unique_ptr<crypto::ECPrivateKey>* key, - CompletionOnceCallback callback, - Request* out_req); - - // Returns the backing ChannelIDStore. - ChannelIDStore* GetChannelIDStore(); - - // Returns an ID that is unique across all instances of ChannelIDService in - // this process. TODO(nharper): remove this once crbug.com/548423 is resolved. - int GetUniqueID() const { return id_; } - - // Public only for unit testing. - size_t channel_id_count(); - uint64_t requests() const { return requests_; } - uint64_t key_store_hits() const { return key_store_hits_; } - uint64_t inflight_joins() const { return inflight_joins_; } - uint64_t workers_created() const { return workers_created_; } - - private: - void GotChannelID(int err, - const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey> key); - void GeneratedChannelID( - const std::string& server_identifier, - int error, - std::unique_ptr<ChannelIDStore::ChannelID> channel_id); - void HandleResult(int error, - const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey> key); - - // Searches for an in-flight request for the same domain. If found, attaches - // to the request, consumes |*callback|, and returns true. Otherwise does not - // consume |*callback| and returns false. - bool JoinToInFlightRequest(const std::string& domain, - std::unique_ptr<crypto::ECPrivateKey>* key, - bool create_if_missing, - CompletionOnceCallback* callback, - Request* out_req); - - // Looks for the channel ID for |domain| in this service's store. Returns OK - // if it can be found synchronously, ERR_IO_PENDING if the result cannot be - // obtained synchronously, or a different network error code on failure - // (including failure to find a channel ID of |domain|). Consumes |*callback| - // if and only if ERR_IO_PENDING is returned. - int LookupChannelID(const std::string& domain, - std::unique_ptr<crypto::ECPrivateKey>* key, - bool create_if_missing, - CompletionOnceCallback* callback, - Request* out_req); - - std::unique_ptr<ChannelIDStore> channel_id_store_; - scoped_refptr<base::TaskRunner> task_runner_; - const int id_; - - // inflight_ maps from a server to an active generation which is taking - // place. - std::map<std::string, std::unique_ptr<ChannelIDServiceJob>> inflight_; - - uint64_t requests_; - uint64_t key_store_hits_; - uint64_t inflight_joins_; - uint64_t workers_created_; - - THREAD_CHECKER(thread_checker_); - - base::WeakPtrFactory<ChannelIDService> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(ChannelIDService); -}; - -} // namespace net - -#endif // NET_SSL_CHANNEL_ID_SERVICE_H_
diff --git a/net/ssl/channel_id_service_unittest.cc b/net/ssl/channel_id_service_unittest.cc deleted file mode 100644 index 696371c..0000000 --- a/net/ssl/channel_id_service_unittest.cc +++ /dev/null
@@ -1,616 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/ssl/channel_id_service.h" - -#include <memory> -#include <string> -#include <vector> - -#include "base/bind.h" -#include "base/location.h" -#include "base/macros.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/strings/string_number_conversions.h" -#include "base/task_runner.h" -#include "base/test/null_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "crypto/ec_private_key.h" -#include "net/base/net_errors.h" -#include "net/base/test_completion_callback.h" -#include "net/cert/asn1_util.h" -#include "net/cert/x509_certificate.h" -#include "net/ssl/default_channel_id_store.h" -#include "net/test/channel_id_test_util.h" -#include "net/test/gtest_util.h" -#include "net/test/test_with_scoped_task_environment.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using net::test::IsError; -using net::test::IsOk; - -namespace net { - -namespace { - -void FailTest(int /* result */) { - FAIL(); -} - -class MockChannelIDStoreWithAsyncGet - : public DefaultChannelIDStore { - public: - MockChannelIDStoreWithAsyncGet() - : DefaultChannelIDStore(nullptr), channel_id_count_(0) {} - - int GetChannelID(const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey>* key_result, - GetChannelIDCallback callback) override; - - void SetChannelID(std::unique_ptr<ChannelID> channel_id) override { - channel_id_count_ = 1; - } - - size_t GetChannelIDCount() override { return channel_id_count_; } - - void CallGetChannelIDCallbackWithResult(int err, crypto::ECPrivateKey* key); - - private: - GetChannelIDCallback callback_; - std::string server_identifier_; - size_t channel_id_count_; -}; - -int MockChannelIDStoreWithAsyncGet::GetChannelID( - const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey>* key_result, - GetChannelIDCallback callback) { - server_identifier_ = server_identifier; - callback_ = std::move(callback); - // Reset the cert count, it'll get incremented in either SetChannelID or - // CallGetChannelIDCallbackWithResult. - channel_id_count_ = 0; - // Do nothing else: the results to be provided will be specified through - // CallGetChannelIDCallbackWithResult. - return ERR_IO_PENDING; -} - -void MockChannelIDStoreWithAsyncGet::CallGetChannelIDCallbackWithResult( - int err, - crypto::ECPrivateKey* key) { - if (err == OK) - channel_id_count_ = 1; - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(std::move(callback_), err, server_identifier_, - base::Passed(key ? key->Copy() : nullptr))); -} - -class ChannelIDServiceTest : public TestWithScopedTaskEnvironment { - public: - ChannelIDServiceTest() - : service_(new ChannelIDService(new DefaultChannelIDStore(nullptr))) {} - - protected: - std::unique_ptr<ChannelIDService> service_; -}; - -TEST_F(ChannelIDServiceTest, GetDomainForHost) { - EXPECT_EQ("google.com", - ChannelIDService::GetDomainForHost("google.com")); - EXPECT_EQ("google.com", - ChannelIDService::GetDomainForHost("www.google.com")); - EXPECT_EQ("foo.appspot.com", - ChannelIDService::GetDomainForHost("foo.appspot.com")); - EXPECT_EQ("bar.appspot.com", - ChannelIDService::GetDomainForHost("foo.bar.appspot.com")); - EXPECT_EQ("appspot.com", - ChannelIDService::GetDomainForHost("appspot.com")); - EXPECT_EQ("google.com", - ChannelIDService::GetDomainForHost("www.mail.google.com")); - EXPECT_EQ("goto", - ChannelIDService::GetDomainForHost("goto")); - EXPECT_EQ("127.0.0.1", - ChannelIDService::GetDomainForHost("127.0.0.1")); -} - -TEST_F(ChannelIDServiceTest, GetCacheMiss) { - std::string host("encrypted.google.com"); - - int error; - TestCompletionCallback callback; - ChannelIDService::Request request; - - // Synchronous completion, because the store is initialized. - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, service_->channel_id_count()); - error = service_->GetChannelID(host, &key, callback.callback(), &request); - EXPECT_THAT(error, IsError(ERR_FILE_NOT_FOUND)); - EXPECT_FALSE(request.is_active()); - EXPECT_EQ(0u, service_->channel_id_count()); - EXPECT_FALSE(key); -} - -TEST_F(ChannelIDServiceTest, CacheHit) { - std::string host("encrypted.google.com"); - - int error; - TestCompletionCallback callback1; - ChannelIDService::Request request; - - // Asynchronous completion. - std::unique_ptr<crypto::ECPrivateKey> key1; - EXPECT_EQ(0u, service_->channel_id_count()); - error = service_->GetOrCreateChannelID(host, &key1, callback1.callback(), - &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - error = callback1.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(1u, service_->channel_id_count()); - EXPECT_TRUE(key1); - EXPECT_FALSE(request.is_active()); - - // Synchronous completion. - std::unique_ptr<crypto::ECPrivateKey> key2; - TestCompletionCallback callback2; - error = service_->GetOrCreateChannelID(host, &key2, callback2.callback(), - &request); - EXPECT_FALSE(request.is_active()); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(1u, service_->channel_id_count()); - EXPECT_TRUE(KeysEqual(key1.get(), key2.get())); - - // Synchronous get. - std::unique_ptr<crypto::ECPrivateKey> key3; - TestCompletionCallback callback3; - error = service_->GetChannelID(host, &key3, callback3.callback(), &request); - EXPECT_FALSE(request.is_active()); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(1u, service_->channel_id_count()); - EXPECT_TRUE(KeysEqual(key1.get(), key3.get())); - - EXPECT_EQ(3u, service_->requests()); - EXPECT_EQ(2u, service_->key_store_hits()); - EXPECT_EQ(0u, service_->inflight_joins()); -} - -TEST_F(ChannelIDServiceTest, StoreChannelIDs) { - int error; - TestCompletionCallback callback; - ChannelIDService::Request request; - - std::string host1("encrypted.google.com"); - std::unique_ptr<crypto::ECPrivateKey> key1; - EXPECT_EQ(0u, service_->channel_id_count()); - error = service_->GetOrCreateChannelID(host1, &key1, callback.callback(), - &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - error = callback.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(1u, service_->channel_id_count()); - - std::string host2("www.verisign.com"); - std::unique_ptr<crypto::ECPrivateKey> key2; - error = service_->GetOrCreateChannelID(host2, &key2, callback.callback(), - &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - error = callback.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(2u, service_->channel_id_count()); - - std::string host3("www.twitter.com"); - std::unique_ptr<crypto::ECPrivateKey> key3; - error = service_->GetOrCreateChannelID(host3, &key3, callback.callback(), - &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - error = callback.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(3u, service_->channel_id_count()); - - EXPECT_FALSE(KeysEqual(key1.get(), key2.get())); - EXPECT_FALSE(KeysEqual(key1.get(), key3.get())); - EXPECT_FALSE(KeysEqual(key2.get(), key3.get())); -} - -// Tests an inflight join. -TEST_F(ChannelIDServiceTest, InflightJoin) { - std::string host("encrypted.google.com"); - int error; - - std::unique_ptr<crypto::ECPrivateKey> key1; - TestCompletionCallback callback1; - ChannelIDService::Request request1; - - std::unique_ptr<crypto::ECPrivateKey> key2; - TestCompletionCallback callback2; - ChannelIDService::Request request2; - - error = service_->GetOrCreateChannelID(host, &key1, callback1.callback(), - &request1); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request1.is_active()); - // Should join with the original request. - error = service_->GetOrCreateChannelID(host, &key2, callback2.callback(), - &request2); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request2.is_active()); - - error = callback1.WaitForResult(); - EXPECT_THAT(error, IsOk()); - error = callback2.WaitForResult(); - EXPECT_THAT(error, IsOk()); - - EXPECT_EQ(2u, service_->requests()); - EXPECT_EQ(0u, service_->key_store_hits()); - EXPECT_EQ(1u, service_->inflight_joins()); - EXPECT_EQ(1u, service_->workers_created()); -} - -// Tests an inflight join of a Get request to a GetOrCreate request. -TEST_F(ChannelIDServiceTest, InflightJoinGetOrCreateAndGet) { - std::string host("encrypted.google.com"); - int error; - - std::unique_ptr<crypto::ECPrivateKey> key1; - TestCompletionCallback callback1; - ChannelIDService::Request request1; - - std::unique_ptr<crypto::ECPrivateKey> key2; - TestCompletionCallback callback2; - ChannelIDService::Request request2; - - error = service_->GetOrCreateChannelID(host, &key1, callback1.callback(), - &request1); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request1.is_active()); - // Should join with the original request. - error = service_->GetChannelID(host, &key2, callback2.callback(), &request2); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request2.is_active()); - - error = callback1.WaitForResult(); - EXPECT_THAT(error, IsOk()); - error = callback2.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_TRUE(KeysEqual(key1.get(), key2.get())); - - EXPECT_EQ(2u, service_->requests()); - EXPECT_EQ(0u, service_->key_store_hits()); - EXPECT_EQ(1u, service_->inflight_joins()); - EXPECT_EQ(1u, service_->workers_created()); -} - -// Tests that the callback of a canceled request is never made. -TEST_F(ChannelIDServiceTest, CancelRequest) { - std::string host("encrypted.google.com"); - std::unique_ptr<crypto::ECPrivateKey> key; - int error; - ChannelIDService::Request request; - - error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest), - &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - request.Cancel(); - EXPECT_FALSE(request.is_active()); - - // Wait for reply from ChannelIDServiceWorker to be posted back to the - // ChannelIDService. - RunUntilIdle(); - - // Even though the original request was cancelled, the service will still - // store the result, it just doesn't call the callback. - EXPECT_EQ(1u, service_->channel_id_count()); -} - -// Tests that destructing the Request cancels the request. -TEST_F(ChannelIDServiceTest, CancelRequestByHandleDestruction) { - std::string host("encrypted.google.com"); - std::unique_ptr<crypto::ECPrivateKey> key; - int error; - std::unique_ptr<ChannelIDService::Request> request( - new ChannelIDService::Request()); - - error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest), - request.get()); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request->is_active()); - - // Delete the Request object. - request.reset(); - - // Wait for reply from ChannelIDServiceWorker to be posted back to the - // ChannelIDService. - RunUntilIdle(); - - // Even though the original request was cancelled, the service will still - // store the result, it just doesn't call the callback. - EXPECT_EQ(1u, service_->channel_id_count()); -} - -TEST_F(ChannelIDServiceTest, DestructionWithPendingRequest) { - std::string host("encrypted.google.com"); - std::unique_ptr<crypto::ECPrivateKey> key; - int error; - ChannelIDService::Request request; - - error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest), - &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - - // Cancel request and destroy the ChannelIDService. - request.Cancel(); - service_.reset(); - - // ChannelIDServiceWorker should not post anything back to the - // non-existent ChannelIDService, but run the loop just to be sure it - // doesn't. - base::RunLoop().RunUntilIdle(); - - // If we got here without crashing or triggering errors in memory - // corruption detectors, it worked. -} - -// Tests that making new requests when the ChannelIDService can no longer post -// tasks gracefully fails. This is a regression test for http://crbug.com/236387 -TEST_F(ChannelIDServiceTest, RequestAfterPoolShutdown) { - service_->set_task_runner_for_testing( - base::MakeRefCounted<base::NullTaskRunner>()); - - // Make a request that will force synchronous completion. - std::string host("encrypted.google.com"); - std::unique_ptr<crypto::ECPrivateKey> key; - int error; - ChannelIDService::Request request; - - error = service_->GetOrCreateChannelID(host, &key, base::Bind(&FailTest), - &request); - // If we got here without crashing or triggering errors in memory - // corruption detectors, it worked. - ASSERT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); -} - -// Tests that simultaneous creation of different certs works. -TEST_F(ChannelIDServiceTest, SimultaneousCreation) { - int error; - - std::string host1("encrypted.google.com"); - std::unique_ptr<crypto::ECPrivateKey> key1; - TestCompletionCallback callback1; - ChannelIDService::Request request1; - - std::string host2("foo.com"); - std::unique_ptr<crypto::ECPrivateKey> key2; - TestCompletionCallback callback2; - ChannelIDService::Request request2; - - std::string host3("bar.com"); - std::unique_ptr<crypto::ECPrivateKey> key3; - TestCompletionCallback callback3; - ChannelIDService::Request request3; - - error = service_->GetOrCreateChannelID(host1, &key1, callback1.callback(), - &request1); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request1.is_active()); - - error = service_->GetOrCreateChannelID(host2, &key2, callback2.callback(), - &request2); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request2.is_active()); - - error = service_->GetOrCreateChannelID(host3, &key3, callback3.callback(), - &request3); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request3.is_active()); - - error = callback1.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_TRUE(key1); - - error = callback2.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_TRUE(key2); - - error = callback3.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_TRUE(key3); - - EXPECT_FALSE(KeysEqual(key1.get(), key2.get())); - EXPECT_FALSE(KeysEqual(key1.get(), key3.get())); - EXPECT_FALSE(KeysEqual(key2.get(), key3.get())); - - EXPECT_EQ(3u, service_->channel_id_count()); -} - -TEST_F(ChannelIDServiceTest, AsyncStoreGetOrCreateNoChannelIDsInStore) { - MockChannelIDStoreWithAsyncGet* mock_store = - new MockChannelIDStoreWithAsyncGet(); - service_ = - std::unique_ptr<ChannelIDService>(new ChannelIDService(mock_store)); - - std::string host("encrypted.google.com"); - - int error; - TestCompletionCallback callback; - ChannelIDService::Request request; - - // Asynchronous completion with no certs in the store. - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, service_->channel_id_count()); - error = - service_->GetOrCreateChannelID(host, &key, callback.callback(), &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - - mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr); - - error = callback.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(1u, service_->channel_id_count()); - EXPECT_TRUE(key); - EXPECT_FALSE(request.is_active()); -} - -TEST_F(ChannelIDServiceTest, AsyncStoreGetNoChannelIDsInStore) { - MockChannelIDStoreWithAsyncGet* mock_store = - new MockChannelIDStoreWithAsyncGet(); - service_ = - std::unique_ptr<ChannelIDService>(new ChannelIDService(mock_store)); - - std::string host("encrypted.google.com"); - - int error; - TestCompletionCallback callback; - ChannelIDService::Request request; - - // Asynchronous completion with no certs in the store. - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, service_->channel_id_count()); - error = service_->GetChannelID(host, &key, callback.callback(), &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - - mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr); - - error = callback.WaitForResult(); - EXPECT_THAT(error, IsError(ERR_FILE_NOT_FOUND)); - EXPECT_EQ(0u, service_->channel_id_count()); - EXPECT_EQ(0u, service_->workers_created()); - EXPECT_FALSE(key); - EXPECT_FALSE(request.is_active()); -} - -TEST_F(ChannelIDServiceTest, AsyncStoreGetOrCreateOneCertInStore) { - MockChannelIDStoreWithAsyncGet* mock_store = - new MockChannelIDStoreWithAsyncGet(); - service_ = - std::unique_ptr<ChannelIDService>(new ChannelIDService(mock_store)); - - std::string host("encrypted.google.com"); - - int error; - TestCompletionCallback callback; - ChannelIDService::Request request; - - // Asynchronous completion with a cert in the store. - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, service_->channel_id_count()); - error = - service_->GetOrCreateChannelID(host, &key, callback.callback(), &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - - std::unique_ptr<crypto::ECPrivateKey> expected_key( - crypto::ECPrivateKey::Create()); - mock_store->CallGetChannelIDCallbackWithResult(OK, expected_key.get()); - - error = callback.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(1u, service_->channel_id_count()); - EXPECT_EQ(1u, service_->requests()); - EXPECT_EQ(1u, service_->key_store_hits()); - // Because the cert was found in the store, no new workers should have been - // created. - EXPECT_EQ(0u, service_->workers_created()); - EXPECT_TRUE(key); - EXPECT_TRUE(KeysEqual(expected_key.get(), key.get())); - EXPECT_FALSE(request.is_active()); -} - -TEST_F(ChannelIDServiceTest, AsyncStoreGetOneCertInStore) { - MockChannelIDStoreWithAsyncGet* mock_store = - new MockChannelIDStoreWithAsyncGet(); - service_ = - std::unique_ptr<ChannelIDService>(new ChannelIDService(mock_store)); - - std::string host("encrypted.google.com"); - - int error; - TestCompletionCallback callback; - ChannelIDService::Request request; - - // Asynchronous completion with a cert in the store. - std::unique_ptr<crypto::ECPrivateKey> key; - std::string private_key, spki; - EXPECT_EQ(0u, service_->channel_id_count()); - error = service_->GetChannelID(host, &key, callback.callback(), &request); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request.is_active()); - - std::unique_ptr<crypto::ECPrivateKey> expected_key( - crypto::ECPrivateKey::Create()); - mock_store->CallGetChannelIDCallbackWithResult(OK, expected_key.get()); - - error = callback.WaitForResult(); - EXPECT_THAT(error, IsOk()); - EXPECT_EQ(1u, service_->channel_id_count()); - EXPECT_EQ(1u, service_->requests()); - EXPECT_EQ(1u, service_->key_store_hits()); - // Because the cert was found in the store, no new workers should have been - // created. - EXPECT_EQ(0u, service_->workers_created()); - EXPECT_TRUE(KeysEqual(expected_key.get(), key.get())); - EXPECT_FALSE(request.is_active()); -} - -TEST_F(ChannelIDServiceTest, AsyncStoreGetThenCreateNoCertsInStore) { - MockChannelIDStoreWithAsyncGet* mock_store = - new MockChannelIDStoreWithAsyncGet(); - service_ = - std::unique_ptr<ChannelIDService>(new ChannelIDService(mock_store)); - - std::string host("encrypted.google.com"); - - int error; - - // Asynchronous get with no certs in the store. - TestCompletionCallback callback1; - ChannelIDService::Request request1; - std::unique_ptr<crypto::ECPrivateKey> key1; - EXPECT_EQ(0u, service_->channel_id_count()); - error = service_->GetChannelID(host, &key1, callback1.callback(), &request1); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request1.is_active()); - - // Asynchronous get/create with no certs in the store. - TestCompletionCallback callback2; - ChannelIDService::Request request2; - std::unique_ptr<crypto::ECPrivateKey> key2; - EXPECT_EQ(0u, service_->channel_id_count()); - error = service_->GetOrCreateChannelID(host, &key2, callback2.callback(), - &request2); - EXPECT_THAT(error, IsError(ERR_IO_PENDING)); - EXPECT_TRUE(request2.is_active()); - - mock_store->CallGetChannelIDCallbackWithResult(ERR_FILE_NOT_FOUND, nullptr); - - // Even though the first request didn't ask to create a cert, it gets joined - // by the second, which does, so both succeed. - error = callback1.WaitForResult(); - EXPECT_THAT(error, IsOk()); - error = callback2.WaitForResult(); - EXPECT_THAT(error, IsOk()); - - // One cert is created, one request is joined. - EXPECT_EQ(2u, service_->requests()); - EXPECT_EQ(1u, service_->channel_id_count()); - EXPECT_EQ(1u, service_->workers_created()); - EXPECT_EQ(1u, service_->inflight_joins()); - EXPECT_TRUE(key1); - EXPECT_TRUE(KeysEqual(key1.get(), key2.get())); - EXPECT_FALSE(request1.is_active()); - EXPECT_FALSE(request2.is_active()); -} - -} // namespace - -} // namespace net
diff --git a/net/ssl/channel_id_store.cc b/net/ssl/channel_id_store.cc deleted file mode 100644 index 69dc514..0000000 --- a/net/ssl/channel_id_store.cc +++ /dev/null
@@ -1,45 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/ssl/channel_id_store.h" - -#include <utility> - -#include "crypto/ec_private_key.h" - -namespace net { - -ChannelIDStore::ChannelID::ChannelID() = default; - -ChannelIDStore::ChannelID::ChannelID(const std::string& server_identifier, - base::Time creation_time, - std::unique_ptr<crypto::ECPrivateKey> key) - : server_identifier_(server_identifier), - creation_time_(creation_time), - key_(std::move(key)) {} - -ChannelIDStore::ChannelID::ChannelID(const ChannelID& other) - : server_identifier_(other.server_identifier_), - creation_time_(other.creation_time_), - key_(other.key_ ? other.key_->Copy() : nullptr) { -} - -ChannelIDStore::ChannelID& ChannelIDStore::ChannelID::operator=( - const ChannelID& other) { - if (&other == this) - return *this; - server_identifier_ = other.server_identifier_; - creation_time_ = other.creation_time_; - if (other.key_) - key_ = other.key_->Copy(); - return *this; -} - -ChannelIDStore::ChannelID::~ChannelID() = default; - -ChannelIDStore::~ChannelIDStore() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); -} - -} // namespace net
diff --git a/net/ssl/channel_id_store.h b/net/ssl/channel_id_store.h deleted file mode 100644 index e26c61a..0000000 --- a/net/ssl/channel_id_store.h +++ /dev/null
@@ -1,119 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_SSL_CHANNEL_ID_STORE_H_ -#define NET_SSL_CHANNEL_ID_STORE_H_ - -#include <list> -#include <memory> -#include <string> - -#include "base/callback.h" -#include "base/threading/thread_checker.h" -#include "base/time/time.h" -#include "crypto/ec_private_key.h" -#include "net/base/net_export.h" - -namespace net { - -// An interface for storing and retrieving channel ID keypairs. -// See https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 - -// Owned only by a single ChannelIDService object, which is responsible -// for deleting it. -class NET_EXPORT ChannelIDStore { - public: - // The ChannelID class contains a keypair, along with the corresponding - // hostname (server identifier) and creation time. - class NET_EXPORT ChannelID { - public: - ChannelID(); - ChannelID(const std::string& server_identifier, - base::Time creation_time, - std::unique_ptr<crypto::ECPrivateKey> key); - ChannelID(const ChannelID& other); - ChannelID& operator=(const ChannelID& other); - ~ChannelID(); - - // Server identifier. - const std::string& server_identifier() const { return server_identifier_; } - // The time the keypair was created. - base::Time creation_time() const { return creation_time_; } - // Returns the keypair for the channel ID. This pointer is only valid for - // the lifetime of the ChannelID object - the ECPrivateKey object remains - // owned by the ChannelID object; no ownership is transferred. - crypto::ECPrivateKey* key() const { return key_.get(); } - - private: - std::string server_identifier_; - base::Time creation_time_; - std::unique_ptr<crypto::ECPrivateKey> key_; - }; - - typedef std::list<ChannelID> ChannelIDList; - - typedef base::OnceCallback< - void(int, const std::string&, std::unique_ptr<crypto::ECPrivateKey>)> - GetChannelIDCallback; - typedef base::OnceCallback<void(const ChannelIDList&)> - GetChannelIDListCallback; - - virtual ~ChannelIDStore(); - - // GetChannelID may return the result synchronously through the - // output parameters, in which case it will return either OK if a keypair is - // found in the store, or ERR_FILE_NOT_FOUND if none is found. If the - // result cannot be returned synchronously, GetChannelID will - // return ERR_IO_PENDING and the callback will be called with the result - // asynchronously. - virtual int GetChannelID(const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey>* key_result, - GetChannelIDCallback callback) = 0; - - // Adds the keypair for a hostname to the store. - virtual void SetChannelID(std::unique_ptr<ChannelID> channel_id) = 0; - - // Removes a keypair from the store. - virtual void DeleteChannelID(const std::string& server_identifier, - base::OnceClosure completion_callback) = 0; - - // Deletes the channel ID keypairs that have a creation_date greater than - // or equal to |delete_begin| and less than |delete_end| and whose server - // identifier matches the |domain_predicate|. If base::Time value is_null, - // that side of the comparison is unbounded. - virtual void DeleteForDomainsCreatedBetween( - const base::Callback<bool(const std::string&)>& domain_predicate, - base::Time delete_begin, - base::Time delete_end, - base::OnceClosure completion_callback) = 0; - - // Removes all channel ID keypairs from the store. - virtual void DeleteAll(base::OnceClosure completion_callback) = 0; - - // Returns all channel ID keypairs. - virtual void GetAllChannelIDs(GetChannelIDListCallback callback) = 0; - - // Signals to the backing store that any pending writes should be flushed. - virtual void Flush() = 0; - - // Returns the number of keypairs in the store. May return 0 if the backing - // store is not loaded yet. - // Public only for unit testing. - virtual size_t GetChannelIDCount() = 0; - - // When invoked, instructs the store to keep session related data on - // destruction. - virtual void SetForceKeepSessionState() = 0; - - // Returns true if this ChannelIDStore is ephemeral, and false if it is - // persistent. - virtual bool IsEphemeral() = 0; - - protected: - THREAD_CHECKER(thread_checker_); -}; - -} // namespace net - -#endif // NET_SSL_CHANNEL_ID_STORE_H_
diff --git a/net/ssl/default_channel_id_store.cc b/net/ssl/default_channel_id_store.cc deleted file mode 100644 index bcde2a5a..0000000 --- a/net/ssl/default_channel_id_store.cc +++ /dev/null
@@ -1,427 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/ssl/default_channel_id_store.h" - -#include <utility> - -#include "base/bind.h" -#include "base/metrics/histogram_macros.h" -#include "crypto/ec_private_key.h" -#include "net/base/net_errors.h" - -namespace { - -bool AllDomainsPredicate(const std::string& domain) { - return true; -} - -} // namespace - -namespace net { - -// -------------------------------------------------------------------------- -// Task -class DefaultChannelIDStore::Task { - public: - virtual ~Task(); - - // Runs the task and invokes the client callback on the thread that - // originally constructed the task. - virtual void Run(DefaultChannelIDStore* store) = 0; - - protected: - void InvokeCallback(base::OnceClosure callback) const; -}; - -DefaultChannelIDStore::Task::~Task() = default; - -void DefaultChannelIDStore::Task::InvokeCallback( - base::OnceClosure callback) const { - if (!callback.is_null()) - std::move(callback).Run(); -} - -// -------------------------------------------------------------------------- -// GetChannelIDTask -class DefaultChannelIDStore::GetChannelIDTask - : public DefaultChannelIDStore::Task { - public: - GetChannelIDTask(const std::string& server_identifier, - GetChannelIDCallback callback); - ~GetChannelIDTask() override; - void Run(DefaultChannelIDStore* store) override; - - private: - std::string server_identifier_; - GetChannelIDCallback callback_; -}; - -DefaultChannelIDStore::GetChannelIDTask::GetChannelIDTask( - const std::string& server_identifier, - GetChannelIDCallback callback) - : server_identifier_(server_identifier), callback_(std::move(callback)) {} - -DefaultChannelIDStore::GetChannelIDTask::~GetChannelIDTask() = default; - -void DefaultChannelIDStore::GetChannelIDTask::Run( - DefaultChannelIDStore* store) { - std::unique_ptr<crypto::ECPrivateKey> key_result; - int err = store->GetChannelID(server_identifier_, &key_result, - GetChannelIDCallback()); - DCHECK(err != ERR_IO_PENDING); - - InvokeCallback(base::BindOnce(std::move(callback_), err, server_identifier_, - std::move(key_result))); -} - -// -------------------------------------------------------------------------- -// SetChannelIDTask -class DefaultChannelIDStore::SetChannelIDTask - : public DefaultChannelIDStore::Task { - public: - SetChannelIDTask(std::unique_ptr<ChannelID> channel_id); - ~SetChannelIDTask() override; - void Run(DefaultChannelIDStore* store) override; - - private: - std::unique_ptr<ChannelID> channel_id_; -}; - -DefaultChannelIDStore::SetChannelIDTask::SetChannelIDTask( - std::unique_ptr<ChannelID> channel_id) - : channel_id_(std::move(channel_id)) {} - -DefaultChannelIDStore::SetChannelIDTask::~SetChannelIDTask() = default; - -void DefaultChannelIDStore::SetChannelIDTask::Run( - DefaultChannelIDStore* store) { - store->SyncSetChannelID(std::move(channel_id_)); -} - -// -------------------------------------------------------------------------- -// DeleteChannelIDTask -class DefaultChannelIDStore::DeleteChannelIDTask - : public DefaultChannelIDStore::Task { - public: - DeleteChannelIDTask(const std::string& server_identifier, - base::OnceClosure callback); - ~DeleteChannelIDTask() override; - void Run(DefaultChannelIDStore* store) override; - - private: - std::string server_identifier_; - base::OnceClosure callback_; -}; - -DefaultChannelIDStore::DeleteChannelIDTask::DeleteChannelIDTask( - const std::string& server_identifier, - base::OnceClosure callback) - : server_identifier_(server_identifier), callback_(std::move(callback)) {} - -DefaultChannelIDStore::DeleteChannelIDTask::~DeleteChannelIDTask() = default; - -void DefaultChannelIDStore::DeleteChannelIDTask::Run( - DefaultChannelIDStore* store) { - store->SyncDeleteChannelID(server_identifier_); - - InvokeCallback(std::move(callback_)); -} - -// -------------------------------------------------------------------------- -// DeleteForDomainssCreatedBetweenTask -class DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask - : public DefaultChannelIDStore::Task { - public: - DeleteForDomainsCreatedBetweenTask( - const base::Callback<bool(const std::string&)>& domain_predicate, - base::Time delete_begin, - base::Time delete_end, - base::OnceClosure callback); - ~DeleteForDomainsCreatedBetweenTask() override; - void Run(DefaultChannelIDStore* store) override; - - private: - const base::Callback<bool(const std::string&)> domain_predicate_; - base::Time delete_begin_; - base::Time delete_end_; - base::OnceClosure callback_; -}; - -DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask:: - DeleteForDomainsCreatedBetweenTask( - const base::Callback<bool(const std::string&)>& domain_predicate, - base::Time delete_begin, - base::Time delete_end, - base::OnceClosure callback) - : domain_predicate_(domain_predicate), - delete_begin_(delete_begin), - delete_end_(delete_end), - callback_(std::move(callback)) {} - -DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask:: - ~DeleteForDomainsCreatedBetweenTask() = default; - -void DefaultChannelIDStore::DeleteForDomainsCreatedBetweenTask::Run( - DefaultChannelIDStore* store) { - store->SyncDeleteForDomainsCreatedBetween(domain_predicate_, delete_begin_, - delete_end_); - - InvokeCallback(std::move(callback_)); -} - -// -------------------------------------------------------------------------- -// GetAllChannelIDsTask -class DefaultChannelIDStore::GetAllChannelIDsTask - : public DefaultChannelIDStore::Task { - public: - explicit GetAllChannelIDsTask(GetChannelIDListCallback callback); - ~GetAllChannelIDsTask() override; - void Run(DefaultChannelIDStore* store) override; - - private: - std::string server_identifier_; - GetChannelIDListCallback callback_; -}; - -DefaultChannelIDStore::GetAllChannelIDsTask::GetAllChannelIDsTask( - GetChannelIDListCallback callback) - : callback_(std::move(callback)) {} - -DefaultChannelIDStore::GetAllChannelIDsTask::~GetAllChannelIDsTask() = default; - -void DefaultChannelIDStore::GetAllChannelIDsTask::Run( - DefaultChannelIDStore* store) { - ChannelIDList key_list; - store->SyncGetAllChannelIDs(&key_list); - - InvokeCallback(base::BindOnce(std::move(callback_), key_list)); -} - -// -------------------------------------------------------------------------- -// DefaultChannelIDStore - -DefaultChannelIDStore::DefaultChannelIDStore( - PersistentStore* store) - : initialized_(false), - loaded_(false), - store_(store), - weak_ptr_factory_(this) {} - -int DefaultChannelIDStore::GetChannelID( - const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey>* key_result, - GetChannelIDCallback callback) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - InitIfNecessary(); - - if (!loaded_) { - EnqueueTask(std::unique_ptr<Task>( - new GetChannelIDTask(server_identifier, std::move(callback)))); - return ERR_IO_PENDING; - } - - auto it = channel_ids_.find(server_identifier); - - if (it == channel_ids_.end()) - return ERR_FILE_NOT_FOUND; - - ChannelID* channel_id = it->second; - *key_result = channel_id->key()->Copy(); - - return OK; -} - -void DefaultChannelIDStore::SetChannelID( - std::unique_ptr<ChannelID> channel_id) { - auto* task = new SetChannelIDTask(std::move(channel_id)); - RunOrEnqueueTask(std::unique_ptr<Task>(task)); -} - -void DefaultChannelIDStore::DeleteChannelID( - const std::string& server_identifier, - base::OnceClosure callback) { - RunOrEnqueueTask(std::unique_ptr<Task>( - new DeleteChannelIDTask(server_identifier, std::move(callback)))); -} - -void DefaultChannelIDStore::DeleteForDomainsCreatedBetween( - const base::Callback<bool(const std::string&)>& domain_predicate, - base::Time delete_begin, - base::Time delete_end, - base::OnceClosure callback) { - RunOrEnqueueTask(std::unique_ptr<Task>(new DeleteForDomainsCreatedBetweenTask( - domain_predicate, delete_begin, delete_end, std::move(callback)))); -} - -void DefaultChannelIDStore::DeleteAll(base::OnceClosure callback) { - DeleteForDomainsCreatedBetween(base::Bind(&AllDomainsPredicate), base::Time(), - base::Time(), std::move(callback)); -} - -void DefaultChannelIDStore::GetAllChannelIDs( - GetChannelIDListCallback callback) { - RunOrEnqueueTask( - std::unique_ptr<Task>(new GetAllChannelIDsTask(std::move(callback)))); -} - -void DefaultChannelIDStore::Flush() { - store_->Flush(); -} - -size_t DefaultChannelIDStore::GetChannelIDCount() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - return channel_ids_.size(); -} - -void DefaultChannelIDStore::SetForceKeepSessionState() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - InitIfNecessary(); - - if (store_) - store_->SetForceKeepSessionState(); -} - -DefaultChannelIDStore::~DefaultChannelIDStore() { - DeleteAllInMemory(); -} - -void DefaultChannelIDStore::DeleteAllInMemory() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - - for (auto it = channel_ids_.begin(); it != channel_ids_.end(); ++it) { - delete it->second; - } - channel_ids_.clear(); -} - -void DefaultChannelIDStore::InitStore() { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(store_) << "Store must exist to initialize"; - DCHECK(!loaded_); - - store_->Load(base::Bind(&DefaultChannelIDStore::OnLoaded, - weak_ptr_factory_.GetWeakPtr())); -} - -void DefaultChannelIDStore::OnLoaded( - std::unique_ptr<std::vector<std::unique_ptr<ChannelID>>> channel_ids) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - for (auto it = channel_ids->begin(); it != channel_ids->end(); ++it) { - DCHECK(channel_ids_.find((*it)->server_identifier()) == - channel_ids_.end()); - std::string ident = (*it)->server_identifier(); - channel_ids_[ident] = it->release(); - } - channel_ids->clear(); - - loaded_ = true; - - for (std::unique_ptr<Task>& i : waiting_tasks_) - i->Run(this); - waiting_tasks_.clear(); -} - -void DefaultChannelIDStore::SyncSetChannelID( - std::unique_ptr<ChannelID> channel_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(loaded_); - - InternalDeleteChannelID(channel_id->server_identifier()); - InternalInsertChannelID(std::move(channel_id)); -} - -void DefaultChannelIDStore::SyncDeleteChannelID( - const std::string& server_identifier) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(loaded_); - InternalDeleteChannelID(server_identifier); -} - -void DefaultChannelIDStore::SyncDeleteForDomainsCreatedBetween( - const base::Callback<bool(const std::string&)>& domain_predicate, - base::Time delete_begin, - base::Time delete_end) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(loaded_); - for (auto it = channel_ids_.begin(); it != channel_ids_.end();) { - auto cur = it; - ++it; - ChannelID* channel_id = cur->second; - - if ((delete_begin.is_null() || - channel_id->creation_time() >= delete_begin) && - (delete_end.is_null() || channel_id->creation_time() < delete_end) && - domain_predicate.Run(channel_id->server_identifier())) { - if (store_) - store_->DeleteChannelID(*channel_id); - delete channel_id; - channel_ids_.erase(cur); - } - } -} - -void DefaultChannelIDStore::SyncGetAllChannelIDs( - ChannelIDList* channel_id_list) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(loaded_); - for (auto it = channel_ids_.begin(); it != channel_ids_.end(); ++it) - channel_id_list->push_back(*it->second); -} - -void DefaultChannelIDStore::EnqueueTask(std::unique_ptr<Task> task) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(!loaded_); - waiting_tasks_.push_back(std::move(task)); -} - -void DefaultChannelIDStore::RunOrEnqueueTask(std::unique_ptr<Task> task) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - InitIfNecessary(); - - if (!loaded_) { - EnqueueTask(std::move(task)); - return; - } - - task->Run(this); -} - -void DefaultChannelIDStore::InternalDeleteChannelID( - const std::string& server_identifier) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(loaded_); - - auto it = channel_ids_.find(server_identifier); - if (it == channel_ids_.end()) - return; // There is nothing to delete. - - ChannelID* channel_id = it->second; - if (store_) - store_->DeleteChannelID(*channel_id); - channel_ids_.erase(it); - delete channel_id; -} - -void DefaultChannelIDStore::InternalInsertChannelID( - std::unique_ptr<ChannelID> channel_id) { - DCHECK_CALLED_ON_VALID_THREAD(thread_checker_); - DCHECK(loaded_); - - if (store_) - store_->AddChannelID(*channel_id); - const std::string& server_identifier = channel_id->server_identifier(); - channel_ids_[server_identifier] = channel_id.release(); -} - -bool DefaultChannelIDStore::IsEphemeral() { - return !store_; -} - -DefaultChannelIDStore::PersistentStore::PersistentStore() = default; - -DefaultChannelIDStore::PersistentStore::~PersistentStore() = default; - -} // namespace net
diff --git a/net/ssl/default_channel_id_store.h b/net/ssl/default_channel_id_store.h deleted file mode 100644 index d7daeff3..0000000 --- a/net/ssl/default_channel_id_store.h +++ /dev/null
@@ -1,185 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_SSL_DEFAULT_CHANNEL_ID_STORE_H_ -#define NET_SSL_DEFAULT_CHANNEL_ID_STORE_H_ - -#include <map> -#include <memory> -#include <string> -#include <vector> - -#include "base/callback_forward.h" -#include "base/compiler_specific.h" -#include "base/macros.h" -#include "base/memory/ref_counted.h" -#include "base/memory/weak_ptr.h" -#include "net/base/net_export.h" -#include "net/ssl/channel_id_store.h" - -namespace crypto { -class ECPrivateKey; -} // namespace crypto - -namespace net { - -// This class is the system for storing and retrieving Channel IDs. Modeled -// after the CookieMonster class, it has an in-memory store and synchronizes -// Channel IDs to an optional permanent storage that implements the -// PersistentStore interface. The use case is described in -// https://tools.ietf.org/html/draft-balfanz-tls-channelid-01 -class NET_EXPORT DefaultChannelIDStore : public ChannelIDStore { - public: - class PersistentStore; - - // The key for each ChannelID* in ChannelIDMap is the - // corresponding server. - typedef std::map<std::string, ChannelID*> ChannelIDMap; - - // The store passed in should not have had Init() called on it yet. This - // class will take care of initializing it. The backing store is NOT owned by - // this class, but it must remain valid for the duration of the - // DefaultChannelIDStore's existence. If |store| is NULL, then no - // backing store will be updated. - explicit DefaultChannelIDStore(PersistentStore* store); - - ~DefaultChannelIDStore() override; - - // ChannelIDStore implementation. - int GetChannelID(const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey>* key_result, - GetChannelIDCallback callback) override; - void SetChannelID(std::unique_ptr<ChannelID> channel_id) override; - void DeleteChannelID(const std::string& server_identifier, - base::OnceClosure callback) override; - void DeleteForDomainsCreatedBetween( - const base::Callback<bool(const std::string&)>& domain_predicate, - base::Time delete_begin, - base::Time delete_end, - base::OnceClosure callback) override; - void DeleteAll(base::OnceClosure callback) override; - void GetAllChannelIDs(GetChannelIDListCallback callback) override; - void Flush() override; - size_t GetChannelIDCount() override; - void SetForceKeepSessionState() override; - bool IsEphemeral() override; - - private: - class Task; - class GetChannelIDTask; - class SetChannelIDTask; - class DeleteChannelIDTask; - class DeleteForDomainsCreatedBetweenTask; - class GetAllChannelIDsTask; - - // Deletes all of the certs. Does not delete them from |store_|. - void DeleteAllInMemory(); - - // Called by all non-static functions to ensure that the cert store has - // been initialized. - // TODO(mattm): since we load asynchronously now, maybe we should start - // loading immediately on construction, or provide some method to initiate - // loading? - void InitIfNecessary() { - if (!initialized_) { - if (store_.get()) { - InitStore(); - } else { - loaded_ = true; - } - initialized_ = true; - } - } - - // Initializes the backing store and reads existing certs from it. - // Should only be called by InitIfNecessary(). - void InitStore(); - - // Callback for backing store loading completion. - void OnLoaded(std::unique_ptr<std::vector<std::unique_ptr<ChannelID>>> certs); - - // Syncronous methods which do the actual work. Can only be called after - // initialization is complete. - void SyncSetChannelID(std::unique_ptr<ChannelID> channel_id); - void SyncDeleteChannelID(const std::string& server_identifier); - void SyncDeleteForDomainsCreatedBetween( - const base::Callback<bool(const std::string&)>& domain_predicate, - base::Time delete_begin, - base::Time delete_end); - void SyncGetAllChannelIDs(ChannelIDList* channel_id_list); - - // Add |task| to |waiting_tasks_|. - void EnqueueTask(std::unique_ptr<Task> task); - // If already initialized, run |task| immediately. Otherwise add it to - // |waiting_tasks_|. - void RunOrEnqueueTask(std::unique_ptr<Task> task); - - // Deletes the channel id for the specified server, if such a channel id - // exists, from the in-memory store. Deletes it from |store_| if |store_| - // is not NULL. - void InternalDeleteChannelID(const std::string& server); - - // Adds the channel id to the in-memory store and adds it to |store_| if - // |store_| is not NULL. - void InternalInsertChannelID(std::unique_ptr<ChannelID> channel_id); - - // Indicates whether the channel id store has been initialized. This happens - // lazily in InitIfNecessary(). - bool initialized_; - - // Indicates whether loading from the backend store is completed and - // calls may be immediately processed. - bool loaded_; - - // Tasks that are waiting to be run once we finish loading. - std::vector<std::unique_ptr<Task>> waiting_tasks_; - - scoped_refptr<PersistentStore> store_; - - ChannelIDMap channel_ids_; - - base::WeakPtrFactory<DefaultChannelIDStore> weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(DefaultChannelIDStore); -}; - -typedef base::RefCountedThreadSafe<DefaultChannelIDStore::PersistentStore> - RefcountedPersistentStore; - -class NET_EXPORT DefaultChannelIDStore::PersistentStore - : public RefcountedPersistentStore { - public: - typedef base::Callback<void( - std::unique_ptr<std::vector<std::unique_ptr<ChannelID>>>)> - LoadedCallback; - - // Initializes the store and retrieves the existing channel_ids. This will be - // called only once at startup. Note that the channel_ids are individually - // allocated and that ownership is transferred to the caller upon return. - // The |loaded_callback| must not be called synchronously. - virtual void Load(const LoadedCallback& loaded_callback) = 0; - - virtual void AddChannelID(const ChannelID& channel_id) = 0; - - virtual void DeleteChannelID(const ChannelID& channel_id) = 0; - - virtual void Flush() = 0; - - // When invoked, instructs the store to keep session related data on - // destruction. - virtual void SetForceKeepSessionState() = 0; - - protected: - friend class base::RefCountedThreadSafe<PersistentStore>; - - PersistentStore(); - virtual ~PersistentStore(); - - private: - DISALLOW_COPY_AND_ASSIGN(PersistentStore); -}; - -} // namespace net - -#endif // NET_SSL_DEFAULT_CHANNEL_ID_STORE_H_
diff --git a/net/ssl/default_channel_id_store_unittest.cc b/net/ssl/default_channel_id_store_unittest.cc deleted file mode 100644 index 1fbe5e8..0000000 --- a/net/ssl/default_channel_id_store_unittest.cc +++ /dev/null
@@ -1,416 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/ssl/default_channel_id_store.h" - -#include <map> -#include <string> -#include <utility> -#include <vector> - -#include "base/bind.h" -#include "base/compiler_specific.h" -#include "base/location.h" -#include "base/logging.h" -#include "base/run_loop.h" -#include "base/single_thread_task_runner.h" -#include "base/threading/thread_task_runner_handle.h" -#include "crypto/ec_private_key.h" -#include "net/base/net_errors.h" -#include "net/test/channel_id_test_util.h" -#include "net/test/gtest_util.h" -#include "net/test/test_with_scoped_task_environment.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -using net::test::IsError; -using net::test::IsOk; - -namespace net { - -namespace { - -void CallCounter(int* counter) { - (*counter)++; -} - -void GetChannelIDCallbackNotCalled( - int err, - const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey> key_result) { - ADD_FAILURE() << "Unexpected callback execution."; -} - -class AsyncGetChannelIDHelper { - public: - AsyncGetChannelIDHelper() : called_(false) {} - - void Callback(int err, - const std::string& server_identifier, - std::unique_ptr<crypto::ECPrivateKey> key_result) { - err_ = err; - server_identifier_ = server_identifier; - key_ = std::move(key_result); - called_ = true; - } - - int err_; - std::string server_identifier_; - std::unique_ptr<crypto::ECPrivateKey> key_; - bool called_; -}; - -void GetAllCallback( - ChannelIDStore::ChannelIDList* dest, - const ChannelIDStore::ChannelIDList& result) { - *dest = result; -} - -class MockPersistentStore - : public DefaultChannelIDStore::PersistentStore { - public: - MockPersistentStore(); - - // DefaultChannelIDStore::PersistentStore implementation. - void Load(const LoadedCallback& loaded_callback) override; - void AddChannelID( - const DefaultChannelIDStore::ChannelID& channel_id) override; - void DeleteChannelID( - const DefaultChannelIDStore::ChannelID& channel_id) override; - void SetForceKeepSessionState() override; - void Flush() override; - - protected: - ~MockPersistentStore() override; - - private: - typedef std::map<std::string, DefaultChannelIDStore::ChannelID> - ChannelIDMap; - - ChannelIDMap channel_ids_; -}; - -MockPersistentStore::MockPersistentStore() = default; - -void MockPersistentStore::Load(const LoadedCallback& loaded_callback) { - std::unique_ptr< - std::vector<std::unique_ptr<DefaultChannelIDStore::ChannelID>>> - channel_ids( - new std::vector<std::unique_ptr<DefaultChannelIDStore::ChannelID>>()); - ChannelIDMap::iterator it; - - for (it = channel_ids_.begin(); it != channel_ids_.end(); ++it) { - channel_ids->push_back( - std::make_unique<DefaultChannelIDStore::ChannelID>(it->second)); - } - - base::ThreadTaskRunnerHandle::Get()->PostTask( - FROM_HERE, base::BindOnce(loaded_callback, std::move(channel_ids))); -} - -void MockPersistentStore::AddChannelID( - const DefaultChannelIDStore::ChannelID& channel_id) { - channel_ids_[channel_id.server_identifier()] = channel_id; -} - -void MockPersistentStore::DeleteChannelID( - const DefaultChannelIDStore::ChannelID& channel_id) { - channel_ids_.erase(channel_id.server_identifier()); -} - -void MockPersistentStore::SetForceKeepSessionState() {} - -void MockPersistentStore::Flush() {} - -MockPersistentStore::~MockPersistentStore() = default; - -bool DomainEquals(const std::string& domain1, const std::string& domain2) { - return domain1 == domain2; -} - -bool DomainNotEquals(const std::string& domain1, const std::string& domain2) { - return !DomainEquals(domain1, domain2); -} - -} // namespace - -using DefaultChannelIDStoreTest = TestWithScopedTaskEnvironment; - -TEST_F(DefaultChannelIDStoreTest, TestLoading) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - - persistent_store->AddChannelID(DefaultChannelIDStore::ChannelID( - "google.com", base::Time(), crypto::ECPrivateKey::Create())); - persistent_store->AddChannelID(DefaultChannelIDStore::ChannelID( - "verisign.com", base::Time(), crypto::ECPrivateKey::Create())); - - // Make sure channel_ids load properly. - DefaultChannelIDStore store(persistent_store.get()); - // Load has not occurred yet. - EXPECT_EQ(0u, store.GetChannelIDCount()); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "verisign.com", base::Time(), crypto::ECPrivateKey::Create())); - // Wait for load & queued set task. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(2u, store.GetChannelIDCount()); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "twitter.com", base::Time(), crypto::ECPrivateKey::Create())); - // Set should be synchronous now that load is done. - EXPECT_EQ(3u, store.GetChannelIDCount()); -} - -//TODO(mattm): add more tests of without a persistent store? -TEST_F(DefaultChannelIDStoreTest, TestSettingAndGetting) { - // No persistent store, all calls will be synchronous. - DefaultChannelIDStore store(nullptr); - std::unique_ptr<crypto::ECPrivateKey> expected_key( - crypto::ECPrivateKey::Create()); - - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, store.GetChannelIDCount()); - EXPECT_EQ(ERR_FILE_NOT_FOUND, - store.GetChannelID("verisign.com", &key, - base::Bind(&GetChannelIDCallbackNotCalled))); - EXPECT_FALSE(key); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "verisign.com", base::Time::FromInternalValue(123), - expected_key->Copy())); - EXPECT_EQ(OK, store.GetChannelID("verisign.com", &key, - base::Bind(&GetChannelIDCallbackNotCalled))); - EXPECT_TRUE(KeysEqual(expected_key.get(), key.get())); -} - -TEST_F(DefaultChannelIDStoreTest, TestDuplicateChannelIds) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - DefaultChannelIDStore store(persistent_store.get()); - std::unique_ptr<crypto::ECPrivateKey> expected_key( - crypto::ECPrivateKey::Create()); - - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, store.GetChannelIDCount()); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "verisign.com", base::Time::FromInternalValue(123), - crypto::ECPrivateKey::Create())); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "verisign.com", base::Time::FromInternalValue(456), - expected_key->Copy())); - - // Wait for load & queued set tasks. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1u, store.GetChannelIDCount()); - EXPECT_EQ(OK, store.GetChannelID("verisign.com", &key, - base::Bind(&GetChannelIDCallbackNotCalled))); - EXPECT_TRUE(KeysEqual(expected_key.get(), key.get())); -} - -TEST_F(DefaultChannelIDStoreTest, TestAsyncGet) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - std::unique_ptr<crypto::ECPrivateKey> expected_key( - crypto::ECPrivateKey::Create()); - persistent_store->AddChannelID(ChannelIDStore::ChannelID( - "verisign.com", base::Time::FromInternalValue(123), - expected_key->Copy())); - - DefaultChannelIDStore store(persistent_store.get()); - AsyncGetChannelIDHelper helper; - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, store.GetChannelIDCount()); - EXPECT_EQ(ERR_IO_PENDING, - store.GetChannelID("verisign.com", &key, - base::Bind(&AsyncGetChannelIDHelper::Callback, - base::Unretained(&helper)))); - - // Wait for load & queued get tasks. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1u, store.GetChannelIDCount()); - EXPECT_FALSE(key); - EXPECT_TRUE(helper.called_); - EXPECT_THAT(helper.err_, IsOk()); - EXPECT_EQ("verisign.com", helper.server_identifier_); - EXPECT_TRUE(KeysEqual(expected_key.get(), helper.key_.get())); -} - -TEST_F(DefaultChannelIDStoreTest, TestDeleteAll) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - DefaultChannelIDStore store(persistent_store.get()); - - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "verisign.com", base::Time(), crypto::ECPrivateKey::Create())); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "google.com", base::Time(), crypto::ECPrivateKey::Create())); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "harvard.com", base::Time(), crypto::ECPrivateKey::Create())); - // Wait for load & queued set tasks. - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(3u, store.GetChannelIDCount()); - int delete_finished = 0; - store.DeleteAll(base::Bind(&CallCounter, &delete_finished)); - ASSERT_EQ(1, delete_finished); - EXPECT_EQ(0u, store.GetChannelIDCount()); -} - -TEST_F(DefaultChannelIDStoreTest, TestDeleteForDomains) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - DefaultChannelIDStore store(persistent_store.get()); - - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "verisign.com", base::Time(), crypto::ECPrivateKey::Create())); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "google.com", base::Time(), crypto::ECPrivateKey::Create())); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "harvard.com", base::Time(), crypto::ECPrivateKey::Create())); - // Wait for load & queued set tasks. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(3u, store.GetChannelIDCount()); - - // Whitelist deletion. - int deletions_finished = 0; - store.DeleteForDomainsCreatedBetween( - base::Bind(&DomainEquals, std::string("verisign.com")), base::Time(), - base::Time(), base::Bind(&CallCounter, &deletions_finished)); - ASSERT_EQ(1, deletions_finished); - EXPECT_EQ(2u, store.GetChannelIDCount()); - ChannelIDStore::ChannelIDList channel_ids; - store.GetAllChannelIDs(base::Bind(GetAllCallback, &channel_ids)); - EXPECT_EQ("google.com", channel_ids.begin()->server_identifier()); - EXPECT_EQ("harvard.com", channel_ids.back().server_identifier()); - - // Blacklist deletion. - store.DeleteForDomainsCreatedBetween( - base::Bind(&DomainNotEquals, std::string("google.com")), base::Time(), - base::Time(), base::Bind(&CallCounter, &deletions_finished)); - ASSERT_EQ(2, deletions_finished); - EXPECT_EQ(1u, store.GetChannelIDCount()); - store.GetAllChannelIDs(base::Bind(GetAllCallback, &channel_ids)); - EXPECT_EQ("google.com", channel_ids.begin()->server_identifier()); -} - -TEST_F(DefaultChannelIDStoreTest, TestAsyncGetAndDeleteAll) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - persistent_store->AddChannelID(ChannelIDStore::ChannelID( - "verisign.com", base::Time(), crypto::ECPrivateKey::Create())); - persistent_store->AddChannelID(ChannelIDStore::ChannelID( - "google.com", base::Time(), crypto::ECPrivateKey::Create())); - - ChannelIDStore::ChannelIDList pre_channel_ids; - ChannelIDStore::ChannelIDList post_channel_ids; - int delete_finished = 0; - DefaultChannelIDStore store(persistent_store.get()); - - store.GetAllChannelIDs(base::Bind(GetAllCallback, &pre_channel_ids)); - store.DeleteAll(base::Bind(&CallCounter, &delete_finished)); - store.GetAllChannelIDs(base::Bind(GetAllCallback, &post_channel_ids)); - // Tasks have not run yet. - EXPECT_EQ(0u, pre_channel_ids.size()); - // Wait for load & queued tasks. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(0u, store.GetChannelIDCount()); - EXPECT_EQ(2u, pre_channel_ids.size()); - EXPECT_EQ(0u, post_channel_ids.size()); -} - -TEST_F(DefaultChannelIDStoreTest, TestDelete) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - DefaultChannelIDStore store(persistent_store.get()); - - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, store.GetChannelIDCount()); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "verisign.com", base::Time(), crypto::ECPrivateKey::Create())); - // Wait for load & queued set task. - base::RunLoop().RunUntilIdle(); - - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "google.com", base::Time(), crypto::ECPrivateKey::Create())); - - EXPECT_EQ(2u, store.GetChannelIDCount()); - int delete_finished = 0; - store.DeleteChannelID("verisign.com", - base::Bind(&CallCounter, &delete_finished)); - ASSERT_EQ(1, delete_finished); - EXPECT_EQ(1u, store.GetChannelIDCount()); - EXPECT_EQ(ERR_FILE_NOT_FOUND, - store.GetChannelID("verisign.com", &key, - base::Bind(&GetChannelIDCallbackNotCalled))); - EXPECT_EQ(OK, store.GetChannelID("google.com", &key, - base::Bind(&GetChannelIDCallbackNotCalled))); - int delete2_finished = 0; - store.DeleteChannelID("google.com", - base::Bind(&CallCounter, &delete2_finished)); - ASSERT_EQ(1, delete2_finished); - EXPECT_EQ(0u, store.GetChannelIDCount()); - EXPECT_EQ(ERR_FILE_NOT_FOUND, - store.GetChannelID("google.com", &key, - base::Bind(&GetChannelIDCallbackNotCalled))); -} - -TEST_F(DefaultChannelIDStoreTest, TestAsyncDelete) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - std::unique_ptr<crypto::ECPrivateKey> expected_key( - crypto::ECPrivateKey::Create()); - persistent_store->AddChannelID( - ChannelIDStore::ChannelID("a.com", base::Time::FromInternalValue(1), - crypto::ECPrivateKey::Create())); - persistent_store->AddChannelID(ChannelIDStore::ChannelID( - "b.com", base::Time::FromInternalValue(3), expected_key->Copy())); - DefaultChannelIDStore store(persistent_store.get()); - int delete_finished = 0; - store.DeleteChannelID("a.com", - base::Bind(&CallCounter, &delete_finished)); - - AsyncGetChannelIDHelper a_helper; - AsyncGetChannelIDHelper b_helper; - std::unique_ptr<crypto::ECPrivateKey> key; - EXPECT_EQ(0u, store.GetChannelIDCount()); - EXPECT_EQ(ERR_IO_PENDING, - store.GetChannelID("a.com", &key, - base::Bind(&AsyncGetChannelIDHelper::Callback, - base::Unretained(&a_helper)))); - EXPECT_EQ(ERR_IO_PENDING, - store.GetChannelID("b.com", &key, - base::Bind(&AsyncGetChannelIDHelper::Callback, - base::Unretained(&b_helper)))); - - EXPECT_EQ(0, delete_finished); - EXPECT_FALSE(a_helper.called_); - EXPECT_FALSE(b_helper.called_); - // Wait for load & queued tasks. - base::RunLoop().RunUntilIdle(); - EXPECT_EQ(1, delete_finished); - EXPECT_EQ(1u, store.GetChannelIDCount()); - EXPECT_FALSE(key); - EXPECT_TRUE(a_helper.called_); - EXPECT_THAT(a_helper.err_, IsError(ERR_FILE_NOT_FOUND)); - EXPECT_EQ("a.com", a_helper.server_identifier_); - EXPECT_FALSE(a_helper.key_); - EXPECT_TRUE(b_helper.called_); - EXPECT_THAT(b_helper.err_, IsOk()); - EXPECT_EQ("b.com", b_helper.server_identifier_); - EXPECT_TRUE(KeysEqual(expected_key.get(), b_helper.key_.get())); -} - -TEST_F(DefaultChannelIDStoreTest, TestGetAll) { - scoped_refptr<MockPersistentStore> persistent_store(new MockPersistentStore); - DefaultChannelIDStore store(persistent_store.get()); - - EXPECT_EQ(0u, store.GetChannelIDCount()); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "verisign.com", base::Time(), crypto::ECPrivateKey::Create())); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "google.com", base::Time(), crypto::ECPrivateKey::Create())); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "harvard.com", base::Time(), crypto::ECPrivateKey::Create())); - store.SetChannelID(std::make_unique<ChannelIDStore::ChannelID>( - "mit.com", base::Time(), crypto::ECPrivateKey::Create())); - // Wait for load & queued set tasks. - base::RunLoop().RunUntilIdle(); - - EXPECT_EQ(4u, store.GetChannelIDCount()); - ChannelIDStore::ChannelIDList channel_ids; - store.GetAllChannelIDs(base::Bind(GetAllCallback, &channel_ids)); - EXPECT_EQ(4u, channel_ids.size()); -} - -} // namespace net
diff --git a/net/test/channel_id_test_util.cc b/net/test/channel_id_test_util.cc deleted file mode 100644 index 77007f2..0000000 --- a/net/test/channel_id_test_util.cc +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/test/channel_id_test_util.h" - -#include <string> - -#include "crypto/ec_private_key.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace net { - -::testing::AssertionResult KeysEqual(crypto::ECPrivateKey* key1, - crypto::ECPrivateKey* key2) { - std::string public_key1, public_key2; - EXPECT_TRUE(key1 && key1->ExportRawPublicKey(&public_key1)); - EXPECT_TRUE(key2 && key2->ExportRawPublicKey(&public_key2)); - if (public_key1 == public_key2) - return ::testing::AssertionSuccess(); - else - return ::testing::AssertionFailure(); -} - -} // namespace net
diff --git a/net/test/channel_id_test_util.h b/net/test/channel_id_test_util.h deleted file mode 100644 index d5c39c47..0000000 --- a/net/test/channel_id_test_util.h +++ /dev/null
@@ -1,25 +0,0 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_TEST_CHANNEL_ID_TEST_UTIL_H_ -#define NET_TEST_CHANNEL_ID_TEST_UTIL_H_ - -#include <string> - -#include "base/compiler_specific.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace crypto { -class ECPrivateKey; -} // namespace crypto - -namespace net { - -::testing::AssertionResult KeysEqual(crypto::ECPrivateKey* key1, - crypto::ECPrivateKey* key2) - WARN_UNUSED_RESULT; - -} // namespace net - -#endif // NET_TEST_CHANNEL_ID_TEST_UTIL_H_
diff --git a/net/url_request/url_request_context.cc b/net/url_request/url_request_context.cc index f9fad8c..8f7623f 100644 --- a/net/url_request/url_request_context.cc +++ b/net/url_request/url_request_context.cc
@@ -32,7 +32,6 @@ : net_log_(nullptr), host_resolver_(nullptr), cert_verifier_(nullptr), - channel_id_service_(nullptr), http_auth_handler_factory_(nullptr), proxy_resolution_service_(nullptr), proxy_delegate_(nullptr), @@ -160,7 +159,6 @@ set_net_log(other->net_log_); set_host_resolver(other->host_resolver_); set_cert_verifier(other->cert_verifier_); - set_channel_id_service(other->channel_id_service_); set_http_auth_handler_factory(other->http_auth_handler_factory_); set_proxy_resolution_service(other->proxy_resolution_service_); set_proxy_delegate(other->proxy_delegate_);
diff --git a/net/url_request/url_request_context.h b/net/url_request/url_request_context.h index 1570b46..d2a989c 100644 --- a/net/url_request/url_request_context.h +++ b/net/url_request/url_request_context.h
@@ -41,7 +41,6 @@ namespace net { class CertVerifier; -class ChannelIDService; class CookieStore; class CTPolicyEnforcer; class CTVerifier; @@ -129,15 +128,6 @@ cert_verifier_ = cert_verifier; } - ChannelIDService* channel_id_service() const { - return channel_id_service_; - } - - void set_channel_id_service( - ChannelIDService* channel_id_service) { - channel_id_service_ = channel_id_service; - } - // Get the proxy service for this context. ProxyResolutionService* proxy_resolution_service() const { return proxy_resolution_service_; @@ -326,7 +316,6 @@ NetLog* net_log_; HostResolver* host_resolver_; CertVerifier* cert_verifier_; - ChannelIDService* channel_id_service_; HttpAuthHandlerFactory* http_auth_handler_factory_; ProxyResolutionService* proxy_resolution_service_; ProxyDelegate* proxy_delegate_;
diff --git a/net/url_request/url_request_context_storage.cc b/net/url_request/url_request_context_storage.cc index 74fb1a4..21da47e 100644 --- a/net/url_request/url_request_context_storage.cc +++ b/net/url_request/url_request_context_storage.cc
@@ -20,7 +20,6 @@ #include "net/http/http_transaction_factory.h" #include "net/log/net_log.h" #include "net/proxy_resolution/proxy_resolution_service.h" -#include "net/ssl/channel_id_service.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_job_factory.h" #include "net/url_request/url_request_throttler_manager.h" @@ -56,12 +55,6 @@ cert_verifier_ = std::move(cert_verifier); } -void URLRequestContextStorage::set_channel_id_service( - std::unique_ptr<ChannelIDService> channel_id_service) { - context_->set_channel_id_service(channel_id_service.get()); - channel_id_service_ = std::move(channel_id_service); -} - void URLRequestContextStorage::set_http_auth_handler_factory( std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory) { context_->set_http_auth_handler_factory(http_auth_handler_factory.get());
diff --git a/net/url_request/url_request_context_storage.h b/net/url_request/url_request_context_storage.h index 0eb99d5..44cae848 100644 --- a/net/url_request/url_request_context_storage.h +++ b/net/url_request/url_request_context_storage.h
@@ -16,7 +16,6 @@ namespace net { class CertVerifier; -class ChannelIDService; class CookieStore; class CTPolicyEnforcer; class CTVerifier; @@ -57,8 +56,6 @@ void set_net_log(std::unique_ptr<NetLog> net_log); void set_host_resolver(std::unique_ptr<HostResolver> host_resolver); void set_cert_verifier(std::unique_ptr<CertVerifier> cert_verifier); - void set_channel_id_service( - std::unique_ptr<ChannelIDService> channel_id_service); void set_http_auth_handler_factory( std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory); void set_proxy_delegate(std::unique_ptr<ProxyDelegate> proxy_delegate); @@ -109,8 +106,6 @@ std::unique_ptr<NetLog> net_log_; std::unique_ptr<HostResolver> host_resolver_; std::unique_ptr<CertVerifier> cert_verifier_; - // The ChannelIDService must outlive the HttpTransactionFactory. - std::unique_ptr<ChannelIDService> channel_id_service_; std::unique_ptr<HttpAuthHandlerFactory> http_auth_handler_factory_; std::unique_ptr<ProxyDelegate> proxy_delegate_; std::unique_ptr<NetworkDelegate> network_delegate_;
diff --git a/net/url_request/url_request_test_util.cc b/net/url_request/url_request_test_util.cc index 70c729a..c8a5f3b 100644 --- a/net/url_request/url_request_test_util.cc +++ b/net/url_request/url_request_test_util.cc
@@ -23,8 +23,6 @@ #include "net/http/http_server_properties_impl.h" #include "net/http/transport_security_state.h" #include "net/proxy_resolution/proxy_retry_info.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/default_channel_id_store.h" #include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/url_request_job.h" #include "net/url_request/url_request_job_factory_impl.h" @@ -108,12 +106,6 @@ nullptr /* store */, nullptr /* netlog */)); } - // In-memory Channel ID service. Must be created before the - // HttpNetworkSession. - if (!channel_id_service()) { - context_storage_.set_channel_id_service( - std::make_unique<ChannelIDService>(new DefaultChannelIDStore(nullptr))); - } if (!http_user_agent_settings() && create_default_http_user_agent_settings_) { context_storage_.set_http_user_agent_settings( std::make_unique<StaticHttpUserAgentSettings>("en-us,fr",
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc index 64e74f8..61243ef 100644 --- a/net/url_request/url_request_unittest.cc +++ b/net/url_request/url_request_unittest.cc
@@ -102,9 +102,7 @@ #include "net/quic/quic_server_info.h" #include "net/socket/socket_test_util.h" #include "net/socket/ssl_client_socket.h" -#include "net/ssl/channel_id_service.h" #include "net/ssl/client_cert_identity_test_util.h" -#include "net/ssl/default_channel_id_store.h" #include "net/ssl/ssl_connection_status_flags.h" #include "net/ssl/ssl_private_key.h" #include "net/ssl/ssl_server_config.h"
diff --git a/remoting/android/java/src/org/chromium/chromoting/SessionConnector.java b/remoting/android/java/src/org/chromium/chromoting/SessionConnector.java index 4153e219..b7ca3ec 100644 --- a/remoting/android/java/src/org/chromium/chromoting/SessionConnector.java +++ b/remoting/android/java/src/org/chromium/chromoting/SessionConnector.java
@@ -68,7 +68,7 @@ } private void doConnect() { - mClient.connectToHost(mAccountName, mAuthToken, mHost.jabberId, mHost.id, + mClient.connectToHost(mAccountName, mAuthToken, mHost.jabberId, mHost.ftlId, mHost.id, mHost.publicKey, mAuthenticator, mFlags, mHost.hostVersion, mHost.hostOs, mHost.hostOsVersion, this); }
diff --git a/remoting/android/java/src/org/chromium/chromoting/jni/Client.java b/remoting/android/java/src/org/chromium/chromoting/jni/Client.java index 817eafd..a48f87c 100644 --- a/remoting/android/java/src/org/chromium/chromoting/jni/Client.java +++ b/remoting/android/java/src/org/chromium/chromoting/jni/Client.java
@@ -85,17 +85,17 @@ } /** Attempts to form a connection to the user-selected host. */ - public void connectToHost(String username, String authToken, String hostJid, + public void connectToHost(String username, String authToken, String hostJid, String hostFtlId, String hostId, String hostPubkey, SessionAuthenticator authenticator, String flags, String hostVersion, String hostOs, String hostOsVersion, ConnectionListener listener) { disconnectFromHost(); mConnectionListener = listener; mAuthenticator = authenticator; - nativeConnect(mNativeJniClient, username, authToken, hostJid, - hostId, hostPubkey, mAuthenticator.getPairingId(hostId), - mAuthenticator.getPairingSecret(hostId), mCapabilityManager.getLocalCapabilities(), - flags, hostVersion, hostOs, hostOsVersion); + nativeConnect(mNativeJniClient, username, authToken, hostJid, hostFtlId, hostId, hostPubkey, + mAuthenticator.getPairingId(hostId), mAuthenticator.getPairingSecret(hostId), + mCapabilityManager.getLocalCapabilities(), flags, hostVersion, hostOs, + hostOsVersion); mConnected = true; } @@ -312,10 +312,10 @@ private native void nativeDestroy(long nativeJniClient); /** Performs the native portion of the connection. */ - private native void nativeConnect(long nativeJniClient, - String username, String authToken, String hostJid, String hostId, String hostPubkey, - String pairId, String pairSecret, String capabilities, String flags, - String hostVersion, String hostOs, String hostOsVersion); + private native void nativeConnect(long nativeJniClient, String username, String authToken, + String hostJid, String hostFtlId, String hostId, String hostPubkey, String pairId, + String pairSecret, String capabilities, String flags, String hostVersion, String hostOs, + String hostOsVersion); /** Native implementation of Client.handleAuthenticationResponse(). */ private native void nativeAuthenticationResponse(
diff --git a/remoting/client/jni/jni_client.cc b/remoting/client/jni/jni_client.cc index 61de27f..fb0afb0 100644 --- a/remoting/client/jni/jni_client.cc +++ b/remoting/client/jni/jni_client.cc
@@ -150,6 +150,7 @@ const base::android::JavaParamRef<jstring>& username, const base::android::JavaParamRef<jstring>& auth_token, const base::android::JavaParamRef<jstring>& host_jid, + const base::android::JavaParamRef<jstring>& host_ftl_id, const base::android::JavaParamRef<jstring>& host_id, const base::android::JavaParamRef<jstring>& host_pubkey, const base::android::JavaParamRef<jstring>& pair_id, @@ -163,6 +164,7 @@ info.username = ConvertJavaStringToUTF8(env, username); info.auth_token = ConvertJavaStringToUTF8(env, auth_token); info.host_jid = ConvertJavaStringToUTF8(env, host_jid); + info.host_ftl_id = ConvertJavaStringToUTF8(env, host_ftl_id); info.host_id = ConvertJavaStringToUTF8(env, host_id); info.host_pubkey = ConvertJavaStringToUTF8(env, host_pubkey); info.pairing_id = ConvertJavaStringToUTF8(env, pair_id);
diff --git a/remoting/client/jni/jni_client.h b/remoting/client/jni/jni_client.h index 7dc889c..936a7714c 100644 --- a/remoting/client/jni/jni_client.h +++ b/remoting/client/jni/jni_client.h
@@ -82,6 +82,7 @@ const base::android::JavaParamRef<jstring>& username, const base::android::JavaParamRef<jstring>& auth_token, const base::android::JavaParamRef<jstring>& host_jid, + const base::android::JavaParamRef<jstring>& host_ftl_id, const base::android::JavaParamRef<jstring>& host_id, const base::android::JavaParamRef<jstring>& host_pubkey, const base::android::JavaParamRef<jstring>& pair_id,
diff --git a/remoting/host/chromoting_messages.h b/remoting/host/chromoting_messages.h index d846dd58..4d5ae53 100644 --- a/remoting/host/chromoting_messages.h +++ b/remoting/host/chromoting_messages.h
@@ -8,7 +8,7 @@ #include <stdint.h> #include "base/files/file_path.h" -#include "base/memory/read_only_shared_memory_region.h" +#include "base/memory/shared_memory_handle.h" #include "base/time/time.h" #include "ipc/ipc_channel_handle.h" #include "ipc/ipc_platform_file.h" @@ -143,7 +143,7 @@ // Notifies the network process that a shared buffer has been created. IPC_MESSAGE_CONTROL(ChromotingDesktopNetworkMsg_CreateSharedBuffer, int /* id */, - base::ReadOnlySharedMemoryRegion /* region */, + base::SharedMemoryHandle /* handle */, uint32_t /* size */) // Request the network process to stop using a shared buffer.
diff --git a/remoting/host/desktop_session_agent.cc b/remoting/host/desktop_session_agent.cc index dd8570f0..71c7dc64 100644 --- a/remoting/host/desktop_session_agent.cc +++ b/remoting/host/desktop_session_agent.cc
@@ -11,7 +11,7 @@ #include "base/logging.h" #include "base/macros.h" #include "base/memory/ptr_util.h" -#include "base/memory/read_only_shared_memory_region.h" +#include "base/memory/shared_memory.h" #include "base/process/process_handle.h" #include "base/time/time.h" #include "build/build_config.h" @@ -72,50 +72,43 @@ desktop_session_agent_->InjectClipboardEvent(event); } -// webrtc::SharedMemory implementation that creates a -// base::ReadOnlySharedMemoryRegion. +// webrtc::SharedMemory implementation that creates base::SharedMemory. class SharedMemoryImpl : public webrtc::SharedMemory { public: static std::unique_ptr<SharedMemoryImpl> Create(size_t size, int id, const base::Closure& on_deleted_callback) { - auto region_mapping = base::ReadOnlySharedMemoryRegion::Create(size); - if (!region_mapping.IsValid()) + std::unique_ptr<base::SharedMemory> memory(new base::SharedMemory()); + if (!memory->CreateAndMapAnonymous(size)) return nullptr; - // The SharedMemoryImpl constructor is private, so std::make_unique can't be - // used. - return base::WrapUnique(new SharedMemoryImpl(std::move(region_mapping), id, - on_deleted_callback)); + return base::WrapUnique( + new SharedMemoryImpl(std::move(memory), size, id, on_deleted_callback)); } ~SharedMemoryImpl() override { on_deleted_callback_.Run(); } - const base::ReadOnlySharedMemoryRegion& region() const { - return region_mapping_.region; - } + base::SharedMemory* shared_memory() { return shared_memory_.get(); } private: - SharedMemoryImpl(base::MappedReadOnlyRegion region_mapping, + SharedMemoryImpl(std::unique_ptr<base::SharedMemory> memory, + size_t size, int id, const base::Closure& on_deleted_callback) - : SharedMemory( - region_mapping.mapping.memory(), - region_mapping.mapping.size(), + : SharedMemory(memory->memory(), + size, // webrtc::ScreenCapturer uses webrtc::SharedMemory::handle() only on Windows. #if defined(OS_WIN) - base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( - region_mapping.region.Duplicate()) - .PassPlatformHandle() - .Take(), + memory->handle().GetHandle(), #else - 0, + 0, #endif - id), - on_deleted_callback_(on_deleted_callback) { - region_mapping_ = std::move(region_mapping); + id), + on_deleted_callback_(on_deleted_callback), + shared_memory_(std::move(memory)) { } base::Closure on_deleted_callback_; - base::MappedReadOnlyRegion region_mapping_; + std::unique_ptr<base::SharedMemory> shared_memory_; + DISALLOW_COPY_AND_ASSIGN(SharedMemoryImpl); }; @@ -149,7 +142,7 @@ send_message_callback_.Run( std::make_unique<ChromotingDesktopNetworkMsg_CreateSharedBuffer>( - buffer->id(), buffer->region().Duplicate(), buffer->size())); + buffer->id(), buffer->shared_memory()->handle(), buffer->size())); } return std::move(buffer);
diff --git a/remoting/host/desktop_session_proxy.cc b/remoting/host/desktop_session_proxy.cc index 66c8796..598eb29 100644 --- a/remoting/host/desktop_session_proxy.cc +++ b/remoting/host/desktop_session_proxy.cc
@@ -43,30 +43,36 @@ #include "base/win/scoped_handle.h" #endif // defined(OS_WIN) +const bool kReadOnly = true; + namespace remoting { class DesktopSessionProxy::IpcSharedBufferCore : public base::RefCountedThreadSafe<IpcSharedBufferCore> { public: - IpcSharedBufferCore(int id, base::ReadOnlySharedMemoryRegion region) - : id_(id) { - mapping_ = region.Map(); - if (!mapping_.IsValid()) { + IpcSharedBufferCore(int id, + base::SharedMemoryHandle handle, + size_t size) + : id_(id), + shared_memory_(handle, kReadOnly), + size_(size) { + if (!shared_memory_.Map(size)) { LOG(ERROR) << "Failed to map a shared buffer: id=" << id - << ", size=" << region.GetSize(); + << ", size=" << size; } } int id() { return id_; } - size_t size() { return mapping_.size(); } - const void* memory() const { return mapping_.memory(); } + size_t size() { return size_; } + void* memory() { return shared_memory_.memory(); } private: virtual ~IpcSharedBufferCore() = default; friend class base::RefCountedThreadSafe<IpcSharedBufferCore>; int id_; - base::ReadOnlySharedMemoryMapping mapping_; + base::SharedMemory shared_memory_; + size_t size_; DISALLOW_COPY_AND_ASSIGN(IpcSharedBufferCore); }; @@ -74,10 +80,7 @@ class DesktopSessionProxy::IpcSharedBuffer : public webrtc::SharedMemory { public: IpcSharedBuffer(scoped_refptr<IpcSharedBufferCore> core) - : SharedMemory(const_cast<void*>(core->memory()), - core->size(), - 0, - core->id()), + : SharedMemory(core->memory(), core->size(), 0, core->id()), core_(core) {} private: @@ -513,12 +516,12 @@ void DesktopSessionProxy::OnCreateSharedBuffer( int id, - base::ReadOnlySharedMemoryRegion region, + base::SharedMemoryHandle handle, uint32_t size) { DCHECK(caller_task_runner_->BelongsToCurrentThread()); scoped_refptr<IpcSharedBufferCore> shared_buffer = - new IpcSharedBufferCore(id, std::move(region)); + new IpcSharedBufferCore(id, handle, size); if (shared_buffer->memory() != nullptr && !shared_buffers_.insert(std::make_pair(id, shared_buffer)).second) {
diff --git a/remoting/host/desktop_session_proxy.h b/remoting/host/desktop_session_proxy.h index 2e8e8da..0df547b 100644 --- a/remoting/host/desktop_session_proxy.h +++ b/remoting/host/desktop_session_proxy.h
@@ -10,8 +10,8 @@ #include <memory> #include "base/macros.h" -#include "base/memory/read_only_shared_memory_region.h" #include "base/memory/ref_counted.h" +#include "base/memory/shared_memory_handle.h" #include "base/memory/weak_ptr.h" #include "base/process/process.h" #include "base/sequenced_task_runner_helpers.h" @@ -171,7 +171,7 @@ // Registers a new shared buffer created by the desktop process. void OnCreateSharedBuffer(int id, - base::ReadOnlySharedMemoryRegion region, + base::SharedMemoryHandle handle, uint32_t size); // Drops a cached reference to the shared buffer.
diff --git a/services/network/network_context_unittest.cc b/services/network/network_context_unittest.cc index 25342e21..7fb306c2 100644 --- a/services/network/network_context_unittest.cc +++ b/services/network/network_context_unittest.cc
@@ -80,8 +80,6 @@ #include "net/proxy_resolution/proxy_info.h" #include "net/proxy_resolution/proxy_resolution_service.h" #include "net/socket/transport_client_socket_pool.h" -#include "net/ssl/channel_id_service.h" -#include "net/ssl/channel_id_store.h" #include "net/test/cert_test_util.h" #include "net/test/embedded_test_server/controllable_http_response.h" #include "net/test/embedded_test_server/default_handlers.h"
diff --git a/services/network/public/cpp/net_ipc_param_traits.cc b/services/network/public/cpp/net_ipc_param_traits.cc index dec6b7ca..8b1ad78 100644 --- a/services/network/public/cpp/net_ipc_param_traits.cc +++ b/services/network/public/cpp/net_ipc_param_traits.cc
@@ -314,26 +314,17 @@ void ParamTraits<scoped_refptr<net::SSLCertRequestInfo>>::Write( base::Pickle* m, const param_type& p) { - WriteParam(m, p != nullptr); - if (p) { - WriteParam(m, p->host_and_port); - WriteParam(m, p->is_proxy); - WriteParam(m, p->cert_authorities); - WriteParam(m, p->cert_key_types); - } + DCHECK(p); + WriteParam(m, p->host_and_port); + WriteParam(m, p->is_proxy); + WriteParam(m, p->cert_authorities); + WriteParam(m, p->cert_key_types); } bool ParamTraits<scoped_refptr<net::SSLCertRequestInfo>>::Read( const base::Pickle* m, base::PickleIterator* iter, param_type* r) { - bool has_object; - if (!ReadParam(m, iter, &has_object)) - return false; - if (!has_object) { - *r = nullptr; - return true; - } *r = new net::SSLCertRequestInfo(); return ReadParam(m, iter, &(*r)->host_and_port) && ReadParam(m, iter, &(*r)->is_proxy) &&
diff --git a/services/tracing/public/cpp/perfetto/perfetto_config.cc b/services/tracing/public/cpp/perfetto/perfetto_config.cc index 558946c..b77f14a 100644 --- a/services/tracing/public/cpp/perfetto/perfetto_config.cc +++ b/services/tracing/public/cpp/perfetto/perfetto_config.cc
@@ -15,7 +15,8 @@ namespace tracing { perfetto::TraceConfig GetDefaultPerfettoConfig( - const base::trace_event::TraceConfig& chrome_config) { + const base::trace_event::TraceConfig& chrome_config, + bool privacy_filtering_enabled) { perfetto::TraceConfig perfetto_config; size_t size_limit = chrome_config.GetTraceBufferSizeInKb(); @@ -52,6 +53,7 @@ trace_event_config->set_target_buffer(0); auto* chrome_proto_config = trace_event_config->mutable_chrome_config(); chrome_proto_config->set_trace_config(chrome_config_string); + chrome_proto_config->set_privacy_filtering_enabled(privacy_filtering_enabled); // Capture system trace events if supported and enabled. The datasources will // only emit events if system tracing is enabled in |chrome_config|. @@ -62,6 +64,8 @@ system_trace_config->set_target_buffer(0); auto* system_chrome_config = system_trace_config->mutable_chrome_config(); system_chrome_config->set_trace_config(chrome_config_string); + system_chrome_config->set_privacy_filtering_enabled( + privacy_filtering_enabled); #endif #if defined(OS_CHROMEOS) @@ -70,6 +74,7 @@ arc_trace_config->set_target_buffer(0); auto* arc_chrome_config = arc_trace_config->mutable_chrome_config(); arc_chrome_config->set_trace_config(chrome_config_string); + arc_chrome_config->set_privacy_filtering_enabled(privacy_filtering_enabled); #endif // Also capture global metadata. @@ -79,7 +84,8 @@ trace_metadata_config->set_target_buffer(0); auto* metadata_chrome_config = trace_metadata_config->mutable_chrome_config(); metadata_chrome_config->set_trace_config(chrome_config_string); - // TODO(ssid): Also set privacy_filtering_enabled here. + metadata_chrome_config->set_privacy_filtering_enabled( + privacy_filtering_enabled); return perfetto_config; }
diff --git a/services/tracing/public/cpp/perfetto/perfetto_config.h b/services/tracing/public/cpp/perfetto/perfetto_config.h index 84fef0f..b461678 100644 --- a/services/tracing/public/cpp/perfetto/perfetto_config.h +++ b/services/tracing/public/cpp/perfetto/perfetto_config.h
@@ -17,7 +17,8 @@ namespace tracing { perfetto::TraceConfig COMPONENT_EXPORT(TRACING_CPP) GetDefaultPerfettoConfig( - const base::trace_event::TraceConfig& chrome_config); + const base::trace_event::TraceConfig& chrome_config, + bool privacy_filtering_enabled = false); } // namespace tracing
diff --git a/services/tracing/public/cpp/trace_event_args_whitelist.cc b/services/tracing/public/cpp/trace_event_args_whitelist.cc index 4904a7f..445199d 100644 --- a/services/tracing/public/cpp/trace_event_args_whitelist.cc +++ b/services/tracing/public/cpp/trace_event_args_whitelist.cc
@@ -36,6 +36,8 @@ "bytes_allocated", nullptr}; const char* const kV8GCAllowedArgs[] = {"num_items", "num_tasks", nullptr}; const char* const kTopLevelFlowAllowedArgs[] = {"task_queue_name", nullptr}; +const char* const kTopLevelIpcRunTaskAllowedArgs[] = {"ipc_program_counter", + nullptr}; const WhitelistEntry kEventArgsWhitelist[] = { {"__metadata", "thread_name", nullptr}, @@ -57,6 +59,7 @@ {"startup", "PrefProvider::PrefProvider", nullptr}, {"task_scheduler", "*", nullptr}, {"toplevel", "*", nullptr}, + {"toplevel.ipc", "TaskAnnotator::RunTask", kTopLevelIpcRunTaskAllowedArgs}, {TRACE_DISABLED_BY_DEFAULT("cpu_profiler"), "*", nullptr}, // Redefined the string since MemoryDumpManager::kTraceCategory causes // static initialization of this struct.
diff --git a/services/tracing/public/cpp/tracing_features.cc b/services/tracing/public/cpp/tracing_features.cc index 7b446da..43a19ec 100644 --- a/services/tracing/public/cpp/tracing_features.cc +++ b/services/tracing/public/cpp/tracing_features.cc
@@ -19,6 +19,11 @@ const base::Feature kTracingPerfettoBackend{"TracingPerfettoBackend", base::FEATURE_ENABLED_BY_DEFAULT}; +// Causes the BackgroundTracingManager to upload proto messages via UMA, +// rather than JSON via the crash frontend. +const base::Feature kBackgroundTracingProtoOutput{ + "BackgroundTracingProtoOutput", base::FEATURE_DISABLED_BY_DEFAULT}; + // Runs the tracing service as an in-process browser service. const base::Feature kTracingServiceInProcess { "TracingServiceInProcess",
diff --git a/services/tracing/public/cpp/tracing_features.h b/services/tracing/public/cpp/tracing_features.h index fca060e..4d282d6e 100644 --- a/services/tracing/public/cpp/tracing_features.h +++ b/services/tracing/public/cpp/tracing_features.h
@@ -21,6 +21,9 @@ extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature kTracingServiceInProcess; +extern const COMPONENT_EXPORT(TRACING_CPP) base::Feature + kBackgroundTracingProtoOutput; + } // namespace features namespace tracing {
diff --git a/testing/variations/fieldtrial_testing_config.json b/testing/variations/fieldtrial_testing_config.json index 2a77e53b..9717cc7 100644 --- a/testing/variations/fieldtrial_testing_config.json +++ b/testing/variations/fieldtrial_testing_config.json
@@ -3003,41 +3003,22 @@ ], "experiments": [ { - "name": "RecordMetrics_1", + "name": "Preconnect_60_20190502", "params": { "area_rank_scale": "0", "contains_image_scale": "50", "is_in_iframe_scale": "0", "is_same_host_scale": "0", "is_url_incremented_scale": "100", + "preconnect_skip_link_scores": "true", "ratio_area_scale": "100", "same_origin_preconnecting_allowed": "true", "source_engagement_score_scale": "100", - "target_engagement_score_scale": "100" - }, - "enable_features": [ - "NavigationPredictor" - ] - } - ] - } - ], - "NetUnusedIdleSocketTimeout": [ - { - "platforms": [ - "android", - "windows", - "mac", - "chromeos", - "linux" - ], - "experiments": [ - { - "name": "Enabled_60_seconds_20190408", - "params": { + "target_engagement_score_scale": "100", "unused_idle_socket_timeout_seconds": "60" }, "enable_features": [ + "NavigationPredictor", "NetUnusedIdleSocketTimeout" ] } @@ -3333,9 +3314,7 @@ "OmniboxRichEntitySuggestions", "OmniboxTailSuggestions", "OmniboxUIExperimentMaxAutocompleteMatches", - "QueryInOmnibox", - "ZeroSuggestRedirectToChrome", - "ZeroSuggestSwapTitleAndUrl" + "QueryInOmnibox" ] } ] @@ -3348,7 +3327,6 @@ { "name": "AndroidExperiments", "enable_features": [ - "OmniboxBreakWordsAtUnderscores", "OmniboxDisplayTitleForCurrentUrl", "OmniboxUIExperimentHideSteadyStateUrlScheme", "OmniboxUIExperimentHideSteadyStateUrlTrivialSubdomains" @@ -3364,7 +3342,6 @@ { "name": "iOSExperiments", "enable_features": [ - "OmniboxBreakWordsAtUnderscores", "OmniboxDisplayTitleForCurrentUrl" ] }
diff --git a/third_party/android_deps/libs/com_google_ar_core/LICENSE b/third_party/android_deps/libs/com_google_ar_core/LICENSE index aeaf58a..89d8dff8 100644 --- a/third_party/android_deps/libs/com_google_ar_core/LICENSE +++ b/third_party/android_deps/libs/com_google_ar_core/LICENSE
@@ -1,4 +1,5 @@ =============================================================================== +Section 1: ARCore SDK binary files The following files: tools/arcoreimg/linux/arcoreimg @@ -14,9 +15,10 @@ [https://developers.google.com/terms/](https://developers.google.com/terms/) =============================================================================== +Section 2: ARCore SDK source files -Except as indicated previously in this LICENSE file, -files in this SDK are licensed as follows: +Except as indicated in sections 1 above and section 3 below, files in this SDK +are licensed as follows: Copyright (c) 2017, Google Inc. Licensed under the Apache License, Version 2.0 (the "License"); @@ -26,153 +28,13069 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION -1. Definitions. - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. -2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. -3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. -4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. -5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. -6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. -7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. -8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. -9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. -END OF TERMS AND CONDITIONS + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +=============================================================================== +Section 3: ARCore SDK dependencies + +******************************************************************************* +Android Activity Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Android Annotations Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Android Architecture Components +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Android Architecture Components Core Library +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Android Architecture Components Lifecycle Library +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Android Architecture Components Lifecycle Runtime Library +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2018 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Android Compat Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Android Compatibility Library v4 +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Android Compatibility Library v7 +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Android Core UI Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Android Core Utils Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Android Design Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Android Fragments Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Android Graphics Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Android Media Compat Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Android Transition Support Library +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +AndroidX async layout inflater. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +AndroidX card view library. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +AndroidX document file library. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +AndroidX interpolator library. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +AndroidX legacy core UI libraries. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +AndroidX local broadcast manager library. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +AndroidX print library. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +AndroidX sliding pane layout library. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +AndroidX swipe refresh layout library. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +AndroidX transition library. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +AndroidX versioned parcelable library. +******************************************************************************* + + Copyright (c) 2005-2018, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Animal Sniffer +******************************************************************************* +The MIT License + +Copyright (c) 2008 Kohsuke Kawaguchi and codehaus.org. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +******************************************************************************* +Checker Framework Annotations +******************************************************************************* +A few parts of the Checker Framework have more permissive licenses. + + * The annotations are licensed under the MIT License. (The text of this + license appears below.) More specifically, all the parts of the Checker + Framework that you might want to include with your own program use the + MIT License. This is the checker-qual.jar file and all the files that + appear in it: every file in a qual/ directory, plus NullnessUtils.java + and RegexUtil.java. In addition, the cleanroom implementations of + third-party annotations, which the Checker Framework recognizes as + aliases for its own annotations, are licensed under the MIT License. + +=========================================================================== + +MIT License: + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +=========================================================================== + +******************************************************************************* +Compatibility Libraries for Android asynclayoutinflater. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android collections. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android coordinatorlayout. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android cursoradapter. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android customview. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android drawerlayout. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android interpolator. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android loader. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android localbroadcastmanager. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Compatibility Libraries for Android support-slices_core +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +Compatibility Libraries for Android viewpager. +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS +******************************************************************************* +Error Prone +******************************************************************************* + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Firebase Common +******************************************************************************* + + +ICU4C: + +COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later) + +Copyright © 1991-2018 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. + +--------------------- + +Third-Party Software Licenses + +This section contains third-party software notices and/or additional +terms for licensed third-party software components included within ICU +libraries. + +1. ICU License - ICU 1.8.1 to ICU 57.1 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1995-2016 International Business Machines Corporation and others +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY +SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +All trademarks and registered trademarks mentioned herein are the +property of their respective owners. + +2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt) + + # The Google Chrome software developed by Google is licensed under + # the BSD license. Other software included in this distribution is + # provided under other licenses, as set forth below. + # + # The BSD License + # http://opensource.org/licenses/bsd-license.php + # Copyright (C) 2006-2008, Google Inc. + # + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # Redistributions in binary form must reproduce the above + # copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided with + # the distribution. + # Neither the name of Google Inc. nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # + # + # The word list in cjdict.txt are generated by combining three word lists + # listed below with further processing for compound word breaking. The + # frequency is generated with an iterative training against Google web + # corpora. + # + # * Libtabe (Chinese) + # - https://sourceforge.net/project/?group_id=1519 + # - Its license terms and conditions are shown below. + # + # * IPADIC (Japanese) + # - http://chasen.aist-nara.ac.jp/chasen/distribution.html + # - Its license terms and conditions are shown below. + # + # ---------COPYING.libtabe ---- BEGIN-------------------- + # + # /* + # * Copyright (c) 1999 TaBE Project. + # * Copyright (c) 1999 Pai-Hsiang Hsiao. + # * All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the TaBE Project nor the names of its + # * contributors may be used to endorse or promote products derived + # * from this software without specific prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # /* + # * Copyright (c) 1999 Computer Systems and Communication Lab, + # * Institute of Information Science, Academia + # * Sinica. All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the Computer Systems and Communication Lab + # * nor the names of its contributors may be used to endorse or + # * promote products derived from this software without specific + # * prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, + # University of Illinois + # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 + # + # ---------------COPYING.libtabe-----END-------------------------------- + # + # + # ---------------COPYING.ipadic-----BEGIN------------------------------- + # + # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science + # and Technology. All Rights Reserved. + # + # Use, reproduction, and distribution of this software is permitted. + # Any copy of this software, whether in its original form or modified, + # must include both the above copyright notice and the following + # paragraphs. + # + # Nara Institute of Science and Technology (NAIST), + # the copyright holders, disclaims all warranties with regard to this + # software, including all implied warranties of merchantability and + # fitness, in no event shall NAIST be liable for + # any special, indirect or consequential damages or any damages + # whatsoever resulting from loss of use, data or profits, whether in an + # action of contract, negligence or other tortuous action, arising out + # of or in connection with the use or performance of this software. + # + # A large portion of the dictionary entries + # originate from ICOT Free Software. The following conditions for ICOT + # Free Software applies to the current dictionary as well. + # + # Each User may also freely distribute the Program, whether in its + # original form or modified, to any third party or parties, PROVIDED + # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear + # on, or be attached to, the Program, which is distributed substantially + # in the same form as set out herein and that such intended + # distribution, if actually made, will neither violate or otherwise + # contravene any of the laws and regulations of the countries having + # jurisdiction over the User or the intended distribution itself. + # + # NO WARRANTY + # + # The program was produced on an experimental basis in the course of the + # research and development conducted during the project and is provided + # to users as so produced on an experimental basis. Accordingly, the + # program is provided without any warranty whatsoever, whether express, + # implied, statutory or otherwise. The term "warranty" used herein + # includes, but is not limited to, any warranty of the quality, + # performance, merchantability and fitness for a particular purpose of + # the program and the nonexistence of any infringement or violation of + # any right of any third party. + # + # Each user of the program will agree and understand, and be deemed to + # have agreed and understood, that there is no warranty whatsoever for + # the program and, accordingly, the entire risk arising from or + # otherwise connected with the program is assumed by the user. + # + # Therefore, neither ICOT, the copyright holder, or any other + # organization that participated in or was otherwise related to the + # development of the program and their respective officials, directors, + # officers and other employees shall be held liable for any and all + # damages, including, without limitation, general, special, incidental + # and consequential damages, arising out of or otherwise in connection + # with the use or inability to use the program or any product, material + # or result produced or otherwise obtained by using the program, + # regardless of whether they have been advised of, or otherwise had + # knowledge of, the possibility of such damages at any time during the + # project or thereafter. Each user will be deemed to have agreed to the + # foregoing by his or her commencement of use of the program. The term + # "use" as used herein includes, but is not limited to, the use, + # modification, copying and distribution of the program and the + # production of secondary products from the program. + # + # In the case where the program, whether in its original form or + # modified, was distributed or delivered to or received by a user from + # any person, organization or entity other than ICOT, unless it makes or + # grants independently of ICOT any specific warranty to the user in + # writing, such person, organization or entity, will also be exempted + # from and not be held liable to the user for any such damages as noted + # above as far as the program is concerned. + # + # ---------------COPYING.ipadic-----END---------------------------------- + +3. Lao Word Break Dictionary Data (laodict.txt) + + # Copyright (c) 2013 International Business Machines Corporation + # and others. All Rights Reserved. + # + # Project: http://code.google.com/p/lao-dictionary/ + # Dictionary: http://lao-dictionary.googlecode.com/git/Lao-Dictionary.txt + # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt + # (copied below) + # + # This file is derived from the above dictionary, with slight + # modifications. + # ---------------------------------------------------------------------- + # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, + # are permitted provided that the following conditions are met: + # + # + # Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. Redistributions in + # binary form must reproduce the above copyright notice, this list of + # conditions and the following disclaimer in the documentation and/or + # other materials provided with the distribution. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # OF THE POSSIBILITY OF SUCH DAMAGE. + # -------------------------------------------------------------------------- + +4. Burmese Word Break Dictionary Data (burmesedict.txt) + + # Copyright (c) 2014 International Business Machines Corporation + # and others. All Rights Reserved. + # + # This list is part of a project hosted at: + # github.com/kanyawtech/myanmar-karen-word-lists + # + # -------------------------------------------------------------------------- + # Copyright (c) 2013, LeRoy Benjamin Sharon + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: Redistributions of source code must retain the above + # copyright notice, this list of conditions and the following + # disclaimer. Redistributions in binary form must reproduce the + # above copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided + # with the distribution. + # + # Neither the name Myanmar Karen Word Lists, nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + # -------------------------------------------------------------------------- + +5. Time Zone Database + + ICU uses the public domain data and code derived from Time Zone +Database for its time zone support. The ownership of the TZ database +is explained in BCP 175: Procedure for Maintaining the Time Zone +Database section 7. + + # 7. Database Ownership + # + # The TZ database itself is not an IETF Contribution or an IETF + # document. Rather it is a pre-existing and regularly updated work + # that is in the public domain, and is intended to remain in the + # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do + # not apply to the TZ Database or contributions that individuals make + # to it. Should any claims be made and substantiated against the TZ + # Database, the organization that is providing the IANA + # Considerations defined in this RFC, under the memorandum of + # understanding with the IETF, currently ICANN, may act in accordance + # with all competent court orders. No ownership claims will be made + # by ICANN or the IETF Trust on the database or the code. Any person + # making a contribution to the database or code waives all rights to + # future claims in that contribution or in the TZ Database. + +6. Google double-conversion + +Copyright 2006-2011, the V8 project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +JSR 305: + +Copyright (c) 2007-2009, JSR305 expert group +All rights reserved. + +http://www.opensource.org/licenses/bsd-license.php + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the JSR305 expert group nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +PCRE: + +PCRE LICENCE +------------ + +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Release 8 of PCRE is distributed under the terms of the "BSD" licence, as +specified below. The documentation for PCRE, supplied in the "doc" +directory, is distributed under the same terms as the software itself. The data +in the testdata directory is not copyrighted and is in the public domain. + +The basic library functions are written in C and are freestanding. Also +included in the distribution is a set of C++ wrapper functions, and a +just-in-time compiler that can be used to optimize pattern matching. These +are both optional features that can be omitted when the library is built. + + +THE BASIC LIBRARY FUNCTIONS +--------------------------- + +Written by: Philip Hazel +Email local part: ph10 +Email domain: cam.ac.uk + +University of Cambridge Computing Service, +Cambridge, England. + +Copyright (c) 1997-2017 University of Cambridge +All rights reserved. + + +PCRE JUST-IN-TIME COMPILATION SUPPORT +------------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Emain domain: freemail.hu + +Copyright(c) 2010-2017 Zoltan Herczeg +All rights reserved. + + +STACK-LESS JUST-IN-TIME COMPILER +-------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Emain domain: freemail.hu + +Copyright(c) 2009-2017 Zoltan Herczeg +All rights reserved. + + +THE C++ WRAPPER FUNCTIONS +------------------------- + +Contributed by: Google Inc. + +Copyright (c) 2007-2012, Google Inc. +All rights reserved. + + +THE "BSD" LICENCE +----------------- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the name of Google + Inc. nor the names of their contributors may be used to endorse or + promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +End + + +Protobuf Nano: + +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + + +RE2: + +// Copyright (c) 2009 The RE2 Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +darts_clone: + +Copyright (c) 2008-2011, Susumu Yata +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +- Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +STL: + +SGI STL + +The STL portion of GNU libstdc++ that is used with gcc3 and gcc4 is licensed +under the GPL, with the following exception: + +# As a special exception, you may use this file as part of a free software +# library without restriction. Specifically, if other files instantiate +# templates or use macros or inline functions from this file, or you compile +# this file and link it with other files to produce an executable, this +# file does not by itself cause the resulting executable to be covered by +# the GNU General Public License. This exception does not however +# invalidate any other reasons why the executable file might be covered by +# the GNU General Public License. + + + +UTF: + +UTF-8 Library + +The authors of this software are Rob Pike and Ken Thompson. + Copyright (c) 1998-2002 by Lucent Technologies. +Permission to use, copy, modify, and distribute this software for any +purpose without fee is hereby granted, provided that this entire notice +is included in all copies of any software which is or includes a copy +or modification of this software and in all copies of the supporting +documentation for such software. +THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED +WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY +REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY +OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + + +flatbuffers: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +safeparcel: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +zlib: + +(extracted from README, except for match.S) + +Copyright notice: + + (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. + +(extracted from match.S, for match.S only) + +Copyright (C) 1998, 2007 Brian Raiter <breadbox@muppetlabs.com> + +This software is provided 'as-is', without any express or implied +warranty. In no event will the author be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +******************************************************************************* +Glide +******************************************************************************* +Covers library/ + +Copyright 2014 Google, Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are +permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, this list of + conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright notice, this list + of conditions and the following disclaimer in the documentation and/or other materials + provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY GOOGLE, INC. ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE, INC. OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those of the +authors and should not be interpreted as representing official policies, either expressed +or implied, of Google, Inc. + +-------------------------------------------------------------------------- +Covers third_party/gif_decoder + +Copyright (c) 2013 Xcellent Creations, Inc. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +-------------------------------------------------------------------------- +Covers third_party/disklrucache + +Copyright 2012 Jake Wharton +Copyright 2011 The Android Open Source Project + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +-------------------------------------------------------------------------- +Covers third_party/gif_encoder/AnimatedGifEncoder.java and +third_party/gif_encoder/LZWEncoder.java: + +No copyright asserted on the source code of this class. May be used for any +purpose, however, refer to the Unisys LZW patent for restrictions on use of +the associated LZWEncoder class. Please forward any corrections to +kweiner@fmsware.com. + +----------------------------------------------------------------------------- +Covers third_party/gif_encoder/NeuQuant.java + +Copyright (c) 1994 Anthony Dekker + +NEUQUANT Neural-Net quantization algorithm by Anthony Dekker, 1994. See +"Kohonen neural networks for optimal colour quantization" in "Network: +Computation in Neural Systems" Vol. 5 (1994) pp 351-367. for a discussion of +the algorithm. + +Any party obtaining a copy of these files from the author, directly or +indirectly, is granted, free of charge, a full and unrestricted irrevocable, +world-wide, paid up, royalty-free, nonexclusive right and license to deal in +this software and documentation files (the "Software"), including without +limitation the rights to use, copy, modify, merge, publish, distribute, +sublicense, and/or sell copies of the Software, and to permit persons who +receive copies from any such party to do so, with the only requirement being +that this copyright notice remain intact. + +******************************************************************************* +Google Auto +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Guava JDK5 +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +Guava JDK7 +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +******************************************************************************* +J2ObjC +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +JSR 250 +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +JSR 305 +******************************************************************************* +Copyright (c) 2007-2009, JSR305 expert group +All rights reserved. + +http://www.opensource.org/licenses/bsd-license.php + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the JSR305 expert group nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +******************************************************************************* +Material Components for Android +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +concurrent_futures +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + +******************************************************************************* +firebase_database +******************************************************************************* + + +ICU4C: + +COPYRIGHT AND PERMISSION NOTICE (ICU 58 and later) + +Copyright © 1991-2018 Unicode, Inc. All rights reserved. +Distributed under the Terms of Use in http://www.unicode.org/copyright.html. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Unicode data files and any associated documentation +(the "Data Files") or Unicode software and any associated documentation +(the "Software") to deal in the Data Files or Software +without restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, and/or sell copies of +the Data Files or Software, and to permit persons to whom the Data Files +or Software are furnished to do so, provided that either +(a) this copyright and permission notice appear with all copies +of the Data Files or Software, or +(b) this copyright and permission notice appear in associated +Documentation. + +THE DATA FILES AND SOFTWARE ARE PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT OF THIRD PARTY RIGHTS. +IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS INCLUDED IN THIS +NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL +DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, +DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER +TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THE DATA FILES OR SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, +use or other dealings in these Data Files or Software without prior +written authorization of the copyright holder. + +--------------------- + +Third-Party Software Licenses + +This section contains third-party software notices and/or additional +terms for licensed third-party software components included within ICU +libraries. + +1. ICU License - ICU 1.8.1 to ICU 57.1 + +COPYRIGHT AND PERMISSION NOTICE + +Copyright (c) 1995-2016 International Business Machines Corporation and others +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, provided that the above +copyright notice(s) and this permission notice appear in all copies of +the Software and that both the above copyright notice(s) and this +permission notice appear in supporting documentation. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR +HOLDERS INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY +SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER +RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF +CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +Except as contained in this notice, the name of a copyright holder +shall not be used in advertising or otherwise to promote the sale, use +or other dealings in this Software without prior written authorization +of the copyright holder. + +All trademarks and registered trademarks mentioned herein are the +property of their respective owners. + +2. Chinese/Japanese Word Break Dictionary Data (cjdict.txt) + + # The Google Chrome software developed by Google is licensed under + # the BSD license. Other software included in this distribution is + # provided under other licenses, as set forth below. + # + # The BSD License + # http://opensource.org/licenses/bsd-license.php + # Copyright (C) 2006-2008, Google Inc. + # + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions are met: + # + # Redistributions of source code must retain the above copyright notice, + # this list of conditions and the following disclaimer. + # Redistributions in binary form must reproduce the above + # copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided with + # the distribution. + # Neither the name of Google Inc. nor the names of its + # contributors may be used to endorse or promote products derived from + # this software without specific prior written permission. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + # + # + # The word list in cjdict.txt are generated by combining three word lists + # listed below with further processing for compound word breaking. The + # frequency is generated with an iterative training against Google web + # corpora. + # + # * Libtabe (Chinese) + # - https://sourceforge.net/project/?group_id=1519 + # - Its license terms and conditions are shown below. + # + # * IPADIC (Japanese) + # - http://chasen.aist-nara.ac.jp/chasen/distribution.html + # - Its license terms and conditions are shown below. + # + # ---------COPYING.libtabe ---- BEGIN-------------------- + # + # /* + # * Copyright (c) 1999 TaBE Project. + # * Copyright (c) 1999 Pai-Hsiang Hsiao. + # * All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the TaBE Project nor the names of its + # * contributors may be used to endorse or promote products derived + # * from this software without specific prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # /* + # * Copyright (c) 1999 Computer Systems and Communication Lab, + # * Institute of Information Science, Academia + # * Sinica. All rights reserved. + # * + # * Redistribution and use in source and binary forms, with or without + # * modification, are permitted provided that the following conditions + # * are met: + # * + # * . Redistributions of source code must retain the above copyright + # * notice, this list of conditions and the following disclaimer. + # * . Redistributions in binary form must reproduce the above copyright + # * notice, this list of conditions and the following disclaimer in + # * the documentation and/or other materials provided with the + # * distribution. + # * . Neither the name of the Computer Systems and Communication Lab + # * nor the names of its contributors may be used to endorse or + # * promote products derived from this software without specific + # * prior written permission. + # * + # * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # * REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + # * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # * OF THE POSSIBILITY OF SUCH DAMAGE. + # */ + # + # Copyright 1996 Chih-Hao Tsai @ Beckman Institute, + # University of Illinois + # c-tsai4@uiuc.edu http://casper.beckman.uiuc.edu/~c-tsai4 + # + # ---------------COPYING.libtabe-----END-------------------------------- + # + # + # ---------------COPYING.ipadic-----BEGIN------------------------------- + # + # Copyright 2000, 2001, 2002, 2003 Nara Institute of Science + # and Technology. All Rights Reserved. + # + # Use, reproduction, and distribution of this software is permitted. + # Any copy of this software, whether in its original form or modified, + # must include both the above copyright notice and the following + # paragraphs. + # + # Nara Institute of Science and Technology (NAIST), + # the copyright holders, disclaims all warranties with regard to this + # software, including all implied warranties of merchantability and + # fitness, in no event shall NAIST be liable for + # any special, indirect or consequential damages or any damages + # whatsoever resulting from loss of use, data or profits, whether in an + # action of contract, negligence or other tortuous action, arising out + # of or in connection with the use or performance of this software. + # + # A large portion of the dictionary entries + # originate from ICOT Free Software. The following conditions for ICOT + # Free Software applies to the current dictionary as well. + # + # Each User may also freely distribute the Program, whether in its + # original form or modified, to any third party or parties, PROVIDED + # that the provisions of Section 3 ("NO WARRANTY") will ALWAYS appear + # on, or be attached to, the Program, which is distributed substantially + # in the same form as set out herein and that such intended + # distribution, if actually made, will neither violate or otherwise + # contravene any of the laws and regulations of the countries having + # jurisdiction over the User or the intended distribution itself. + # + # NO WARRANTY + # + # The program was produced on an experimental basis in the course of the + # research and development conducted during the project and is provided + # to users as so produced on an experimental basis. Accordingly, the + # program is provided without any warranty whatsoever, whether express, + # implied, statutory or otherwise. The term "warranty" used herein + # includes, but is not limited to, any warranty of the quality, + # performance, merchantability and fitness for a particular purpose of + # the program and the nonexistence of any infringement or violation of + # any right of any third party. + # + # Each user of the program will agree and understand, and be deemed to + # have agreed and understood, that there is no warranty whatsoever for + # the program and, accordingly, the entire risk arising from or + # otherwise connected with the program is assumed by the user. + # + # Therefore, neither ICOT, the copyright holder, or any other + # organization that participated in or was otherwise related to the + # development of the program and their respective officials, directors, + # officers and other employees shall be held liable for any and all + # damages, including, without limitation, general, special, incidental + # and consequential damages, arising out of or otherwise in connection + # with the use or inability to use the program or any product, material + # or result produced or otherwise obtained by using the program, + # regardless of whether they have been advised of, or otherwise had + # knowledge of, the possibility of such damages at any time during the + # project or thereafter. Each user will be deemed to have agreed to the + # foregoing by his or her commencement of use of the program. The term + # "use" as used herein includes, but is not limited to, the use, + # modification, copying and distribution of the program and the + # production of secondary products from the program. + # + # In the case where the program, whether in its original form or + # modified, was distributed or delivered to or received by a user from + # any person, organization or entity other than ICOT, unless it makes or + # grants independently of ICOT any specific warranty to the user in + # writing, such person, organization or entity, will also be exempted + # from and not be held liable to the user for any such damages as noted + # above as far as the program is concerned. + # + # ---------------COPYING.ipadic-----END---------------------------------- + +3. Lao Word Break Dictionary Data (laodict.txt) + + # Copyright (c) 2013 International Business Machines Corporation + # and others. All Rights Reserved. + # + # Project: http://code.google.com/p/lao-dictionary/ + # Dictionary: http://lao-dictionary.googlecode.com/git/Lao-Dictionary.txt + # License: http://lao-dictionary.googlecode.com/git/Lao-Dictionary-LICENSE.txt + # (copied below) + # + # This file is derived from the above dictionary, with slight + # modifications. + # ---------------------------------------------------------------------- + # Copyright (C) 2013 Brian Eugene Wilson, Robert Martin Campbell. + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, + # are permitted provided that the following conditions are met: + # + # + # Redistributions of source code must retain the above copyright notice, this + # list of conditions and the following disclaimer. Redistributions in + # binary form must reproduce the above copyright notice, this list of + # conditions and the following disclaimer in the documentation and/or + # other materials provided with the distribution. + # + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + # FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + # COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + # INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + # SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + # HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + # STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + # OF THE POSSIBILITY OF SUCH DAMAGE. + # -------------------------------------------------------------------------- + +4. Burmese Word Break Dictionary Data (burmesedict.txt) + + # Copyright (c) 2014 International Business Machines Corporation + # and others. All Rights Reserved. + # + # This list is part of a project hosted at: + # github.com/kanyawtech/myanmar-karen-word-lists + # + # -------------------------------------------------------------------------- + # Copyright (c) 2013, LeRoy Benjamin Sharon + # All rights reserved. + # + # Redistribution and use in source and binary forms, with or without + # modification, are permitted provided that the following conditions + # are met: Redistributions of source code must retain the above + # copyright notice, this list of conditions and the following + # disclaimer. Redistributions in binary form must reproduce the + # above copyright notice, this list of conditions and the following + # disclaimer in the documentation and/or other materials provided + # with the distribution. + # + # Neither the name Myanmar Karen Word Lists, nor the names of its + # contributors may be used to endorse or promote products derived + # from this software without specific prior written permission. + # + # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND + # CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, + # INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + # MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + # DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS + # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + # TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR + # TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF + # THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + # SUCH DAMAGE. + # -------------------------------------------------------------------------- + +5. Time Zone Database + + ICU uses the public domain data and code derived from Time Zone +Database for its time zone support. The ownership of the TZ database +is explained in BCP 175: Procedure for Maintaining the Time Zone +Database section 7. + + # 7. Database Ownership + # + # The TZ database itself is not an IETF Contribution or an IETF + # document. Rather it is a pre-existing and regularly updated work + # that is in the public domain, and is intended to remain in the + # public domain. Therefore, BCPs 78 [RFC5378] and 79 [RFC3979] do + # not apply to the TZ Database or contributions that individuals make + # to it. Should any claims be made and substantiated against the TZ + # Database, the organization that is providing the IANA + # Considerations defined in this RFC, under the memorandum of + # understanding with the IETF, currently ICANN, may act in accordance + # with all competent court orders. No ownership claims will be made + # by ICANN or the IETF Trust on the database or the code. Any person + # making a contribution to the database or code waives all rights to + # future claims in that contribution or in the TZ Database. + +6. Google double-conversion + +Copyright 2006-2011, the V8 project authors. All rights reserved. +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the following + disclaimer in the documentation and/or other materials provided + with the distribution. + * Neither the name of Google Inc. nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +JSR 305: + +Copyright (c) 2007-2009, JSR305 expert group +All rights reserved. + +http://www.opensource.org/licenses/bsd-license.php + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the JSR305 expert group nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +PCRE: + +PCRE LICENCE +------------ + +PCRE is a library of functions to support regular expressions whose syntax +and semantics are as close as possible to those of the Perl 5 language. + +Release 8 of PCRE is distributed under the terms of the "BSD" licence, as +specified below. The documentation for PCRE, supplied in the "doc" +directory, is distributed under the same terms as the software itself. The data +in the testdata directory is not copyrighted and is in the public domain. + +The basic library functions are written in C and are freestanding. Also +included in the distribution is a set of C++ wrapper functions, and a +just-in-time compiler that can be used to optimize pattern matching. These +are both optional features that can be omitted when the library is built. + + +THE BASIC LIBRARY FUNCTIONS +--------------------------- + +Written by: Philip Hazel +Email local part: ph10 +Email domain: cam.ac.uk + +University of Cambridge Computing Service, +Cambridge, England. + +Copyright (c) 1997-2017 University of Cambridge +All rights reserved. + + +PCRE JUST-IN-TIME COMPILATION SUPPORT +------------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Emain domain: freemail.hu + +Copyright(c) 2010-2017 Zoltan Herczeg +All rights reserved. + + +STACK-LESS JUST-IN-TIME COMPILER +-------------------------------- + +Written by: Zoltan Herczeg +Email local part: hzmester +Emain domain: freemail.hu + +Copyright(c) 2009-2017 Zoltan Herczeg +All rights reserved. + + +THE C++ WRAPPER FUNCTIONS +------------------------- + +Contributed by: Google Inc. + +Copyright (c) 2007-2012, Google Inc. +All rights reserved. + + +THE "BSD" LICENCE +----------------- + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of the University of Cambridge nor the name of Google + Inc. nor the names of their contributors may be used to endorse or + promote products derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + +End + + +Protobuf Nano: + +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + + +RE2: + +// Copyright (c) 2009 The RE2 Authors. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +darts_clone: + +Copyright (c) 2008-2011, Susumu Yata +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +- Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + + +STL: + +SGI STL + +The STL portion of GNU libstdc++ that is used with gcc3 and gcc4 is licensed +under the GPL, with the following exception: + +# As a special exception, you may use this file as part of a free software +# library without restriction. Specifically, if other files instantiate +# templates or use macros or inline functions from this file, or you compile +# this file and link it with other files to produce an executable, this +# file does not by itself cause the resulting executable to be covered by +# the GNU General Public License. This exception does not however +# invalidate any other reasons why the executable file might be covered by +# the GNU General Public License. + + + +UTF: + +UTF-8 Library + +The authors of this software are Rob Pike and Ken Thompson. + Copyright (c) 1998-2002 by Lucent Technologies. +Permission to use, copy, modify, and distribute this software for any +purpose without fee is hereby granted, provided that this entire notice +is included in all copies of any software which is or includes a copy +or modification of this software and in all copies of the supporting +documentation for such software. +THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED +WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY +REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY +OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + + +flatbuffers: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +safeparcel: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +zlib: + +(extracted from README, except for match.S) + +Copyright notice: + + (C) 1995-2013 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* receiving +lengthy legal documents to sign. The sources are provided for free but without +warranty of any kind. The library has been entirely written by Jean-loup +Gailly and Mark Adler; it does not include third-party code. + +If you redistribute modified sources, we would appreciate that you include in +the file ChangeLog history information documenting your changes. Please read +the FAQ for more information on the distribution of modified source versions. + +(extracted from match.S, for match.S only) + +Copyright (C) 1998, 2007 Brian Raiter <breadbox@muppetlabs.com> + +This software is provided 'as-is', without any express or implied +warranty. In no event will the author be held liable for any damages +arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. +2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. +3. This notice may not be removed or altered from any source distribution. + +******************************************************************************* +firebase_database_collection +******************************************************************************* + + +JSR 250: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +absl: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + +safeparcel: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +JSR 305: + +Copyright (c) 2007-2009, JSR305 expert group +All rights reserved. + +http://www.opensource.org/licenses/bsd-license.php + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + * Neither the name of the JSR305 expert group nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + + +Protobuf Nano: + +Copyright 2008, Google Inc. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Code generated by the Protocol Buffer compiler is owned by the owner +of the input file used when generating it. This code is not +standalone and requires a support library to be linked with it. This +support library is itself covered by the above license. + + +STL: + +SGI STL + +The STL portion of GNU libstdc++ that is used with gcc3 and gcc4 is licensed +under the GPL, with the following exception: + +# As a special exception, you may use this file as part of a free software +# library without restriction. Specifically, if other files instantiate +# templates or use macros or inline functions from this file, or you compile +# this file and link it with other files to produce an executable, this +# file does not by itself cause the resulting executable to be covered by +# the GNU General Public License. This exception does not however +# invalidate any other reasons why the executable file might be covered by +# the GNU General Public License. + + + +flatbuffers: + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2014 Google Inc. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +glm +******************************************************************************* +The MIT License + +Copyright (c) 2005 - 2013 G-Truc Creation + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +******************************************************************************* +javagl_obj +******************************************************************************* + +www.javagl.de - Obj + +Copyright (c) 2008-2015 Marco Hutter - http://www.javagl.de + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +******************************************************************************* +safeparcel +******************************************************************************* + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +******************************************************************************* +savedstate +******************************************************************************* + + Copyright (c) 2005-2011, The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + +
diff --git a/third_party/android_deps/libs/com_google_dagger_dagger/README.chromium b/third_party/android_deps/libs/com_google_dagger_dagger/README.chromium index 7adc1e2..35b7f2c 100644 --- a/third_party/android_deps/libs/com_google_dagger_dagger/README.chromium +++ b/third_party/android_deps/libs/com_google_dagger_dagger/README.chromium
@@ -3,8 +3,8 @@ URL: https://github.com/google/dagger Version: 2.17 License: Apache 2.0 -License File: LICENSE -Security Critical: yes +License File: NOT_SHIPPED +Security Critical: no Description: A fast dependency injector for Android and Java.
diff --git a/third_party/android_deps/libs/javax_inject_javax_inject/README.chromium b/third_party/android_deps/libs/javax_inject_javax_inject/README.chromium index dc2aa5b..ce5d4c8b 100644 --- a/third_party/android_deps/libs/javax_inject_javax_inject/README.chromium +++ b/third_party/android_deps/libs/javax_inject_javax_inject/README.chromium
@@ -3,8 +3,8 @@ URL: http://code.google.com/p/atinject/ Version: 1 License: Apache Version 2.0 -License File: LICENSE -Security Critical: yes +License File: NOT_SHIPPED +Security Critical: no Description: The javax.inject API
diff --git a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h index c88a10c9..692a45f1 100644 --- a/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h +++ b/third_party/blink/public/common/scheduler/web_scheduler_tracked_feature.h
@@ -44,7 +44,20 @@ // Recorded only for the main frame. kHasScriptableFramesInMultipleTabs = 18, - kMaxValue = kHasScriptableFramesInMultipleTabs + // Whether the page tried to request a permission regardless of the outcome. + // TODO(altimin): Track this more accurately depending on the data. + // See permission.mojom for more details. + kRequestedGeolocationPermission = 19, + kRequestedNotificationsPermission = 20, + kRequestedMIDIPermission = 21, + kRequestedAudioCapturePermission = 22, + kRequestedVideoCapturePermission = 23, + kRequestedSensorsPermission = 24, + // This covers all background-related permissions, including background sync, + // background fetch and others. + kRequestedBackgroundWorkPermission = 26, + + kMaxValue = kRequestedBackgroundWorkPermission }; } // namespace scheduler
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc index 0b6fd06..679754a0 100644 --- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc +++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.cc
@@ -235,9 +235,7 @@ v8::Local<v8::Function>(), global_interface_template); if (!disable_eval_pending_.IsEmpty()) { - script_state_->GetContext()->AllowCodeGenerationFromStrings(false); - script_state_->GetContext()->SetErrorMessageForCodeGenerationFromStrings( - V8String(isolate_, disable_eval_pending_)); + DisableEvalInternal(disable_eval_pending_); disable_eval_pending_ = String(); } @@ -248,6 +246,17 @@ return true; } +void WorkerOrWorkletScriptController::DisableEvalInternal( + const String& error_message) { + DCHECK(IsContextInitialized()); + DCHECK(!error_message.IsEmpty()); + + ScriptState::Scope scope(script_state_); + script_state_->GetContext()->AllowCodeGenerationFromStrings(false); + script_state_->GetContext()->SetErrorMessageForCodeGenerationFromStrings( + V8String(isolate_, error_message)); +} + ScriptValue WorkerOrWorkletScriptController::EvaluateInternal( const ScriptSourceCode& source_code, SanitizeScriptErrors sanitize_script_errors, @@ -370,6 +379,23 @@ } void WorkerOrWorkletScriptController::DisableEval(const String& error_message) { + DCHECK(!error_message.IsEmpty()); + // Currently, this can be called before or after + // WorkerOrWorkletScriptController::Initialize() because of messy + // worker/worklet initialization sequences. Tidy them up after + // off-the-main-thread worker script fetch is enabled by default, make + // sure to call WorkerOrWorkletScriptController::DisableEval() after + // WorkerOrWorkletScriptController::Initialize(), and remove + // |disable_eval_pending_| logic (https://crbug.com/960770). + if (IsContextInitialized()) { + DisableEvalInternal(error_message); + return; + } + // `eval()` will actually be disabled on + // WorkerOrWorkletScriptController::Initialize() to be called from + // WorkerThread::InitializeOnWorkerThread() immediately and synchronously + // after returning here. Keep the error message until that time. + DCHECK(disable_eval_pending_.IsEmpty()); disable_eval_pending_ = error_message; }
diff --git a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h index cdf69f97..03f829b 100644 --- a/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h +++ b/third_party/blink/renderer/bindings/core/v8/worker_or_worklet_script_controller.h
@@ -77,6 +77,7 @@ // Used by WorkerGlobalScope: void RethrowExceptionFromImportedScript(ErrorEvent*, ExceptionState&); + // Disables `eval()` on JavaScript. This must be called before Evaluate(). void DisableEval(const String&); // Used by Inspector agents: @@ -103,6 +104,8 @@ private: class ExecutionState; + void DisableEvalInternal(const String& error_message); + // Evaluate a script file in the current execution environment. ScriptValue EvaluateInternal(const ScriptSourceCode&, SanitizeScriptErrors, @@ -118,7 +121,10 @@ Member<ScriptState> script_state_; scoped_refptr<DOMWrapperWorld> world_; + + // Keeps the error message for `eval()` on JavaScript until Initialize(). String disable_eval_pending_; + bool execution_forbidden_; scoped_refptr<RejectedPromises> rejected_promises_;
diff --git a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc index 049ec64..b31247f 100644 --- a/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc +++ b/third_party/blink/renderer/core/css/properties/longhands/longhands_custom.cc
@@ -5504,6 +5504,8 @@ strictness_id != CSSValueID::kMandatory) return axis_value; CSSValue* strictness_value = css_property_parser_helpers::ConsumeIdent(range); + if (strictness_id == CSSValueID::kProximity) + return axis_value; // Shortest serialization. auto* pair = MakeGarbageCollected<CSSValuePair>( axis_value, strictness_value, CSSValuePair::kDropIdenticalValues); return pair;
diff --git a/third_party/blink/renderer/core/dom/document.cc b/third_party/blink/renderer/core/dom/document.cc index e89a4c7b..07da90f 100644 --- a/third_party/blink/renderer/core/dom/document.cc +++ b/third_party/blink/renderer/core/dom/document.cc
@@ -3500,7 +3500,7 @@ if (!ShouldComplete()) return false; - if (frame_) { + if (frame_ && !UnloadStarted()) { frame_->Client()->RunScriptsAtDocumentIdle(); // Injected scripts may have disconnected this frame.
diff --git a/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc b/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc index e90c3ba..e0c550f 100644 --- a/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc +++ b/third_party/blink/renderer/core/editing/commands/indent_outdent_command.cc
@@ -48,15 +48,15 @@ // "Outdent" command considers <BLOCKQUOTE style="display:inline"> makes // indentation. static bool IsHTMLListOrBlockquoteElement(const Node* node) { - if (!node || !node->IsHTMLElement()) + const auto* element = DynamicTo<HTMLElement>(node); + if (!element) return false; if (!node->GetLayoutObject() || !node->GetLayoutObject()->IsLayoutBlock()) return false; - const HTMLElement& element = ToHTMLElement(*node); // TODO(yosin): We should check OL/UL element has "list-style-type" CSS // property to make sure they layout contents as list. - return IsHTMLUListElement(element) || IsHTMLOListElement(element) || - element.HasTagName(kBlockquoteTag); + return IsHTMLUListElement(*element) || IsHTMLOListElement(*element) || + element->HasTagName(kBlockquoteTag); } IndentOutdentCommand::IndentOutdentCommand(Document& document, @@ -93,7 +93,7 @@ // We should calculate visible range in list item because inserting new // list element will change visibility of list item, e.g. :first-child // CSS selector. - HTMLElement* new_list = ToHTMLElement(GetDocument().CreateElement( + auto* new_list = To<HTMLElement>(GetDocument().CreateElement( list_element->TagQName(), CreateElementFlags::ByCloneNode(), g_null_atom)); InsertNodeBefore(new_list, selected_list_item, editing_state); @@ -210,7 +210,7 @@ VisiblePosition visible_end_of_paragraph = EndOfParagraph(visible_start_of_paragraph); - HTMLElement* enclosing_element = ToHTMLElement( + auto* enclosing_element = To<HTMLElement>( EnclosingNodeOfType(visible_start_of_paragraph.DeepEquivalent(), &IsHTMLListOrBlockquoteElement)); // We can't outdent if there is no place to go! @@ -299,9 +299,9 @@ // may be at different indentations. const Position& previous_element = PreviousCandidate(visible_start_of_paragraph.DeepEquivalent()); - HTMLElement* const previous_element_is_blockquote = - ToHTMLElement(EnclosingNodeOfType(previous_element, - &IsHTMLListOrBlockquoteElement)); + auto* const previous_element_is_blockquote = + To<HTMLElement>(EnclosingNodeOfType(previous_element, + &IsHTMLListOrBlockquoteElement)); const bool is_previous_blockquote_same = !previous_element_is_blockquote || (enclosing_element == previous_element_is_blockquote);
diff --git a/third_party/blink/renderer/core/editing/commands/insert_list_command.cc b/third_party/blink/renderer/core/editing/commands/insert_list_command.cc index 2876169..ddf9e35 100644 --- a/third_party/blink/renderer/core/editing/commands/insert_list_command.cc +++ b/third_party/blink/renderer/core/editing/commands/insert_list_command.cc
@@ -88,10 +88,10 @@ return nullptr; Element* next_sibling = ElementTraversal::NextSibling(*list); - if (!next_sibling || !next_sibling->IsHTMLElement()) + auto* next_list = DynamicTo<HTMLElement>(next_sibling); + if (!next_list) return list; - HTMLElement* next_list = ToHTMLElement(next_sibling); GetDocument().UpdateStyleAndLayout(); if (CanMergeLists(*list, *next_list)) { MergeIdenticalElements(list, next_list, editing_state);
diff --git a/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command.cc b/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command.cc index c4fdebbc..305e7f7 100644 --- a/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command.cc +++ b/third_party/blink/renderer/core/editing/commands/insert_paragraph_separator_command.cc
@@ -213,9 +213,7 @@ insertion_position.ParentAnchoredEquivalent().ComputeContainerNode()); Node* list_child_node = EnclosingListChild( insertion_position.ParentAnchoredEquivalent().ComputeContainerNode()); - HTMLElement* list_child = list_child_node && list_child_node->IsHTMLElement() - ? ToHTMLElement(list_child_node) - : nullptr; + auto* list_child = DynamicTo<HTMLElement>(list_child_node); Position canonical_pos = CreateVisiblePosition(insertion_position).DeepEquivalent(); if (!start_block || !start_block->NonShadowBoundaryParentNode() || @@ -253,7 +251,7 @@ // |positionAvoidingSpecialElementBoundary()| creates new A element and // move to another place. list_child = - ToHTMLElement(EnclosingAnchorElement(original_insertion_position)); + To<HTMLElement>(EnclosingAnchorElement(original_insertion_position)); } GetDocument().UpdateStyleAndLayout();
diff --git a/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc b/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc index dd5a661..0d2ada1 100644 --- a/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc +++ b/third_party/blink/renderer/core/editing/commands/replace_selection_command.cc
@@ -503,13 +503,13 @@ } static bool IsHTMLHeaderElement(const Node* a) { - if (!a || !a->IsHTMLElement()) + const auto* element = DynamicTo<HTMLElement>(a); + if (!element) return false; - const HTMLElement& element = ToHTMLElement(*a); - return element.HasTagName(kH1Tag) || element.HasTagName(kH2Tag) || - element.HasTagName(kH3Tag) || element.HasTagName(kH4Tag) || - element.HasTagName(kH5Tag) || element.HasTagName(kH6Tag); + return element->HasTagName(kH1Tag) || element->HasTagName(kH2Tag) || + element->HasTagName(kH3Tag) || element->HasTagName(kH4Tag) || + element->HasTagName(kH5Tag) || element->HasTagName(kH6Tag); } static bool HaveSameTagName(Element* a, Element* b) { @@ -562,9 +562,9 @@ EditingStyle* new_inline_style = MakeGarbageCollected<EditingStyle>(inline_style); if (inline_style) { - if (element->IsHTMLElement()) { + auto* html_element = DynamicTo<HTMLElement>(element); + if (html_element) { Vector<QualifiedName> attributes; - HTMLElement* html_element = ToHTMLElement(element); DCHECK(html_element); if (new_inline_style->ConflictsWithImplicitStyleOfElement( @@ -701,29 +701,28 @@ node && node != past_end_node; node = next) { next = NodeTraversal::Next(*node); - if (!node->IsHTMLElement()) + auto* element = DynamicTo<HTMLElement>(node); + if (!element) continue; // moveElementOutOfAncestor() in a previous iteration might have failed, // and |node| might have been detached from the document tree. if (!node->isConnected()) continue; - HTMLElement& element = ToHTMLElement(*node); - if (IsProhibitedParagraphChild(element.localName())) { + if (IsProhibitedParagraphChild(element->localName())) { if (HTMLElement* paragraph_element = - ToHTMLElement(EnclosingElementWithTag( - Position::InParentBeforeNode(element), kPTag))) { - MoveElementOutOfAncestor(&element, paragraph_element, editing_state); + To<HTMLElement>(EnclosingElementWithTag( + Position::InParentBeforeNode(*element), kPTag))) { + MoveElementOutOfAncestor(element, paragraph_element, editing_state); if (editing_state->IsAborted()) return; } } - if (IsHTMLHeaderElement(&element)) { - if (HTMLElement* header_element = ToHTMLElement( - HighestEnclosingNodeOfType(Position::InParentBeforeNode(element), - IsHTMLHeaderElement))) { - MoveElementOutOfAncestor(&element, header_element, editing_state); + if (IsHTMLHeaderElement(element)) { + if (auto* header_element = To<HTMLElement>(HighestEnclosingNodeOfType( + Position::InParentBeforeNode(*element), IsHTMLHeaderElement))) { + MoveElementOutOfAncestor(element, header_element, editing_state); if (editing_state->IsAborted()) return; } @@ -840,7 +839,8 @@ } static bool FollowBlockElementStyle(const Node* node) { - if (!node->IsHTMLElement()) + const auto* element = DynamicTo<HTMLElement>(node); + if (!element) return false; // When content is inserted into an empty block, use the original style // instead of the block style. @@ -852,11 +852,11 @@ return false; } - const HTMLElement& element = ToHTMLElement(*node); - return IsListItem(node) || IsTableCell(node) || element.HasTagName(kPreTag) || - element.HasTagName(kH1Tag) || element.HasTagName(kH2Tag) || - element.HasTagName(kH3Tag) || element.HasTagName(kH4Tag) || - element.HasTagName(kH5Tag) || element.HasTagName(kH6Tag); + return IsListItem(node) || IsTableCell(node) || + element->HasTagName(kPreTag) || element->HasTagName(kH1Tag) || + element->HasTagName(kH2Tag) || element->HasTagName(kH3Tag) || + element->HasTagName(kH4Tag) || element->HasTagName(kH5Tag) || + element->HasTagName(kH6Tag); } // Remove style spans before insertion if they are unnecessary. It's faster @@ -1000,12 +1000,12 @@ if (IsEnclosingBlock(node)) return false; - if (!node->IsHTMLElement()) + const auto* element = DynamicTo<HTMLElement>(node); + if (!element) return false; // We can skip over elements whose class attribute is // one of our internal classes. - const HTMLElement* element = ToHTMLElement(node); return EditingStyle::ElementIsStyledSpanOrHTMLEquivalent(element); } @@ -1014,7 +1014,7 @@ const Position& insertion_pos) { Element* containing_block = EnclosingBlock(insertion_pos.ComputeContainerNode()); - return ToHTMLElement(HighestEnclosingNodeOfType( + return To<HTMLElement>(HighestEnclosingNodeOfType( insertion_pos, IsInlineHTMLElementWithStyle, kCannotCrossEditingBoundary, containing_block)); } @@ -1349,9 +1349,9 @@ (IsHTMLListElement(inserted_nodes.RefNode()->firstChild()))) && block_start && block_start->GetLayoutObject()->IsListItem() && HasEditableStyle(*block_start->parentNode())) { - inserted_nodes.SetRefNode( - InsertAsListItems(ToHTMLElement(inserted_nodes.RefNode()), block_start, - insertion_pos, inserted_nodes, editing_state)); + inserted_nodes.SetRefNode(InsertAsListItems( + To<HTMLElement>(inserted_nodes.RefNode()), block_start, insertion_pos, + inserted_nodes, editing_state)); if (editing_state->IsAborted()) return; } else { @@ -1948,7 +1948,7 @@ EditingState* editing_state) { while (list_element->HasOneChild() && IsHTMLListElement(list_element->firstChild())) - list_element = ToHTMLElement(list_element->firstChild()); + list_element = To<HTMLElement>(list_element->firstChild()); GetDocument().UpdateStyleAndLayout(); bool is_start = IsStartOfParagraph(CreateVisiblePosition(insert_pos));
diff --git a/third_party/blink/renderer/core/editing/editing_strategy.cc b/third_party/blink/renderer/core/editing/editing_strategy.cc index add81ff5..535905a 100644 --- a/third_party/blink/renderer/core/editing/editing_strategy.cc +++ b/third_party/blink/renderer/core/editing/editing_strategy.cc
@@ -10,7 +10,8 @@ namespace { blink::EUserSelect UsedValueOfUserSelect(const blink::Node& node) { - if (node.IsHTMLElement() && ToHTMLElement(node).IsTextControl()) + auto* html_element = blink::DynamicTo<blink::HTMLElement>(node); + if (html_element && html_element->IsTextControl()) return blink::EUserSelect::kText; if (!node.GetLayoutObject()) return blink::EUserSelect::kNone;
diff --git a/third_party/blink/renderer/core/editing/editing_style_test.cc b/third_party/blink/renderer/core/editing/editing_style_test.cc index 6f433d6..fcce278 100644 --- a/third_party/blink/renderer/core/editing/editing_style_test.cc +++ b/third_party/blink/renderer/core/editing/editing_style_test.cc
@@ -23,9 +23,9 @@ UpdateAllLifecyclePhasesForTest(); EditingStyle* editing_style = MakeGarbageCollected<EditingStyle>( - ToHTMLElement(GetDocument().getElementById("s2"))); + To<HTMLElement>(GetDocument().getElementById("s2"))); editing_style->MergeInlineStyleOfElement( - ToHTMLElement(GetDocument().getElementById("s1")), + To<HTMLElement>(GetDocument().getElementById("s1")), EditingStyle::kOverrideValues); EXPECT_FALSE(editing_style->Style()->HasProperty(CSSPropertyID::kFloat))
diff --git a/third_party/blink/renderer/core/editing/editing_style_utilities.cc b/third_party/blink/renderer/core/editing/editing_style_utilities.cc index ebfeb55..d184475 100644 --- a/third_party/blink/renderer/core/editing/editing_style_utilities.cc +++ b/third_party/blink/renderer/core/editing/editing_style_utilities.cc
@@ -94,7 +94,7 @@ // blockquote, to help us differentiate those styles from ones that the user // has applied. This helps us get the color of content pasted into // blockquotes right. - wrapping_style->RemoveStyleAddedByElement(ToHTMLElement(EnclosingNodeOfType( + wrapping_style->RemoveStyleAddedByElement(To<HTMLElement>(EnclosingNodeOfType( FirstPositionInOrBeforeNode(*context), IsMailHTMLBlockquoteElement, kCanCrossEditingBoundary)));
diff --git a/third_party/blink/renderer/core/editing/editing_utilities.cc b/third_party/blink/renderer/core/editing/editing_utilities.cc index b4c2371..bdb50218 100644 --- a/third_party/blink/renderer/core/editing/editing_utilities.cc +++ b/third_party/blink/renderer/core/editing/editing_utilities.cc
@@ -1120,14 +1120,14 @@ } bool IsPresentationalHTMLElement(const Node* node) { - if (!node->IsHTMLElement()) + const auto* element = DynamicTo<HTMLElement>(node); + if (!element) return false; - const HTMLElement& element = ToHTMLElement(*node); - return element.HasTagName(kUTag) || element.HasTagName(kSTag) || - element.HasTagName(kStrikeTag) || element.HasTagName(kITag) || - element.HasTagName(kEmTag) || element.HasTagName(kBTag) || - element.HasTagName(kStrongTag); + return element->HasTagName(kUTag) || element->HasTagName(kSTag) || + element->HasTagName(kStrikeTag) || element->HasTagName(kITag) || + element->HasTagName(kEmTag) || element->HasTagName(kBTag) || + element->HasTagName(kStrongTag); } Element* AssociatedElementOf(const Position& position) { @@ -1374,19 +1374,20 @@ } bool IsMailHTMLBlockquoteElement(const Node* node) { - if (!node || !node->IsHTMLElement()) + const auto* element = DynamicTo<HTMLElement>(*node); + if (!element) return false; - const HTMLElement& element = ToHTMLElement(*node); - return element.HasTagName(kBlockquoteTag) && - element.getAttribute("type") == "cite"; + return element->HasTagName(kBlockquoteTag) && + element->getAttribute("type") == "cite"; } bool ElementCannotHaveEndTag(const Node& node) { - if (!node.IsHTMLElement()) + auto* html_element = DynamicTo<HTMLElement>(node); + if (!html_element) return false; - return !ToHTMLElement(node).ShouldSerializeEndTag(); + return !html_element->ShouldSerializeEndTag(); } // FIXME: indexForVisiblePosition and visiblePositionForIndex use TextIterators @@ -1498,16 +1499,16 @@ } bool IsNonTableCellHTMLBlockElement(const Node* node) { - if (!node->IsHTMLElement()) + const auto* element = DynamicTo<HTMLElement>(node); + if (!element) return false; - const HTMLElement& element = ToHTMLElement(*node); - return element.HasTagName(kListingTag) || element.HasTagName(kOlTag) || - element.HasTagName(kPreTag) || element.HasTagName(kTableTag) || - element.HasTagName(kUlTag) || element.HasTagName(kXmpTag) || - element.HasTagName(kH1Tag) || element.HasTagName(kH2Tag) || - element.HasTagName(kH3Tag) || element.HasTagName(kH4Tag) || - element.HasTagName(kH5Tag); + return element->HasTagName(kListingTag) || element->HasTagName(kOlTag) || + element->HasTagName(kPreTag) || element->HasTagName(kTableTag) || + element->HasTagName(kUlTag) || element->HasTagName(kXmpTag) || + element->HasTagName(kH1Tag) || element->HasTagName(kH2Tag) || + element->HasTagName(kH3Tag) || element->HasTagName(kH4Tag) || + element->HasTagName(kH5Tag); } bool IsBlockFlowElement(const Node& node) { @@ -1695,12 +1696,12 @@ // TODO(editing-dev): This should probably be reconciled with // HitTestResult::absoluteImageURL. if (IsHTMLImageElement(node) || IsHTMLInputElement(node)) - return ToHTMLElement(node).getAttribute(kSrcAttr); + return To<HTMLElement>(node).getAttribute(kSrcAttr); if (IsSVGImageElement(node)) return ToSVGElement(node).ImageSourceURL(); if (IsHTMLEmbedElement(node) || IsHTMLObjectElement(node) || IsHTMLCanvasElement(node)) - return ToHTMLElement(node).ImageSourceURL(); + return To<HTMLElement>(node).ImageSourceURL(); return AtomicString(); }
diff --git a/third_party/blink/renderer/core/editing/finder/find_buffer.cc b/third_party/blink/renderer/core/editing/finder/find_buffer.cc index 77df41b7..3006efe 100644 --- a/third_party/blink/renderer/core/editing/finder/find_buffer.cc +++ b/third_party/blink/renderer/core/editing/finder/find_buffer.cc
@@ -138,19 +138,19 @@ } bool ShouldIgnoreContents(const Node& node) { - if (!node.IsHTMLElement()) + const auto* element = DynamicTo<HTMLElement>(node); + if (!element) return false; - const HTMLElement& element = ToHTMLElement(node); - return (!element.ShouldSerializeEndTag() && !IsHTMLInputElement(element)) || - IsHTMLIFrameElement(element) || IsHTMLImageElement(element) || - IsHTMLLegendElement(element) || IsHTMLMeterElement(element) || - IsHTMLObjectElement(element) || IsHTMLProgressElement(element) || - (IsHTMLSelectElement(element) && - ToHTMLSelectElement(element).UsesMenuList()) || - IsHTMLStyleElement(element) || IsHTMLScriptElement(element) || - IsHTMLVideoElement(element) || IsHTMLAudioElement(element) || - (element.GetDisplayLockContext() && - !element.GetDisplayLockContext()->IsActivatable()); + return (!element->ShouldSerializeEndTag() && !IsHTMLInputElement(*element)) || + IsHTMLIFrameElement(*element) || IsHTMLImageElement(*element) || + IsHTMLLegendElement(*element) || IsHTMLMeterElement(*element) || + IsHTMLObjectElement(*element) || IsHTMLProgressElement(*element) || + (IsHTMLSelectElement(*element) && + ToHTMLSelectElement(*element).UsesMenuList()) || + IsHTMLStyleElement(*element) || IsHTMLScriptElement(*element) || + IsHTMLVideoElement(*element) || IsHTMLAudioElement(*element) || + (element->GetDisplayLockContext() && + !element->GetDisplayLockContext()->IsActivatable()); } Node* GetNonSearchableAncestor(const Node& node) { @@ -364,7 +364,7 @@ } // Move the node so we wouldn't encounter this node or its descendants // later. - if (!IsHTMLWBRElement(ToHTMLElement(*node))) + if (!IsHTMLWBRElement(To<HTMLElement>(*node))) buffer_.push_back(kObjectReplacementCharacter); node = FlatTreeTraversal::NextSkippingChildren(*node); continue;
diff --git a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc index 474f6c39..2c3a4c2f 100644 --- a/third_party/blink/renderer/core/editing/ime/input_method_controller.cc +++ b/third_party/blink/renderer/core/editing/ime/input_method_controller.cc
@@ -1471,8 +1471,8 @@ return kWebTextInputTypeTextArea; } - if (element->IsHTMLElement()) { - if (ToHTMLElement(element)->IsDateTimeFieldElement()) + if (auto* html_element = DynamicTo<HTMLElement>(element)) { + if (html_element->IsDateTimeFieldElement()) return kWebTextInputTypeDateTimeField; }
diff --git a/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc b/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc index 9308f12..f5d5511 100644 --- a/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc +++ b/third_party/blink/renderer/core/fetch/blob_bytes_consumer.cc
@@ -7,6 +7,7 @@ #include "third_party/blink/renderer/core/execution_context/execution_context.h" #include "third_party/blink/renderer/core/fetch/form_data_bytes_consumer.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" +#include "third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h" namespace blink {
diff --git a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc index e37cea211..47256d60 100644 --- a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc +++ b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer.cc
@@ -15,6 +15,7 @@ #include "third_party/blink/renderer/platform/loader/fetch/data_pipe_bytes_consumer.h" #include "third_party/blink/renderer/platform/network/encoded_form_data.h" #include "third_party/blink/renderer/platform/network/form_data_encoder.h" +#include "third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/text/text_codec.h" #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h"
diff --git a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc index 105b5fe1..6fff99d 100644 --- a/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc +++ b/third_party/blink/renderer/core/fetch/form_data_bytes_consumer_test.cc
@@ -8,6 +8,7 @@ #include "base/stl_util.h" #include "mojo/public/cpp/bindings/binding_set.h" #include "mojo/public/cpp/system/data_pipe_utils.h" +#include "services/network/public/mojom/data_pipe_getter.mojom-blink.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/public/platform/web_http_body.h"
diff --git a/third_party/blink/renderer/core/html/html_element.h b/third_party/blink/renderer/core/html/html_element.h index a8bcab9..0695267c 100644 --- a/third_party/blink/renderer/core/html/html_element.h +++ b/third_party/blink/renderer/core/html/html_element.h
@@ -26,6 +26,7 @@ #include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/dom/element.h" #include "third_party/blink/renderer/platform/text/text_direction.h" +#include "third_party/blink/renderer/platform/wtf/casting.h" namespace blink { @@ -217,6 +218,11 @@ DEFINE_ELEMENT_TYPE_CASTS(HTMLElement, IsHTMLElement()); +template <> +struct DowncastTraits<HTMLElement> { + static bool AllowFrom(const Node& node) { return node.IsHTMLElement(); } +}; + template <typename T> bool IsElementOfType(const HTMLElement&); template <> @@ -232,7 +238,8 @@ } inline bool Node::HasTagName(const HTMLQualifiedName& name) const { - return IsHTMLElement() && ToHTMLElement(*this).HasTagName(name); + auto* html_element = DynamicTo<HTMLElement>(this); + return html_element && html_element->HasTagName(name); } // Functor used to match HTMLElements with a specific HTML tag when using the
diff --git a/third_party/blink/renderer/core/html/media/html_media_element.cc b/third_party/blink/renderer/core/html/media/html_media_element.cc index b25092f..56c1fe2 100644 --- a/third_party/blink/renderer/core/html/media/html_media_element.cc +++ b/third_party/blink/renderer/core/html/media/html_media_element.cc
@@ -4087,11 +4087,12 @@ void HTMLMediaElement::DefaultEventHandler(Event& event) { if (event.IsKeyboardEvent() && ShouldShowControls()) { - const String& key = ToKeyboardEvent(event).key(); - if (key == "SoftRight") { + // TODO(bokan): Cleanup magic numbers once https://crbug.com/949766 lands. + const int key = + static_cast<int>(ToKeyboardEvent(event).KeyEvent()->dom_key); + if (key == 0x00200310) { // We need to handle the event here rather than in - // MediaControlsTouchlessImpl because right soft key - // event is not sent to JS. + // MediaControlsTouchlessImpl because it is not sent to JS. GetMediaControls()->ShowContextMenu(); event.SetDefaultHandled(); }
diff --git a/third_party/blink/renderer/core/input/keyboard_event_manager.cc b/third_party/blink/renderer/core/input/keyboard_event_manager.cc index 1942097a..97c1ac8 100644 --- a/third_party/blink/renderer/core/input/keyboard_event_manager.cc +++ b/third_party/blink/renderer/core/input/keyboard_event_manager.cc
@@ -133,7 +133,7 @@ } bool KeyboardEventManager::HandleAccessKey(const WebKeyboardEvent& evt) { - // FIXME: Ignoring the state of Shift key is what neither IE nor Firefox do. + // TODO: Ignoring the state of Shift key is what neither IE nor Firefox do. // IE matches lower and upper case access keys regardless of Shift key state - // but if both upper and lower case variants are present in a document, the // correct element is matched based on Shift key state. Firefox only matches @@ -226,11 +226,10 @@ bool event_cancellable = true; if (!should_send_key_events_to_js) { - // TODO(crbug.com/949766) Should cleanup these magic number. + // TODO(bokan) Should cleanup these magic number. https://crbug.com/949766. const int kDomKeysDontSend[] = {0x00200309, 0x00200310}; const int kDomKeysNotCancellabelUnlessInEditor[] = {0x00400031, 0x00400032, 0x00400033}; - for (int dom_key : kDomKeysDontSend) { if (initial_key_event.dom_key == dom_key) send_key_event = false; @@ -242,8 +241,8 @@ } } - // FIXME: it would be fair to let an input method handle KeyUp events before - // DOM dispatch. + // TODO: it would be fair to let an input method handle KeyUp events + // before DOM dispatch. if (initial_key_event.GetType() == WebInputEvent::kKeyUp || initial_key_event.GetType() == WebInputEvent::kChar) { KeyboardEvent* dom_event = KeyboardEvent::Create( @@ -374,7 +373,8 @@ ScrollDirection direction = event->shiftKey() ? kScrollBlockDirectionBackward : kScrollBlockDirectionForward; - // FIXME: enable scroll customization in this case. See crbug.com/410974. + // TODO(bokan): enable scroll customization in this case. See + // crbug.com/410974. if (scroll_manager_->LogicalScroll(direction, kScrollByPage, nullptr, possible_focused_node)) { UseCounter::Count(frame_->GetDocument(),
diff --git a/third_party/blink/renderer/core/messaging/blink_transferable_message.cc b/third_party/blink/renderer/core/messaging/blink_transferable_message.cc index 27c80c3..f2ad6c0 100644 --- a/third_party/blink/renderer/core/messaging/blink_transferable_message.cc +++ b/third_party/blink/renderer/core/messaging/blink_transferable_message.cc
@@ -6,6 +6,7 @@ #include <utility> #include "mojo/public/cpp/base/big_buffer.h" +#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" #include "third_party/blink/public/platform/web_string.h" #include "third_party/blink/renderer/core/imagebitmap/image_bitmap.h" #include "third_party/blink/renderer/platform/blob/blob_data.h"
diff --git a/third_party/blink/renderer/core/paint/block_painter.cc b/third_party/blink/renderer/core/paint/block_painter.cc index 0914ddb..fb676ef 100644 --- a/third_party/blink/renderer/core/paint/block_painter.cc +++ b/third_party/blink/renderer/core/paint/block_painter.cc
@@ -17,6 +17,7 @@ #include "third_party/blink/renderer/core/paint/object_painter.h" #include "third_party/blink/renderer/core/paint/paint_info.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" +#include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/scoped_paint_state.h" #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h" #include "third_party/blink/renderer/platform/graphics/graphics_layer.h" @@ -31,6 +32,11 @@ if (!ShouldPaint(paint_state)) return; + base::Optional<ScopedPaintTimingDetectorBlockPaintHook> + scoped_paint_timing_detector_block_paint_hook; + if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled()) + scoped_paint_timing_detector_block_paint_hook.emplace(layout_block_); + auto paint_offset = paint_state.PaintOffset(); auto& local_paint_info = paint_state.MutablePaintInfo(); PaintPhase original_phase = local_paint_info.phase;
diff --git a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc index 8615f53f7..ab38f86 100644 --- a/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/image_paint_timing_detector.cc
@@ -2,6 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "third_party/blink/renderer/core/paint/image_paint_timing_detector.h" + #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" #include "third_party/blink/renderer/core/inspector/identifiers_factory.h" @@ -252,8 +253,10 @@ if (visual_rect.IsEmpty()) return; uint64_t rect_size = - frame_view_->GetPaintTimingDetector().CalculateVisualSize( - visual_rect, current_paint_chunk_properties); + frame_view_->GetPaintTimingDetector() + .CalculateVisualRect(visual_rect, current_paint_chunk_properties) + .Size() + .Area(); rect_size = DownScaleIfIntrinsicSizeIsSmaller( rect_size, intrinsic_size.Area(), (visual_rect.Width() * visual_rect.Height())); @@ -309,8 +312,10 @@ if (visual_rect.IsEmpty()) return; uint64_t rect_size = - frame_view_->GetPaintTimingDetector().CalculateVisualSize( - visual_rect, current_paint_chunk_properties); + frame_view_->GetPaintTimingDetector() + .CalculateVisualRect(visual_rect, current_paint_chunk_properties) + .Size() + .Area(); rect_size = DownScaleIfIntrinsicSizeIsSmaller( rect_size, intrinsic_size.Area(), visual_rect.Width() * visual_rect.Height());
diff --git a/third_party/blink/renderer/core/paint/inline_painter.cc b/third_party/blink/renderer/core/paint/inline_painter.cc index 490a7efe..b5093cc1 100644 --- a/third_party/blink/renderer/core/paint/inline_painter.cc +++ b/third_party/blink/renderer/core/paint/inline_painter.cc
@@ -11,12 +11,18 @@ #include "third_party/blink/renderer/core/paint/ng/ng_paint_fragment.h" #include "third_party/blink/renderer/core/paint/object_painter.h" #include "third_party/blink/renderer/core/paint/paint_info.h" +#include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/scoped_paint_state.h" #include "third_party/blink/renderer/platform/geometry/layout_point.h" namespace blink { void InlinePainter::Paint(const PaintInfo& paint_info) { + base::Optional<ScopedPaintTimingDetectorBlockPaintHook> + scoped_paint_timing_detector_block_paint_hook; + if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled()) + scoped_paint_timing_detector_block_paint_hook.emplace(layout_inline_); + ScopedPaintState paint_state(layout_inline_, paint_info); auto paint_offset = paint_state.PaintOffset(); const auto& local_paint_info = paint_state.GetPaintInfo(); @@ -44,8 +50,9 @@ if (ShouldPaintDescendantOutlines(local_paint_info.phase)) painter.PaintInlineChildrenOutlines(local_paint_info); if (ShouldPaintSelfOutline(local_paint_info.phase) && - !layout_inline_.IsElementContinuation()) + !layout_inline_.IsElementContinuation()) { painter.PaintOutline(local_paint_info, paint_offset); + } return; }
diff --git a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc index 3b66df4..3126b7c 100644 --- a/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc +++ b/third_party/blink/renderer/core/paint/ng/ng_box_fragment_painter.cc
@@ -32,6 +32,7 @@ #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h" #include "third_party/blink/renderer/core/paint/paint_phase.h" +#include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/paint/scoped_paint_state.h" #include "third_party/blink/renderer/core/paint/scrollable_area_painter.h" #include "third_party/blink/renderer/core/paint/theme_painter.h" @@ -339,6 +340,10 @@ DCHECK(layout_object->IsLayoutBlockFlow()); const auto& layout_block = To<LayoutBlock>(*layout_object); DCHECK(layout_block.ChildrenInline()); + base::Optional<ScopedPaintTimingDetectorBlockPaintHook> + scoped_paint_timing_detector_block_paint_hook; + if (RuntimeEnabledFeatures::FirstContentfulPaintPlusPlusEnabled()) + scoped_paint_timing_detector_block_paint_hook.emplace(layout_block); if (ShouldPaintDescendantOutlines(paint_info.phase)) { ObjectPainter(layout_block).PaintInlineChildrenOutlines(paint_info); } else {
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.cc b/third_party/blink/renderer/core/paint/paint_timing_detector.cc index 41a4bea..dd52bf6 100644 --- a/third_party/blink/renderer/core/paint/paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/paint_timing_detector.cc
@@ -2,10 +2,12 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "third_party/blink/renderer/core/paint/paint_timing_detector.h" + #include "third_party/blink/public/platform/web_input_event.h" #include "third_party/blink/renderer/core/dom/document.h" #include "third_party/blink/renderer/core/frame/local_frame.h" #include "third_party/blink/renderer/core/frame/local_frame_view.h" +#include "third_party/blink/renderer/core/layout/layout_box_model_object.h" #include "third_party/blink/renderer/core/layout/layout_object.h" #include "third_party/blink/renderer/core/layout/layout_view.h" #include "third_party/blink/renderer/core/loader/document_loader.h" @@ -122,10 +124,10 @@ if (!object.HasNonZeroEffectiveOpacity()) return; PaintTimingDetector& detector = frame_view->GetPaintTimingDetector(); - if (detector.GetTextPaintTimingDetector()) { - detector.GetTextPaintTimingDetector()->RecordText( - object, current_paint_chunk_properties); - } + if (!detector.GetTextPaintTimingDetector()) + return; + detector.GetTextPaintTimingDetector()->AggregateText( + object, current_paint_chunk_properties); } void PaintTimingDetector::NotifyNodeRemoved(const LayoutObject& object) { @@ -201,7 +203,7 @@ loader->DidChangePerformanceTiming(); } -uint64_t PaintTimingDetector::CalculateVisualSize( +FloatRect PaintTimingDetector::CalculateVisualRect( const IntRect& visual_rect, const PropertyTreeState& current_paint_chunk_properties) const { // This case should be dealt with outside the function. @@ -215,7 +217,7 @@ float_clip_visual_rect); FloatRect& float_visual_rect = float_clip_visual_rect.Rect(); if (frame_view_->GetFrame().LocalFrameRoot().IsMainFrame()) - return float_visual_rect.Size().Area(); + return float_visual_rect; // OOPIF. The final rect lives in the iframe's root frame space. We need to // project it to the top frame space. LayoutRect layout_visual_rect(float_visual_rect); @@ -223,9 +225,29 @@ .LocalFrameRoot() .View() ->MapToVisualRectInTopFrameSpace(layout_visual_rect); - return (layout_visual_rect.Size().Width() * - layout_visual_rect.Size().Height()) - .ToUnsigned(); + return FloatRect(layout_visual_rect); +} + +ScopedPaintTimingDetectorBlockPaintHook:: + ScopedPaintTimingDetectorBlockPaintHook( + const LayoutBoxModelObject& text_aggregating_block) + : text_aggregating_block_(text_aggregating_block) { + frame_view_ = text_aggregating_block.GetFrameView(); + DCHECK(frame_view_); + PaintTimingDetector& detector = frame_view_->GetPaintTimingDetector(); + if (detector.GetTextPaintTimingDetector()) { + detector.GetTextPaintTimingDetector()->WillWalkTextAggregatingNode(); + } +} + +ScopedPaintTimingDetectorBlockPaintHook:: + ~ScopedPaintTimingDetectorBlockPaintHook() { + DCHECK(frame_view_); + PaintTimingDetector& detector = frame_view_->GetPaintTimingDetector(); + if (detector.GetTextPaintTimingDetector()) { + detector.GetTextPaintTimingDetector()->DidWalkTextAggregatingNode( + text_aggregating_block_); + } } void PaintTimingDetector::Trace(Visitor* visitor) {
diff --git a/third_party/blink/renderer/core/paint/paint_timing_detector.h b/third_party/blink/renderer/core/paint/paint_timing_detector.h index 2ad32710..541654f 100644 --- a/third_party/blink/renderer/core/paint/paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/paint_timing_detector.h
@@ -7,6 +7,7 @@ #include "third_party/blink/public/platform/web_input_event.h" #include "third_party/blink/renderer/core/core_export.h" +#include "third_party/blink/renderer/core/layout/layout_box_model_object.h" #include "third_party/blink/renderer/core/scroll/scroll_types.h" #include "third_party/blink/renderer/platform/heap/member.h" @@ -55,10 +56,8 @@ void NotifyLargestText(base::TimeTicks, uint64_t size); void DidChangePerformanceTiming(); - // |visual_rect| should be an object's bounding rect in the space of - // PropertyTreeState. - uint64_t CalculateVisualSize(const IntRect& visual_rect, - const PropertyTreeState&) const; + FloatRect CalculateVisualRect(const IntRect& visual_rect, + const PropertyTreeState&) const; TextPaintTimingDetector* GetTextPaintTimingDetector() { return text_paint_timing_detector_; @@ -91,6 +90,32 @@ uint64_t largest_text_paint_size_ = 0; }; +// Largest Text Paint aggregates text nodes by these text nodes' ancestors. In +// order to tell whether a text node is contained by another node +// efficiently, LTP relies on the paint order of the rendering tree +// (https://www.w3.org/TR/CSS21/zindex.html). Because of the paint order, we can +// assume that if a text node T is visited during the visit of another node B, +// then B contains T. This class acts as the hook to certain container nodes +// (block object or inline object) to tell whether a text node is their +// descendant. The hook should be placed right before visiting the subtree of an +// container node, so that the constructor and the destructor can tell the start +// and end of the visit. +class ScopedPaintTimingDetectorBlockPaintHook { + DISALLOW_NEW(); + + public: + ScopedPaintTimingDetectorBlockPaintHook( + const LayoutBoxModelObject& text_aggregating_block_); + + ~ScopedPaintTimingDetectorBlockPaintHook(); + + private: + Persistent<LocalFrameView> frame_view_; + const LayoutBoxModelObject& text_aggregating_block_; + + DISALLOW_COPY_AND_ASSIGN(ScopedPaintTimingDetectorBlockPaintHook); +}; + } // namespace blink #endif // THIRD_PARTY_BLINK_RENDERER_CORE_PAINT_PAINT_TIMING_DETECTOR_H_
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc index 413147d..881e7e15 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.cc
@@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "third_party/blink/renderer/core/paint/text_paint_timing_detector.h" + #include <memory> #include "third_party/blink/renderer/core/frame/local_frame.h" @@ -14,7 +16,6 @@ #include "third_party/blink/renderer/core/page/page.h" #include "third_party/blink/renderer/core/paint/paint_layer.h" #include "third_party/blink/renderer/core/paint/paint_timing_detector.h" -#include "third_party/blink/renderer/core/paint/text_paint_timing_detector.h" #include "third_party/blink/renderer/platform/geometry/layout_rect.h" #include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h" #include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h" @@ -25,6 +26,7 @@ // Calculate metrics candidate every 1 second after the first text pre-paint. static constexpr TimeDelta kTimerDelay = TimeDelta::FromSeconds(1); constexpr size_t kTextNodeNumberLimit = 5000; +constexpr size_t kVisitedTextObjectsLimit = 10000; static bool LargeTextFirst(const base::WeakPtr<TextRecord>& a, const base::WeakPtr<TextRecord>& b) { @@ -134,15 +136,48 @@ awaiting_swap_promise_ = false; } -void TextPaintTimingDetector::RecordText( +void TextPaintTimingDetector::AggregateText( const LayoutObject& object, const PropertyTreeState& current_paint_chunk_properties) { if (!is_recording_) return; + // Text nodes are aggregated with the lowest of either block-level block + // element or self-painting inline-level element. + DCHECK_GT(walking_block_stack_.size(), 0u); + AggregateTextToClosestBlock(object, current_paint_chunk_properties); +} + +void TextPaintTimingDetector::AggregateTextToClosestBlock( + const LayoutObject& text_object, + const PropertyTreeState& current_paint_chunk_properties) { + DCHECK_GT(walking_block_stack_.size(), 0u); + + if (visited_text_objects_.Contains(&text_object) || + visited_text_objects_.size() >= kVisitedTextObjectsLimit) + return; + + IntRect visual_rect = text_object.FragmentsVisualRectBoundingBox(); + if (visual_rect.IsEmpty()) + return; + + visited_text_objects_.insert(&text_object); + FloatRect mapped_visual_rect = + frame_view_->GetPaintTimingDetector().CalculateVisualRect( + visual_rect, current_paint_chunk_properties); + if (mapped_visual_rect.Size().Area() == 0) + return; + walking_block_stack_.back().Aggregate(mapped_visual_rect); +} + +void TextPaintTimingDetector::RecordAggregatedText( + const LayoutObject& text_aggregating_object, + uint64_t aggregated_size) { + if (!is_recording_) + return; DCHECK(!records_manager_.HasTooManyNodes()); // TODO(crbug.com/933479): Use LayoutObject::GeneratingNode() to include // anonymous objects' rect. - Node* node = object.GetNode(); + Node* node = text_aggregating_object.GetNode(); if (!node) return; DOMNodeId node_id = DOMNodeIds::IdForNode(node); @@ -150,28 +185,16 @@ records_manager_.MarkNodeReattachedIfNeeded(node_id); - // This metric defines the size of a text by its first size. So it - // early-returns if the text has been recorded. + // This metric defines the size of a text block by its first size. So it + // early-returns if the text block has been recorded. if (records_manager_.HasRecorded(node_id)) return; - uint64_t visual_size = 0; - // Compared to object.FirstFragment().VisualRect(), this will include other - // fragments of the object. - IntRect visual_rect = object.FragmentsVisualRectBoundingBox(); - if (!visual_rect.IsEmpty()) { - visual_size = frame_view_->GetPaintTimingDetector().CalculateVisualSize( - visual_rect, current_paint_chunk_properties); - } - DVLOG(2) << "Node id (" << node_id << "): size=" << visual_size - << ", type=" << object.DebugName(); - - // When visual_size == 0, it either means the text size is 0 or the text is - // out of viewport. In either case, we don't record their time for efficiency. - if (visual_size == 0) { + if (aggregated_size == 0) { records_manager_.RecordInvisibleNode(node_id); } else { - records_manager_.RecordVisibleNode(node_id, visual_size, object); + records_manager_.RecordVisibleNode(node_id, aggregated_size, + text_aggregating_object); } if (records_manager_.HasTooManyNodes()) { @@ -218,13 +241,13 @@ // consumed in a callback earlier than this one. That violates the assumption // that only one or zero callback will be called after one OnPaintFinished. DCHECK_GT(texts_queued_for_paint_time_.size(), 0UL); - while (!texts_queued_for_paint_time_.empty()) { + while (!texts_queued_for_paint_time_.IsEmpty()) { base::WeakPtr<TextRecord>& record = texts_queued_for_paint_time_.front(); DCHECK(visible_node_map_.Contains(record->node_id)); DCHECK_EQ(record->paint_time, base::TimeTicks()); record->paint_time = timestamp; - texts_queued_for_paint_time_.pop(); + texts_queued_for_paint_time_.pop_front(); is_result_invalidated_ = true; } } @@ -274,7 +297,7 @@ void TextRecordsManager::QueueToMeasurePaintTime( base::WeakPtr<TextRecord> record) { - texts_queued_for_paint_time_.emplace(record); + texts_queued_for_paint_time_.push_back(std::move(record)); } bool TextRecordsManager::HasTooManyNodes() const { @@ -303,4 +326,16 @@ is_result_invalidated_ = false; return new_largest_paint_candidate; } + +void TextPaintTimingDetector::WillWalkTextAggregatingNode() { + walking_block_stack_.push_back(BlockInfo()); +} + +void TextPaintTimingDetector::DidWalkTextAggregatingNode( + const LayoutBoxModelObject& text_aggregating_block) { + uint64_t aggregated_size = walking_block_stack_.back().AggregatedTextSize(); + if (aggregated_size > 0) + RecordAggregatedText(text_aggregating_block, aggregated_size); + walking_block_stack_.pop_back(); +} } // namespace blink
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h index 6cd1b60..32e1483 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector.h +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector.h
@@ -15,12 +15,14 @@ #include "third_party/blink/renderer/platform/timer.h" #include "third_party/blink/renderer/platform/wtf/hash_set.h" #include "third_party/blink/renderer/platform/wtf/time.h" +#include "third_party/blink/renderer/platform/wtf/vector.h" namespace blink { class LayoutObject; class TracedValue; class LocalFrameView; class PropertyTreeState; +class LayoutBoxModelObject; class TextRecord : public base::SupportsWeakPtr<TextRecord> { public: @@ -37,6 +39,17 @@ DISALLOW_COPY_AND_ASSIGN(TextRecord); }; +class BlockInfo { + public: + void Aggregate(FloatRect new_text_rect) { + aggregated_text_rect_.UniteIfNonZero(new_text_rect); + } + uint64_t AggregatedTextSize() { return aggregated_text_rect_.Size().Area(); } + + private: + FloatRect aggregated_text_rect_; +}; + class TextRecordsManager { using TextRecordSetComparator = bool (*)(const base::WeakPtr<TextRecord>&, const base::WeakPtr<TextRecord>&); @@ -57,7 +70,7 @@ const uint64_t& visual_size, const LayoutObject&); bool NeedMeausuringPaintTime() const { - return !texts_queued_for_paint_time_.empty(); + return !texts_queued_for_paint_time_.IsEmpty(); } void AssignPaintTimeToQueuedNodes(const base::TimeTicks&); @@ -84,7 +97,7 @@ // the largest node efficiently. Note that the entries in |size_ordered_set_| // and |visible_node_map_| should always be added/deleted together. TextRecordSet size_ordered_set_; - std::queue<base::WeakPtr<TextRecord>> texts_queued_for_paint_time_; + Deque<base::WeakPtr<TextRecord>> texts_queued_for_paint_time_; TextRecord* cached_largest_paint_candidate_; DISALLOW_COPY_AND_ASSIGN(TextRecordsManager); @@ -114,7 +127,11 @@ public: TextPaintTimingDetector(LocalFrameView* frame_view); - void RecordText(const LayoutObject& object, const PropertyTreeState&); + // TODO(crbug.com/960946): we should document the text aggregation. + void AggregateText(const LayoutObject&, const PropertyTreeState&); + void WillWalkTextAggregatingNode(); + void DidWalkTextAggregatingNode( + const LayoutBoxModelObject& text_aggregating_block); void OnPaintFinished(); void NotifyNodeRemoved(DOMNodeId); TextRecord* FindLargestPaintCandidate(); @@ -126,11 +143,15 @@ void Trace(blink::Visitor*); private: - void PopulateTraceValue(TracedValue& value, + void AggregateTextToClosestBlock(const LayoutObject&, + const PropertyTreeState&); + void PopulateTraceValue(TracedValue&, const TextRecord& first_text_paint, unsigned candidate_index) const; void TimerFired(TimerBase*); void UpdateCandidate(); + void RecordAggregatedText(const LayoutObject& aggregating_object, + uint64_t aggregated_size); void ReportSwapTime(WebWidgetClient::SwapResult result, base::TimeTicks timestamp); @@ -147,6 +168,10 @@ bool has_records_changed_ = true; bool need_update_timing_at_frame_end_ = false; + HashSet<const LayoutObject*> visited_text_objects_; + + Vector<BlockInfo> walking_block_stack_; + base::TimeTicks largest_text_paint_; uint64_t largest_text_paint_size_ = 0; TaskRunnerTimer<TextPaintTimingDetector> timer_;
diff --git a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc index 04446ab..b5796186 100644 --- a/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc +++ b/third_party/blink/renderer/core/paint/text_paint_timing_detector_test.cc
@@ -3,11 +3,13 @@ // found in the LICENSE file. #include "third_party/blink/renderer/core/paint/text_paint_timing_detector.h" + #include "third_party/blink/renderer/core/paint/paint_timing_detector.h" #include "third_party/blink/renderer/core/svg/svg_text_content_element.h" #include "third_party/blink/renderer/core/testing/core_unit_test_helper.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" #include "third_party/blink/renderer/platform/testing/runtime_enabled_features_test_helpers.h" +#include "third_party/blink/renderer/platform/testing/wtf/scoped_mock_clock.h" namespace blink { @@ -104,13 +106,15 @@ GetPaintTimingDetector().GetTextPaintTimingDetector()->UpdateCandidate(); } - Element* AppendFontElementToBody(String content) { - Element* element = GetDocument().CreateRawElement(html_names::kFontTag); - element->setAttribute(html_names::kSizeAttr, AtomicString("5")); + Element* AppendFontBlockToBody(String content) { + Element* font = GetDocument().CreateRawElement(html_names::kFontTag); + font->setAttribute(html_names::kSizeAttr, AtomicString("5")); Text* text = GetDocument().createTextNode(content); - element->AppendChild(text); - GetDocument().body()->AppendChild(element); - return element; + font->AppendChild(text); + Element* div = GetDocument().CreateRawElement(html_names::kDivTag); + div->AppendChild(font); + GetDocument().body()->AppendChild(div); + return font; } Element* AppendDivElementToBody(String content, String style = "") { @@ -122,13 +126,6 @@ return div; } - DOMNodeId NodeIdOfText(Element* element) { - DCHECK_EQ(element->CountChildren(), 1u); - DCHECK(element->firstChild()->IsTextNode()); - DCHECK(!element->firstChild()->hasChildren()); - return DOMNodeIds::IdForNode(element->firstChild()); - } - TextRecord* TextRecordOfLargestTextPaint() { return GetFrameView() .GetPaintTimingDetector() @@ -170,7 +167,23 @@ )HTML"); Element* only_text = AppendDivElementToBody("The only text"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(only_text)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(only_text)); +} + +TEST_F(TextPaintTimingDetectorTest, AggregationBySelfPaintingInlineElement) { + SetBodyInnerHTML(R"HTML( + <div style="background: yellow"> + tiny + <span id="target" + style="position: relative; background: blue; top: 100px; left: 100px"> + this is the largest text in the world.</span> + </div> + )HTML"); + Element* span = GetDocument().getElementById("target"); + UpdateAllLifecyclePhasesAndSimulateSwapTime(); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(span)); } TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_OpacityZero) { @@ -212,7 +225,8 @@ AppendDivElementToBody("small"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(large_text)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(large_text)); } TEST_F(TextPaintTimingDetectorTest, UpdateResultWhenCandidateChanged) { @@ -227,8 +241,7 @@ EXPECT_GE(first_largest, time1); EXPECT_GE(time2, first_largest); - Text* larger_text = GetDocument().createTextNode("a long-long-long text"); - GetDocument().body()->AppendChild(larger_text); + AppendDivElementToBody("a long-long-long text"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); UpdateCandidate(); TimeTicks time3 = CurrentTimeTicks(); @@ -263,30 +276,25 @@ GetFrameView().UpdateAllLifecyclePhases( DocumentLifecycle::LifecycleUpdateReason::kTest); InvokeCallback(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(text)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(text)); } TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportFirstPaintTime) { - TimeTicks time1 = CurrentTimeTicks(); + WTF::ScopedMockClock clock; + clock.Advance(TimeDelta::FromSecondsD(1)); SetBodyInnerHTML(R"HTML( )HTML"); - Element* size_changing_text = AppendFontElementToBody("size-changing text"); - Element* long_text = - AppendFontElementToBody("a long-long-long-long moving text"); + Element* text = AppendDivElementToBody("text"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - - TimeTicks time2 = CurrentTimeTicks(); - SetFontSize(size_changing_text, 50); + clock.Advance(TimeDelta::FromSecondsD(1)); + text->setAttribute(html_names::kStyleAttr, + AtomicString("position:fixed;left:30px")); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - - SetFontSize(long_text, 100); - UpdateAllLifecyclePhasesAndSimulateSwapTime(); - + clock.Advance(TimeDelta::FromSecondsD(1)); TextRecord* record = TextRecordOfLargestTextPaint(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(long_text)); - TimeTicks paint_time = record->paint_time; - EXPECT_GE(paint_time, time1); - EXPECT_GE(time2, paint_time); + EXPECT_TRUE(record); + EXPECT_EQ(record->paint_time, base::TimeTicks() + TimeDelta::FromSecondsD(1)); } TEST_F(TextPaintTimingDetectorTest, @@ -312,11 +320,13 @@ "text)"); Element* small_text = AppendDivElementToBody("small text"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(large_text)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(large_text)); RemoveElement(large_text); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(small_text)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(small_text)); } TEST_F(TextPaintTimingDetectorTest, LargestTextPaint_ReportLastNullCandidate) { @@ -325,7 +335,8 @@ Element* text = AppendDivElementToBody("text to remove"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); UpdateCandidate(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(text)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(text)); EXPECT_NE(LargestPaintStoredResult(), base::TimeTicks()); RemoveElement(text); @@ -342,7 +353,8 @@ AppendDivElementToBody("a long text", "position:fixed;left:-10px"); Element* short_text = AppendDivElementToBody("short"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(short_text)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(short_text)); } // Depite that the l @@ -357,7 +369,7 @@ SetElementStyle(shortening_long_text, "position:fixed;left:-10px"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, - NodeIdOfText(shortening_long_text)); + DOMNodeIds::ExistingIdForNode(shortening_long_text)); } TEST_F(TextPaintTimingDetectorTest, TreatEllipsisAsText) { @@ -370,15 +382,7 @@ )HTML"); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - // The FCP++ hook in ellipsis box painter is using the line layout item as the - // tracking node while layout ng is using the layout text as the tracking - // node. - if (RuntimeEnabledFeatures::LayoutNGEnabled()) { - EXPECT_EQ(CountVisibleTexts(), 1u); - } else { - // The text and the elllipsis are recorded. - EXPECT_EQ(CountVisibleTexts(), 2u); - } + EXPECT_EQ(CountVisibleTexts(), 1u); } TEST_F(TextPaintTimingDetectorTest, CaptureFileUploadController) { @@ -388,7 +392,7 @@ EXPECT_EQ(CountVisibleTexts(), 1u); EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, - DOMNodeIds::IdForNode(element)); + DOMNodeIds::ExistingIdForNode(element)); } TEST_F(TextPaintTimingDetectorTest, NotCapturingListMarkers) { @@ -417,7 +421,8 @@ UpdateAllLifecyclePhasesAndSimulateSwapTime(); EXPECT_EQ(CountVisibleTexts(), 1u); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(elem)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(elem)); } TEST_F(TextPaintTimingDetectorTest, StopRecordingOverNodeLimit) { @@ -488,7 +493,8 @@ GetDocument().body()->getElementById("outer1")->AppendChild(div1); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(div1)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(div1)); EXPECT_EQ(TextRecordOfLargestTextPaint()->first_size, 1u); Element* div2 = GetDocument().CreateRawElement(html_names::kDivTag); @@ -500,7 +506,8 @@ GetDocument().body()->getElementById("outer2")->AppendChild(div2); UpdateAllLifecyclePhasesAndSimulateSwapTime(); - EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, NodeIdOfText(div2)); + EXPECT_EQ(TextRecordOfLargestTextPaint()->node_id, + DOMNodeIds::ExistingIdForNode(div2)); // This size is larger than the size of the first object . But the exact size // depends on different platforms. We only need to ensure this size is larger // than the first size.
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/IsolateSelector.js b/third_party/blink/renderer/devtools/front_end/profiler/IsolateSelector.js index ee2bcda8..e32dd0f8 100644 --- a/third_party/blink/renderer/devtools/front_end/profiler/IsolateSelector.js +++ b/third_party/blink/renderer/devtools/front_end/profiler/IsolateSelector.js
@@ -205,10 +205,10 @@ } /** - * @return {!SDK.RuntimeModel} + * @return {?SDK.RuntimeModel} */ model() { - return this._isolate.models().values().next().value; + return this._isolate.runtimeModel(); } updateStats() {
diff --git a/third_party/blink/renderer/devtools/front_end/profiler/LiveHeapProfileView.js b/third_party/blink/renderer/devtools/front_end/profiler/LiveHeapProfileView.js index 4aca1ce0..12ee406 100644 --- a/third_party/blink/renderer/devtools/front_end/profiler/LiveHeapProfileView.js +++ b/third_party/blink/renderer/devtools/front_end/profiler/LiveHeapProfileView.js
@@ -21,6 +21,7 @@ align: DataGrid.DataGrid.Align.Right, sort: DataGrid.DataGrid.Order.Descending }, + {id: 'isolates', title: ls`VMs`, width: '40px', fixedWidth: true, align: DataGrid.DataGrid.Align.Right}, {id: 'url', title: ls`Script URL`, fixedWidth: false, sortable: true} ]; this._dataGrid = new DataGrid.SortableDataGrid(columns); @@ -50,39 +51,43 @@ async _poll() { const pollId = this._currentPollId; do { - const models = SDK.targetManager.models(SDK.HeapProfilerModel); - const profiles = await Promise.all(models.map(model => model.getSamplingProfile())); + const isolates = Array.from(SDK.isolateManager.isolates()); + const profiles = await Promise.all( + isolates.map(isolate => isolate.heapProfilerModel() && isolate.heapProfilerModel().getSamplingProfile())); if (this._currentPollId !== pollId) return; - profiles.remove(null); - this._update(profiles); + this._update(isolates, profiles); await new Promise(r => setTimeout(r, 3000)); } while (this._currentPollId === pollId); } /** - * @param {!Array<!Protocol.HeapProfiler.SamplingHeapProfile>} profiles + * @param {!Array<!SDK.IsolateManager.Isolate>} isolates + * @param {!Array<?Protocol.HeapProfiler.SamplingHeapProfile>} profiles */ - _update(profiles) { - /** @type {!Map<string, number>} */ - const sizeByUrl = new Map(); - for (const profile of profiles) - processNode('', profile.head); + _update(isolates, profiles) { + /** @type {!Map<string, !{size: number, isolates: !Set<!SDK.IsolateManager.Isolate>}>} */ + const dataByUrl = new Map(); + profiles.forEach((profile, index) => { + if (profile) + processNodeTree(isolates[index], '', profile.head); + }); const rootNode = this._dataGrid.rootNode(); const exisitingNodes = new Set(); - for (const pair of sizeByUrl) { + for (const pair of dataByUrl) { const url = /** @type {string} */ (pair[0]); - const size = /** @type {number} */ (pair[1]); + const size = /** @type {number} */ (pair[1].size); + const isolateCount = /** @type {number} */ (pair[1].isolates.size); if (!url) { console.info(`Node with empty URL: ${size} bytes`); // eslint-disable-line no-console continue; } let node = this._gridNodeByUrl.get(url); if (node) { - node.updateSize(size); + node.updateNode(size, isolateCount); } else { - node = new Profiler.LiveHeapProfileView.GridNode(url, size); + node = new Profiler.LiveHeapProfileView.GridNode(url, size, isolateCount); this._gridNodeByUrl.set(url, node); rootNode.appendChild(node); } @@ -98,14 +103,22 @@ this._sortingChanged(); /** + * @param {!SDK.IsolateManager.Isolate} isolate * @param {string} parentUrl * @param {!Protocol.HeapProfiler.SamplingHeapProfileNode} node */ - function processNode(parentUrl, node) { + function processNodeTree(isolate, parentUrl, node) { const url = node.callFrame.url || parentUrl || systemNodeName(node) || anonymousScriptName(node); - if (node.selfSize) - sizeByUrl.set(url, (sizeByUrl.get(url) || 0) + node.selfSize); - node.children.forEach(child => processNode(url, child)); + node.children.forEach(processNodeTree.bind(null, isolate, url)); + if (!node.selfSize) + return; + let data = dataByUrl.get(url); + if (!data) { + data = {size: 0, isolates: new Set()}; + dataByUrl.set(url, data); + } + data.size += node.selfSize; + data.isolates.add(isolate); } /** @@ -160,20 +173,24 @@ /** * @param {string} url * @param {number} size + * @param {number} isolateCount */ - constructor(url, size) { + constructor(url, size, isolateCount) { super(); this._url = url; this._size = size; + this._isolateCount = isolateCount; } /** * @param {number} size + * @param {number} isolateCount */ - updateSize(size) { - if (this._size === size) + updateNode(size, isolateCount) { + if (this._size === size && this._isolateCount === isolateCount) return; this._size = size; + this._isolateCount = isolateCount; this.refresh(); } @@ -186,13 +203,15 @@ const cell = this.createTD(columnId); switch (columnId) { case 'url': - cell.title = this._url; cell.textContent = this._url; break; case 'size': cell.textContent = Number.withThousandsSeparator(Math.round(this._size / 1e3)); cell.createChild('span', 'size-units').textContent = ls`KB`; break; + case 'isolates': + cell.textContent = this._isolateCount; + break; } return cell; }
diff --git a/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js b/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js index caba26a..7237643 100644 --- a/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js +++ b/third_party/blink/renderer/devtools/front_end/resources/ServiceWorkersView.js
@@ -513,7 +513,7 @@ } if (installing) { const installingEntry = this._addVersion( - versionsStack, 'service-worker-installing-circle', Common.UIString('#%s installing', installing.id)); + versionsStack, 'service-worker-installing-circle', Common.UIString('#%s trying to install', installing.id)); installingEntry.createChild('div', 'service-worker-subtitle').textContent = Common.UIString('Received %s', new Date(installing.scriptResponseTime * 1000).toLocaleString()); if (!this._targetForVersionId(installing.id) && (installing.isRunning() || installing.isStarting())) {
diff --git a/third_party/blink/renderer/devtools/front_end/sdk/IsolateManager.js b/third_party/blink/renderer/devtools/front_end/sdk/IsolateManager.js index 7680c3e..d24d9b3 100644 --- a/third_party/blink/renderer/devtools/front_end/sdk/IsolateManager.js +++ b/third_party/blink/renderer/devtools/front_end/sdk/IsolateManager.js
@@ -176,8 +176,24 @@ return this._models; } + /** + * @return {?SDK.RuntimeModel} + */ + runtimeModel() { + return this._models.values().next().value || null; + } + + /** + * @return {?SDK.HeapProfilerModel} + */ + heapProfilerModel() { + const runtimeModel = this.runtimeModel(); + return runtimeModel && runtimeModel.heapProfilerModel(); + } + async _update() { - const usage = await this._models.values().next().value.heapUsage(); + const model = this.runtimeModel(); + const usage = model && await model.heapUsage(); if (!usage) return; this._usedHeapSize = usage.usedSize;
diff --git a/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js b/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js index 253f22f..765893a 100644 --- a/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js +++ b/third_party/blink/renderer/devtools/front_end/ui/Tooltip.js
@@ -62,11 +62,12 @@ this._hide(false); for (const element of path) { - // The offsetParent is null when the element or an ancestor has 'display: none'. - if (!(element instanceof Element) || element === this._anchorElement || - (element.nodeName !== 'SLOT' && element.offsetParent === null)) { + if (element === this._anchorElement) return; - } else if (element[UI.Tooltip._symbol]) { + // The offsetParent is null when the element or an ancestor has 'display: none'. + if (!(element instanceof Element) || element.offsetParent === null) + continue; + if (element[UI.Tooltip._symbol]) { this._show(element, mouseEvent); return; }
diff --git a/third_party/blink/renderer/modules/permissions/permissions.cc b/third_party/blink/renderer/modules/permissions/permissions.cc index c8201dc..443a59a 100644 --- a/third_party/blink/renderer/modules/permissions/permissions.cc +++ b/third_party/blink/renderer/modules/permissions/permissions.cc
@@ -25,6 +25,7 @@ #include "third_party/blink/renderer/modules/permissions/permission_status.h" #include "third_party/blink/renderer/modules/permissions/permission_utils.h" #include "third_party/blink/renderer/platform/runtime_enabled_features.h" +#include "third_party/blink/renderer/platform/scheduler/public/frame_scheduler.h" #include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/vector.h" #include "third_party/blink/renderer/platform/wtf/wtf_size_t.h" @@ -155,6 +156,45 @@ return nullptr; } +base::Optional<SchedulingPolicy::Feature> PermissionToSchedulingFeature( + PermissionName permission) { + switch (permission) { + case PermissionName::GEOLOCATION: + return SchedulingPolicy::Feature::kRequestedGeolocationPermission; + case PermissionName::NOTIFICATIONS: + return SchedulingPolicy::Feature::kRequestedNotificationsPermission; + case PermissionName::MIDI: + return SchedulingPolicy::Feature::kRequestedMIDIPermission; + case PermissionName::AUDIO_CAPTURE: + return SchedulingPolicy::Feature::kRequestedAudioCapturePermission; + case PermissionName::VIDEO_CAPTURE: + return SchedulingPolicy::Feature::kRequestedVideoCapturePermission; + case PermissionName::SENSORS: + return SchedulingPolicy::Feature::kRequestedSensorsPermission; + case PermissionName::BACKGROUND_SYNC: + case PermissionName::BACKGROUND_FETCH: + case PermissionName::PERIODIC_BACKGROUND_SYNC: + return SchedulingPolicy::Feature::kRequestedBackgroundWorkPermission; + default: + return base::nullopt; + } +} + +void NotifySchedulerAboutPermissionRequest(ExecutionContext* context, + PermissionName permission) { + if (!context) + return; + + base::Optional<SchedulingPolicy::Feature> feature = + PermissionToSchedulingFeature(permission); + + if (!feature) + return; + + context->GetScheduler()->RegisterStickyFeature( + feature.value(), {SchedulingPolicy::RecordMetricsForBackForwardCache()}); +} + } // anonymous namespace ScriptPromise Permissions::query(ScriptState* script_state, @@ -191,6 +231,8 @@ ExecutionContext* context = ExecutionContext::From(script_state); + NotifySchedulerAboutPermissionRequest(context, descriptor->name); + auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise(); @@ -236,6 +278,9 @@ Vector<PermissionDescriptorPtr> internal_permissions; Vector<int> caller_index_to_internal_index; caller_index_to_internal_index.resize(raw_permissions.size()); + + ExecutionContext* context = ExecutionContext::From(script_state); + for (wtf_size_t i = 0; i < raw_permissions.size(); ++i) { const ScriptValue& raw_permission = raw_permissions[i]; @@ -244,6 +289,8 @@ if (exception_state.HadException()) return ScriptPromise(); + NotifySchedulerAboutPermissionRequest(context, descriptor->name); + // Only append permissions types that are not already present in the vector. wtf_size_t internal_index = kNotFound; for (wtf_size_t j = 0; j < internal_permissions.size(); ++j) { @@ -259,8 +306,6 @@ caller_index_to_internal_index[i] = internal_index; } - ExecutionContext* context = ExecutionContext::From(script_state); - auto* resolver = MakeGarbageCollected<ScriptPromiseResolver>(script_state); ScriptPromise promise = resolver->Promise();
diff --git a/third_party/blink/renderer/platform/blob/blob_bytes_provider.h b/third_party/blink/renderer/platform/blob/blob_bytes_provider.h index a66f1f17..faafa10 100644 --- a/third_party/blink/renderer/platform/blob/blob_bytes_provider.h +++ b/third_party/blink/renderer/platform/blob/blob_bytes_provider.h
@@ -7,6 +7,7 @@ #include "base/sequenced_task_runner.h" #include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h" +#include "third_party/blink/public/mojom/blob/data_element.mojom-blink.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/blob/blob_data.cc b/third_party/blink/renderer/platform/blob/blob_data.cc index 8a1c9ffa2..2462b79 100644 --- a/third_party/blink/renderer/platform/blob/blob_data.cc +++ b/third_party/blink/renderer/platform/blob/blob_data.cc
@@ -38,7 +38,9 @@ #include "base/single_thread_task_runner.h" #include "mojo/public/cpp/bindings/strong_binding.h" #include "services/network/public/mojom/data_pipe_getter.mojom-blink.h" +#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" #include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h" +#include "third_party/blink/public/mojom/blob/data_element.mojom-blink.h" #include "third_party/blink/public/platform/file_path_conversion.h" #include "third_party/blink/public/platform/interface_provider.h" #include "third_party/blink/public/platform/platform.h" @@ -105,6 +107,15 @@ RawData::RawData() = default; +BlobData::BlobData(FileCompositionStatus composition) + : file_composition_(composition) {} + +BlobData::~BlobData() {} + +Vector<mojom::blink::DataElementPtr> BlobData::ReleaseElements() { + return std::move(elements_); +} + std::unique_ptr<BlobData> BlobData::CreateForFileWithUnknownSize( const String& path) { std::unique_ptr<BlobData> data = base::WrapUnique( @@ -297,6 +308,19 @@ last_bytes_provider_->AppendData(std::move(data)); } +// static +scoped_refptr<BlobDataHandle> BlobDataHandle::Create( + const String& uuid, + const String& type, + uint64_t size, + mojom::blink::BlobPtrInfo blob_info) { + if (blob_info.is_valid()) { + return base::AdoptRef( + new BlobDataHandle(uuid, type, size, std::move(blob_info))); + } + return base::AdoptRef(new BlobDataHandle(uuid, type, size)); +} + BlobDataHandle::BlobDataHandle() : uuid_(CreateCanonicalUUIDString()), size_(0),
diff --git a/third_party/blink/renderer/platform/blob/blob_data.h b/third_party/blink/renderer/platform/blob/blob_data.h index c5829fe3..82135c9 100644 --- a/third_party/blink/renderer/platform/blob/blob_data.h +++ b/third_party/blink/renderer/platform/blob/blob_data.h
@@ -31,11 +31,18 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_BLOB_BLOB_DATA_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_BLOB_BLOB_DATA_H_ +// This file is required via serialized_blob.typemap and, transitively, +// encoded_form_data.typemap. To avoid build circularity issues, it should not +// transitively include anything that is generated from a mojom_blink target. +// +// This requires some gymnastics below, to explicitly forward-declare the +// required types without reference to the generator output headers. + #include <memory> #include "base/gtest_prod_util.h" #include "base/thread_annotations.h" -#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" -#include "third_party/blink/public/mojom/blob/data_element.mojom-blink.h" +#include "mojo/public/cpp/bindings/interface_ptr.h" +#include "mojo/public/cpp/bindings/struct_ptr.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" #include "third_party/blink/renderer/platform/wtf/forward.h" @@ -43,10 +50,29 @@ #include "third_party/blink/renderer/platform/wtf/thread_safe_ref_counted.h" #include "third_party/blink/renderer/platform/wtf/threading_primitives.h" +namespace network { +namespace mojom { +namespace blink { +class DataPipeGetter; +using DataPipeGetterPtr = mojo::InterfacePtr<DataPipeGetter>; +} // namespace blink +} // namespace mojom +} // namespace network + namespace blink { namespace mojom { namespace blink { +class Blob; +using BlobPtr = mojo::InterfacePtr<Blob>; +using BlobPtrInfo = mojo::InterfacePtrInfo<Blob>; + +class BlobReaderClient; +using BlobReaderClientPtr = mojo::InterfacePtr<BlobReaderClient>; + class BlobRegistry; + +class DataElement; +using DataElementPtr = mojo::StructPtr<DataElement>; } } // namespace mojom @@ -79,9 +105,9 @@ NO_UNKNOWN_SIZE_FILES }; - explicit BlobData(FileCompositionStatus composition = - FileCompositionStatus::NO_UNKNOWN_SIZE_FILES) - : file_composition_(composition) {} + explicit BlobData( + FileCompositionStatus = FileCompositionStatus::NO_UNKNOWN_SIZE_FILES); + ~BlobData(); // Calling append* on objects returned by createFor___WithUnknownSize will // check-fail. The caller can only have an unknown-length file if it is the @@ -104,9 +130,7 @@ const Vector<mojom::blink::DataElementPtr>& Elements() const { return elements_; } - Vector<mojom::blink::DataElementPtr> ReleaseElements() { - return std::move(elements_); - } + Vector<mojom::blink::DataElementPtr> ReleaseElements(); void AppendBytes(const void*, size_t length); void AppendData(scoped_refptr<RawData>); @@ -172,17 +196,10 @@ return base::AdoptRef(new BlobDataHandle(uuid, type, size)); } - static scoped_refptr<BlobDataHandle> Create( - const String& uuid, - const String& type, - uint64_t size, - mojom::blink::BlobPtrInfo blob_info) { - if (blob_info.is_valid()) { - return base::AdoptRef( - new BlobDataHandle(uuid, type, size, std::move(blob_info))); - } - return base::AdoptRef(new BlobDataHandle(uuid, type, size)); - } + static scoped_refptr<BlobDataHandle> Create(const String& uuid, + const String& type, + uint64_t size, + mojom::blink::BlobPtrInfo); String Uuid() const { return uuid_.IsolatedCopy(); } String GetType() const { return type_.IsolatedCopy(); }
diff --git a/third_party/blink/renderer/platform/blob/testing/fake_blob_registry.cc b/third_party/blink/renderer/platform/blob/testing/fake_blob_registry.cc index d85a2d6..b700087b 100644 --- a/third_party/blink/renderer/platform/blob/testing/fake_blob_registry.cc +++ b/third_party/blink/renderer/platform/blob/testing/fake_blob_registry.cc
@@ -5,6 +5,7 @@ #include "third_party/blink/renderer/platform/blob/testing/fake_blob_registry.h" #include "mojo/public/cpp/bindings/strong_binding.h" +#include "third_party/blink/public/mojom/blob/data_element.mojom-blink.h" #include "third_party/blink/renderer/platform/blob/testing/fake_blob.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/exported/web_blob_info.cc b/third_party/blink/renderer/platform/exported/web_blob_info.cc index b4808d0..7c4a712 100644 --- a/third_party/blink/renderer/platform/exported/web_blob_info.cc +++ b/third_party/blink/renderer/platform/exported/web_blob_info.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/public/platform/web_blob_info.h" +#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/exported/web_http_body.cc b/third_party/blink/renderer/platform/exported/web_http_body.cc index 8f5324c..9888991 100644 --- a/third_party/blink/renderer/platform/exported/web_http_body.cc +++ b/third_party/blink/renderer/platform/exported/web_http_body.cc
@@ -32,9 +32,11 @@ #include "mojo/public/cpp/system/data_pipe.h" #include "services/network/public/mojom/data_pipe_getter.mojom-blink.h" +#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" #include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/network/encoded_form_data.h" #include "third_party/blink/renderer/platform/network/form_data_encoder.h" +#include "third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h" #include "third_party/blink/renderer/platform/shared_buffer.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/exported/web_service_worker_response.cc b/third_party/blink/renderer/platform/exported/web_service_worker_response.cc index e3cde41..317e4d1 100644 --- a/third_party/blink/renderer/platform/exported/web_service_worker_response.cc +++ b/third_party/blink/renderer/platform/exported/web_service_worker_response.cc
@@ -4,6 +4,7 @@ #include "third_party/blink/public/platform/modules/service_worker/web_service_worker_response.h" +#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" #include "third_party/blink/public/platform/web_http_header_visitor.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" #include "third_party/blink/renderer/platform/network/http_header_map.h"
diff --git a/third_party/blink/renderer/platform/heap/thread_state.cc b/third_party/blink/renderer/platform/heap/thread_state.cc index c8fda1aa..75f5107e 100644 --- a/third_party/blink/renderer/platform/heap/thread_state.cc +++ b/third_party/blink/renderer/platform/heap/thread_state.cc
@@ -830,6 +830,8 @@ if (IsGCForbidden()) return; + base::AutoReset<bool> precise_gc_allowed_scope(&precise_gc_allowed_, true); + switch (GetGCState()) { case kForcedGCForTestingScheduled: CollectAllGarbageForTesting(); @@ -1459,6 +1461,13 @@ BlinkGC::MarkingType marking_type, BlinkGC::SweepingType sweeping_type, BlinkGC::GCReason reason) { + // // Precise GC must only be executed when we don't need to scan the stack. + // crbug.com/937117 crbug.com/937117 + if (stack_state == BlinkGC::kNoHeapPointersOnStack && + reason != BlinkGC::GCReason::kForcedGCForTesting && + reason != BlinkGC::GCReason::kThreadTerminationGC) + CHECK(precise_gc_allowed_); + // Nested garbage collection invocations are not supported. CHECK(!IsGCForbidden()); // Garbage collection during sweeping is not supported. This can happen when
diff --git a/third_party/blink/renderer/platform/heap/thread_state.h b/third_party/blink/renderer/platform/heap/thread_state.h index 4c91b5d..3bb7d431 100644 --- a/third_party/blink/renderer/platform/heap/thread_state.h +++ b/third_party/blink/renderer/platform/heap/thread_state.h
@@ -595,6 +595,10 @@ }; GCData current_gc_data_; + // Used to ensure precise GC is only run when we don't need to scan the stack. + // crbug.com/937117 + bool precise_gc_allowed_ = false; + friend class BlinkGCObserver; friend class incremental_marking_test::IncrementalMarkingScope; friend class incremental_marking_test::IncrementalMarkingTestDriver;
diff --git a/third_party/blink/renderer/platform/loader/cors/cors_test.cc b/third_party/blink/renderer/platform/loader/cors/cors_test.cc index c595094..5365a937 100644 --- a/third_party/blink/renderer/platform/loader/cors/cors_test.cc +++ b/third_party/blink/renderer/platform/loader/cors/cors_test.cc
@@ -6,6 +6,7 @@ #include "testing/gtest/include/gtest/gtest.h" #include "third_party/blink/renderer/platform/loader/fetch/resource_response.h" +#include "third_party/blink/renderer/platform/weborigin/security_origin.h" namespace blink {
diff --git a/third_party/blink/renderer/platform/network/BUILD.gn b/third_party/blink/renderer/platform/network/BUILD.gn index d895fca..2ef1999 100644 --- a/third_party/blink/renderer/platform/network/BUILD.gn +++ b/third_party/blink/renderer/platform/network/BUILD.gn
@@ -62,6 +62,7 @@ "parsed_content_type.h", "server_timing_header.cc", "server_timing_header.h", + "wrapped_data_pipe_getter.h", ] sources += get_target_outputs(":http_names")
diff --git a/third_party/blink/renderer/platform/network/encoded_form_data.cc b/third_party/blink/renderer/platform/network/encoded_form_data.cc index bdd6f26..f4315e851 100644 --- a/third_party/blink/renderer/platform/network/encoded_form_data.cc +++ b/third_party/blink/renderer/platform/network/encoded_form_data.cc
@@ -23,16 +23,70 @@ #include "third_party/blink/renderer/platform/file_metadata.h" #include "third_party/blink/renderer/platform/network/form_data_encoder.h" +#include "third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h" #include "third_party/blink/renderer/platform/wtf/text/cstring.h" #include "third_party/blink/renderer/platform/wtf/text/text_encoding.h" namespace blink { +FormDataElement::FormDataElement() : type_(kData) {} + +FormDataElement::FormDataElement(const Vector<char>& array) + : type_(kData), data_(array) {} + bool FormDataElement::IsSafeToSendToAnotherThread() const { return filename_.IsSafeToSendToAnotherThread() && blob_uuid_.IsSafeToSendToAnotherThread(); } +FormDataElement::FormDataElement(const String& filename, + int64_t file_start, + int64_t file_length, + double expected_file_modification_time) + : type_(kEncodedFile), + filename_(filename), + file_start_(file_start), + file_length_(file_length), + expected_file_modification_time_(expected_file_modification_time) {} + +FormDataElement::FormDataElement(const String& blob_uuid, + scoped_refptr<BlobDataHandle> optional_handle) + : type_(kEncodedBlob), + blob_uuid_(blob_uuid), + optional_blob_data_handle_(std::move(optional_handle)) {} + +FormDataElement::FormDataElement( + scoped_refptr<WrappedDataPipeGetter> data_pipe_getter) + : type_(kDataPipe), data_pipe_getter_(std::move(data_pipe_getter)) {} + +FormDataElement::FormDataElement(const FormDataElement&) = default; +FormDataElement::FormDataElement(FormDataElement&&) = default; +FormDataElement::~FormDataElement() = default; +FormDataElement& FormDataElement::operator=(const FormDataElement&) = default; +FormDataElement& FormDataElement::operator=(FormDataElement&&) = default; + +bool operator==(const FormDataElement& a, const FormDataElement& b) { + if (&a == &b) + return true; + + if (a.type_ != b.type_) + return false; + if (a.type_ == FormDataElement::kData) + return a.data_ == b.data_; + if (a.type_ == FormDataElement::kEncodedFile) { + return a.filename_ == b.filename_ && a.file_start_ == b.file_start_ && + a.file_length_ == b.file_length_ && + a.expected_file_modification_time_ == + b.expected_file_modification_time_; + } + if (a.type_ == FormDataElement::kEncodedBlob) + return a.blob_uuid_ == b.blob_uuid_; + if (a.type_ == FormDataElement::kDataPipe) + return a.data_pipe_getter_ == b.data_pipe_getter_; + + return true; +} + inline EncodedFormData::EncodedFormData() : identifier_(0), contains_password_data_(false) {}
diff --git a/third_party/blink/renderer/platform/network/encoded_form_data.h b/third_party/blink/renderer/platform/network/encoded_form_data.h index 6a3075b..e51137d 100644 --- a/third_party/blink/renderer/platform/network/encoded_form_data.h +++ b/third_party/blink/renderer/platform/network/encoded_form_data.h
@@ -20,8 +20,16 @@ #ifndef THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_ENCODED_FORM_DATA_H_ #define THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_ENCODED_FORM_DATA_H_ +// This file is required via encoded_form_data.typemap. To avoid build +// circularity issues, it should not transitively include anything that is +// generated from a mojom_blink target. +// +// This requires some gymnastics below, to explicitly forward-declare the +// required types without reference to the generator output headers. + #include <utility> +#include "mojo/public/cpp/bindings/struct_traits.h" #include "third_party/blink/renderer/platform/blob/blob_data.h" #include "third_party/blink/renderer/platform/weborigin/kurl.h" #include "third_party/blink/renderer/platform/wtf/allocator.h" @@ -30,61 +38,38 @@ #include "third_party/blink/renderer/platform/wtf/text/wtf_string.h" #include "third_party/blink/renderer/platform/wtf/vector.h" -#include "services/network/public/mojom/data_pipe_getter.mojom-blink.h" - namespace network { namespace mojom { class URLRequestBodyDataView; -} +} // namespace mojom } // namespace network namespace blink { class BlobDataHandle; - -// Refcounted wrapper around a DataPipeGetter to allow sharing the move-only -// type. This is only needed so EncodedFormData/FormDataElement have a copy -// constructor. -class PLATFORM_EXPORT WrappedDataPipeGetter final - : public RefCounted<WrappedDataPipeGetter> { - public: - explicit WrappedDataPipeGetter( - network::mojom::blink::DataPipeGetterPtr data_pipe_getter) - : data_pipe_getter_(std::move(data_pipe_getter)) {} - ~WrappedDataPipeGetter() = default; - - network::mojom::blink::DataPipeGetterPtr* GetPtr() { - return &data_pipe_getter_; - } - - private: - network::mojom::blink::DataPipeGetterPtr data_pipe_getter_; -}; +class WrappedDataPipeGetter; class PLATFORM_EXPORT FormDataElement final { DISALLOW_NEW(); public: - FormDataElement() : type_(kData) {} - explicit FormDataElement(const Vector<char>& array) - : type_(kData), data_(array) {} + FormDataElement(); + explicit FormDataElement(const Vector<char>&); FormDataElement(const String& filename, int64_t file_start, int64_t file_length, - double expected_file_modification_time) - : type_(kEncodedFile), - filename_(filename), - file_start_(file_start), - file_length_(file_length), - expected_file_modification_time_(expected_file_modification_time) {} + double expected_file_modification_time); FormDataElement(const String& blob_uuid, - scoped_refptr<BlobDataHandle> optional_handle) - : type_(kEncodedBlob), - blob_uuid_(blob_uuid), - optional_blob_data_handle_(std::move(optional_handle)) {} - explicit FormDataElement( - scoped_refptr<WrappedDataPipeGetter> data_pipe_getter) - : type_(kDataPipe), data_pipe_getter_(std::move(data_pipe_getter)) {} + scoped_refptr<BlobDataHandle> optional_handle); + explicit FormDataElement(scoped_refptr<WrappedDataPipeGetter>); + + FormDataElement(const FormDataElement&); + FormDataElement(FormDataElement&&); + + ~FormDataElement(); + + FormDataElement& operator=(const FormDataElement&); + FormDataElement& operator=(FormDataElement&&); bool IsSafeToSendToAnotherThread() const; @@ -99,26 +84,8 @@ scoped_refptr<WrappedDataPipeGetter> data_pipe_getter_; }; -inline bool operator==(const FormDataElement& a, const FormDataElement& b) { - if (&a == &b) - return true; - - if (a.type_ != b.type_) - return false; - if (a.type_ == FormDataElement::kData) - return a.data_ == b.data_; - if (a.type_ == FormDataElement::kEncodedFile) - return a.filename_ == b.filename_ && a.file_start_ == b.file_start_ && - a.file_length_ == b.file_length_ && - a.expected_file_modification_time_ == - b.expected_file_modification_time_; - if (a.type_ == FormDataElement::kEncodedBlob) - return a.blob_uuid_ == b.blob_uuid_; - if (a.type_ == FormDataElement::kDataPipe) - return a.data_pipe_getter_ == b.data_pipe_getter_; - - return true; -} +PLATFORM_EXPORT bool operator==(const FormDataElement& a, + const FormDataElement& b); inline bool operator!=(const FormDataElement& a, const FormDataElement& b) { return !(a == b);
diff --git a/third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.cc b/third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.cc index d449da74..02c7cbc5 100644 --- a/third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.cc +++ b/third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.cc
@@ -12,9 +12,11 @@ #include "mojo/public/cpp/bindings/array_traits_wtf_vector.h" #include "mojo/public/cpp/bindings/string_traits_wtf.h" #include "services/network/public/mojom/data_pipe_getter.mojom-blink.h" +#include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" #include "third_party/blink/public/mojom/blob/blob_registry.mojom-blink.h" #include "third_party/blink/public/platform/interface_provider.h" #include "third_party/blink/public/platform/platform.h" +#include "third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h" namespace mojo {
diff --git a/third_party/blink/renderer/platform/network/encoded_form_data_test.cc b/third_party/blink/renderer/platform/network/encoded_form_data_test.cc index ba3e7e1..c71f053 100644 --- a/third_party/blink/renderer/platform/network/encoded_form_data_test.cc +++ b/third_party/blink/renderer/platform/network/encoded_form_data_test.cc
@@ -16,6 +16,7 @@ #include "third_party/blink/public/mojom/blob/blob.mojom-blink.h" #include "third_party/blink/renderer/platform/network/encoded_form_data.h" #include "third_party/blink/renderer/platform/network/encoded_form_data_mojom_traits.h" +#include "third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h" #include "testing/gtest/include/gtest/gtest.h"
diff --git a/third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h b/third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h new file mode 100644 index 0000000..f50bf14 --- /dev/null +++ b/third_party/blink/renderer/platform/network/wrapped_data_pipe_getter.h
@@ -0,0 +1,35 @@ +// Copyright 2019 The Chromium 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 THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_WRAPPED_DATA_PIPE_GETTER_H_ +#define THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_WRAPPED_DATA_PIPE_GETTER_H_ + +#include "third_party/blink/renderer/platform/platform_export.h" + +#include "services/network/public/mojom/data_pipe_getter.mojom-blink.h" + +namespace blink { + +// Refcounted wrapper around a DataPipeGetter to allow sharing the move-only +// type. This is only needed so EncodedFormData/FormDataElement have a copy +// constructor. +class PLATFORM_EXPORT WrappedDataPipeGetter final + : public RefCounted<WrappedDataPipeGetter> { + public: + explicit WrappedDataPipeGetter( + network::mojom::blink::DataPipeGetterPtr data_pipe_getter) + : data_pipe_getter_(std::move(data_pipe_getter)) {} + ~WrappedDataPipeGetter() = default; + + network::mojom::blink::DataPipeGetterPtr* GetPtr() { + return &data_pipe_getter_; + } + + private: + network::mojom::blink::DataPipeGetterPtr data_pipe_getter_; +}; + +} // namespace blink + +#endif // THIRD_PARTY_BLINK_RENDERER_PLATFORM_NETWORK_WRAPPED_DATA_PIPE_GETTER_H_
diff --git a/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc b/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc index 17c24ba6..4f3c875 100644 --- a/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc +++ b/third_party/blink/renderer/platform/scheduler/common/scheduling_policy.cc
@@ -30,6 +30,13 @@ case Feature::kContainsPlugins: case Feature::kDocumentLoaded: case Feature::kServiceWorkerControlledPage: + case Feature::kRequestedGeolocationPermission: + case Feature::kRequestedNotificationsPermission: + case Feature::kRequestedMIDIPermission: + case Feature::kRequestedAudioCapturePermission: + case Feature::kRequestedVideoCapturePermission: + case Feature::kRequestedSensorsPermission: + case Feature::kRequestedBackgroundWorkPermission: return true; } }
diff --git a/third_party/blink/web_tests/TestExpectations b/third_party/blink/web_tests/TestExpectations index 4d545e3..1f6aef4 100644 --- a/third_party/blink/web_tests/TestExpectations +++ b/third_party/blink/web_tests/TestExpectations
@@ -3463,7 +3463,6 @@ crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-containing-block.html [ Failure ] crbug.com/626703 external/wpt/quirks/text-decoration-doesnt-propagate-into-tables/quirks.html [ Failure ] crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-overflow-hidden.html [ Failure ] -crbug.com/626703 [ Mac10.12 ] external/wpt/webxr/xrSession_requestAnimationFrame_getViewerPose.https.html [ Failure Timeout ] crbug.com/626703 external/wpt/html/rendering/non-replaced-elements/the-fieldset-and-legend-elements/fieldset-painting-order.html [ Failure ] crbug.com/626703 external/wpt/html/webappapis/dynamic-markup-insertion/opening-the-input-stream/tasks.window.html [ Timeout ] crbug.com/875411 external/wpt/svg/text/reftests/text-complex-002.svg [ Failure ] @@ -5668,6 +5667,9 @@ # WebXR feature policy feature name in Chrome doesn't match spec. crbug.com/924670 external/wpt/webvr/webvr-supported-by-feature-policy.html [ Failure ] +crbug.com/961015 [ Mac ] external/wpt/webxr/xrSession_requestAnimationFrame_callback_calls.https.html [ Timeout ] +crbug.com/961015 [ Mac ] external/wpt/webxr/xrSession_requestAnimationFrame_getViewerPose.https.html [ Timeout ] + # Sheriff 2019-01-25 crbug.com/925325 [ Mac ] storage/indexeddb/index-population.html [ Pass Failure ] @@ -5959,3 +5961,14 @@ # Sheriff 2019-05-07 crbug.com/960443 [ Mac10.10 Mac10.11 ] external/wpt/animation-worklet/worklet-animation-with-scroll-timeline.https.html [ Failure Pass ] + +# Sheriff 2019-05-08 +crbug.com/961009 [ Linux ] http/tests/devtools/console-xhr-logging.js [ Failure Timeout ] +crbug.com/961009 [ Linux ] http/tests/eventsource/eventsource-cors-non-http.html [ Failure ] +crbug.com/961009 [ Linux ] http/tests/eventsource/workers/eventsource-cors-non-http.html [ Failure ] +crbug.com/961009 [ Linux ] http/tests/inspector-protocol/network-fetch-content-with-error-status-code.js [ Failure ] +crbug.com/961009 [ Linux ] http/tests/security/script-crossorigin-redirect-credentials.html [ Failure ] +crbug.com/961009 [ Linux ] http/tests/xmlhttprequest/cross-origin-unsupported-url.html [ Failure ] +crbug.com/961009 [ Linux ] http/tests/xmlhttprequest/workers/cross-origin-unsupported-url.html [ Failure ] +crbug.com/961009 [ Linux ] mhtml/cid_in_html_resource.html [ Failure ] +crbug.com/961009 [ Linux ] http/tests/security/img-redirect-to-crossorigin-credentials.html [ Failure ]
diff --git a/third_party/blink/web_tests/css-parser/snap-points-parsing.html b/third_party/blink/web_tests/css-parser/snap-points-parsing.html index bb97f2b..14994506e 100644 --- a/third_party/blink/web_tests/css-parser/snap-points-parsing.html +++ b/third_party/blink/web_tests/css-parser/snap-points-parsing.html
@@ -3,15 +3,6 @@ <script src="../resources/testharnessreport.js"></script> <script src="resources/property-parsing-test.js"></script> <script> -assert_valid_value("scroll-snap-type", "none"); -assert_valid_value("scroll-snap-type", "x"); -assert_valid_value("scroll-snap-type", "y mandatory"); -assert_valid_value("scroll-snap-type", "block proximity"); -assert_valid_value("scroll-snap-type", "inline proximity"); -assert_valid_value("scroll-snap-type", "both mandatory"); -assert_invalid_value("scroll-snap-type", "both none"); -assert_invalid_value("scroll-snap-type", "mandatory"); - assert_valid_value("scroll-padding", "3px"); assert_valid_value("scroll-padding", "3%"); assert_invalid_value("scroll-padding", "-3px");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-invalid.html index 72306dc0..6177ff3 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-invalid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-invalid.html
@@ -16,6 +16,7 @@ test_invalid_value("scroll-snap-type", "x y"); test_invalid_value("scroll-snap-type", "block mandatory inline"); +test_invalid_value("scroll-snap-type", "both none"); test_invalid_value("scroll-snap-type", "mandatory"); test_invalid_value("scroll-snap-type", "proximity"); test_invalid_value("scroll-snap-type", "mandatory inline");
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid-expected.txt deleted file mode 100644 index 3c91974..0000000 --- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid-expected.txt +++ /dev/null
@@ -1,11 +0,0 @@ -This is a testharness.js-based test. -PASS e.style['scroll-snap-type'] = "none" should set the property value -PASS e.style['scroll-snap-type'] = "x" should set the property value -PASS e.style['scroll-snap-type'] = "y" should set the property value -PASS e.style['scroll-snap-type'] = "block" should set the property value -PASS e.style['scroll-snap-type'] = "inline" should set the property value -PASS e.style['scroll-snap-type'] = "both" should set the property value -PASS e.style['scroll-snap-type'] = "y mandatory" should set the property value -FAIL e.style['scroll-snap-type'] = "inline proximity" should set the property value assert_equals: serialization should be canonical expected "inline" but got "inline proximity" -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid.html b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid.html index 59a0cb9..ca995770 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid.html +++ b/third_party/blink/web_tests/external/wpt/css/css-scroll-snap/parsing/scroll-snap-type-valid.html
@@ -20,7 +20,10 @@ test_valid_value("scroll-snap-type", "both"); test_valid_value("scroll-snap-type", "y mandatory"); +test_valid_value("scroll-snap-type", "block mandatory"); +test_valid_value("scroll-snap-type", "both mandatory"); test_valid_value("scroll-snap-type", "inline proximity", "inline"); // The shortest serialization is preferable +test_valid_value("scroll-snap-type", "x proximity", "x"); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/inheritance.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/inheritance.html index 17486f1..b1063437 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-text-decor/inheritance.html +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/inheritance.html
@@ -4,6 +4,7 @@ <meta charset="utf-8"> <title>Inheritance of CSS Text Decoration properties</title> <link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#property-index"> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#property-index"> <meta name="assert" content="Properties inherit or not according to the spec."> <meta name="assert" content="Properties have initial values according to the spec."> <script src="/resources/testharness.js"></script> @@ -28,6 +29,8 @@ assert_inherited('text-emphasis-style', 'none', 'filled triangle'); assert_inherited('text-shadow', 'none', 'rgba(42, 53, 64, 0.75) 10px 20px 0px'); assert_inherited('text-underline-position', 'auto', 'under'); + +assert_inherited('text-decoration-skip-ink', 'auto', 'none'); </script> </body> </html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-computed.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-computed.html new file mode 100644 index 0000000..3d6435ee --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-computed.html
@@ -0,0 +1,19 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: getComputedValue().textDecorationSkipInk</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-skip-ink-property"> +<meta name="assert" content="text-decoration-skip-ink computed value is as specified."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +</head> +<body> +<div id="target"></div> +<script> +test_computed_value("text-decoration-skip-ink", "auto"); +test_computed_value("text-decoration-skip-ink", "none"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-invalid.html new file mode 100644 index 0000000..4c983182 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-invalid.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: Parsing text-decoration-skip-ink with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-skip-ink-property"> +<meta name="assert" content="text-decoration-skip-ink supports only the grammar 'auto | none'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> +test_invalid_value("text-decoration-skip-ink", "edges"); +test_invalid_value("text-decoration-skip-ink", "auto none"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-valid.html new file mode 100644 index 0000000..bc694490 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-skip-ink-valid.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: Parsing text-decoration-skip-ink with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-4/#text-decoration-skip-ink-property"> +<meta name="assert" content="text-decoration-skip-ink supports the full grammar 'auto | none'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> +test_valid_value("text-decoration-skip-ink", "auto"); +test_valid_value("text-decoration-skip-ink", "none"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-computed.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-computed.html new file mode 100644 index 0000000..da4977ad --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-computed.html
@@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: getComputedValue().textDecorationStyle</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-decoration-style-property"> +<meta name="assert" content="text-decoration-style computed value is as specified."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +</head> +<body> +<div id="target"></div> +<script> +test_computed_value("text-decoration-style", "solid"); +test_computed_value("text-decoration-style", "double"); +test_computed_value("text-decoration-style", "dotted"); +test_computed_value("text-decoration-style", "dashed"); +test_computed_value("text-decoration-style", "wavy"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-invalid.html new file mode 100644 index 0000000..ad92c71f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-invalid.html
@@ -0,0 +1,12 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: Parsing text-decoration-style with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-decoration-style-property"> +<meta name="assert" content="text-decoration-style supports only the grammar 'solid | double | dotted | dashed | wavy'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> +test_invalid_value("text-decoration-style", "groove"); +test_invalid_value("text-decoration-style", "solid wavy"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-valid.html new file mode 100644 index 0000000..d47303f --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-decoration-style-valid.html
@@ -0,0 +1,15 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: Parsing text-decoration-style with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-decoration-style-property"> +<meta name="assert" content="text-decoration-style supports the full grammar 'solid | double | dotted | dashed | wavy'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> +test_valid_value("text-decoration-style", "solid"); +test_valid_value("text-decoration-style", "double"); +test_valid_value("text-decoration-style", "dotted"); +test_valid_value("text-decoration-style", "dashed"); +test_valid_value("text-decoration-style", "wavy"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-computed.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-computed.html new file mode 100644 index 0000000..eadbe04 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-computed.html
@@ -0,0 +1,23 @@ +<!DOCTYPE html> +<html> +<head> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: getComputedValue().textUnderlinePosition</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-decoration-style-property"> +<meta name="assert" content="text-underline-position computed value is as specified."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/computed-testcommon.js"></script> +</head> +<body> +<div id="target"></div> +<script> +test_computed_value("text-underline-position", "auto"); + +test_computed_value("text-underline-position", "under"); +test_computed_value("text-underline-position", "left"); +test_computed_value("text-underline-position", "right"); +test_computed_value("text-underline-position", "under left"); +</script> +</body> +</html>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-invalid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-invalid.html new file mode 100644 index 0000000..5feea8e --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-invalid.html
@@ -0,0 +1,14 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: Parsing text-underline-position with invalid values</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-decoration-style-property"> +<meta name="assert" content="text-underline-position supports only the grammar 'auto | [ under || [ left | right ] ]'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> +test_invalid_value("text-underline-position", "auto under"); +test_invalid_value("text-underline-position", "left auto"); +test_invalid_value("text-underline-position", "left right"); +test_invalid_value("text-underline-position", "right under left"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-valid.html b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-valid.html new file mode 100644 index 0000000..fa05448 --- /dev/null +++ b/third_party/blink/web_tests/external/wpt/css/css-text-decor/parsing/text-underline-position-valid.html
@@ -0,0 +1,17 @@ +<!DOCTYPE html> +<meta charset="utf-8"> +<title>CSS Text Decoration Test: Parsing text-underline-position with valid values</title> +<link rel="help" href="https://drafts.csswg.org/css-text-decor-3/#text-decoration-style-property"> +<meta name="assert" content="text-underline-position supports the full grammar 'auto | [ under || [ left | right ] ]'."> +<script src="/resources/testharness.js"></script> +<script src="/resources/testharnessreport.js"></script> +<script src="/css/support/parsing-testcommon.js"></script> +<script> +test_valid_value("text-underline-position", "auto"); + +test_valid_value("text-underline-position", "under"); +test_valid_value("text-underline-position", "left"); +test_valid_value("text-underline-position", "right"); +test_valid_value("text-underline-position", "under left"); +test_valid_value("text-underline-position", "right under", "under right"); +</script>
diff --git a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-type-expected.txt b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-type-expected.txt index 0295837..e53364b6 100644 --- a/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-type-expected.txt +++ b/third_party/blink/web_tests/external/wpt/css/css-typed-om/the-stylepropertymap/properties/scroll-snap-type-expected.txt
@@ -17,6 +17,6 @@ PASS Setting 'scroll-snap-type' to a URL throws TypeError PASS Setting 'scroll-snap-type' to a transform throws TypeError PASS 'scroll-snap-type' does not supported 'x mandatory' -PASS 'scroll-snap-type' does not supported 'inline proximity' +FAIL 'scroll-snap-type' does not supported 'inline proximity' assert_equals: Unsupported value must be a CSSStyleValue and not one of its subclasses expected "[object CSSStyleValue]" but got "[object CSSKeywordValue]" Harness: the test ran to completion.
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/csp-fetch-from-installed-service-worker-default-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/csp-fetch-from-installed-service-worker-default-expected.txt deleted file mode 100644 index 19b56ff..0000000 --- a/third_party/blink/web_tests/http/tests/serviceworker/csp-fetch-from-installed-service-worker-default-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -PASS CSP test for default-src in installed ServiceWorkerGlobalScope -PASS importScripts test for default-src -FAIL eval test for default-src assert_throws: eval() should throw EvalError. function "function() { eval('1 + 1'); }" did not throw -PASS Fetch test for default-src -PASS Redirected fetch test for default-src -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/csp-fetch-from-installed-service-worker-script-expected.txt b/third_party/blink/web_tests/http/tests/serviceworker/csp-fetch-from-installed-service-worker-script-expected.txt deleted file mode 100644 index e13cc67..0000000 --- a/third_party/blink/web_tests/http/tests/serviceworker/csp-fetch-from-installed-service-worker-script-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -PASS CSP test for script-src in installed ServiceWorkerGlobalScope -PASS importScripts test for script-src -FAIL eval test for script-src assert_throws: eval() should throw EvalError. function "function() { eval('1 + 1'); }" did not throw -PASS Fetch test for script-src -PASS Redirected fetch test for script-src -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/service-worker-csp-default.https-expected.txt b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/service-worker-csp-default.https-expected.txt deleted file mode 100644 index 7409f704..0000000 --- a/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/service-worker-csp-default.https-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -PASS CSP test for default-src in ServiceWorkerGlobalScope -PASS importScripts test for default-src -FAIL eval test for default-src assert_throws: eval() should throw EvalError. function "function() { eval('1 + 1'); }" did not throw -PASS Fetch test for default-src -PASS Redirected fetch test for default-src -Harness: the test ran to completion. -
diff --git a/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/service-worker-csp-script.https-expected.txt b/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/service-worker-csp-script.https-expected.txt deleted file mode 100644 index a4f95319..0000000 --- a/third_party/blink/web_tests/virtual/omt-worker-fetch/external/wpt/service-workers/service-worker/service-worker-csp-script.https-expected.txt +++ /dev/null
@@ -1,8 +0,0 @@ -This is a testharness.js-based test. -PASS CSP test for script-src in ServiceWorkerGlobalScope -PASS importScripts test for script-src -FAIL eval test for script-src assert_throws: eval() should throw EvalError. function "function() { eval('1 + 1'); }" did not throw -PASS Fetch test for script-src -PASS Redirected fetch test for script-src -Harness: the test ran to completion. -
diff --git a/third_party/ink/OWNERS b/third_party/ink/OWNERS index 6a73fc4..0392501d 100644 --- a/third_party/ink/OWNERS +++ b/third_party/ink/OWNERS
@@ -1,4 +1,3 @@ dstockwell@chromium.org dvallet@chromium.org -fdegros@chromium.org martiw@chromium.org
diff --git a/third_party/mocha/LICENSE b/third_party/mocha/LICENSE index 9919641..9ab23f6 100644 --- a/third_party/mocha/LICENSE +++ b/third_party/mocha/LICENSE
@@ -1,6 +1,6 @@ (The MIT License) -Copyright (c) 2011-2016 TJ Holowaychuk <tj@vision-media.ca> +Copyright (c) 2011-2018 JS Foundation and contributors, https://js.foundation Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the
diff --git a/third_party/mocha/OWNERS b/third_party/mocha/OWNERS index a3fb9ac..81d7ea4 100644 --- a/third_party/mocha/OWNERS +++ b/third_party/mocha/OWNERS
@@ -1 +1,2 @@ michaelpg@chromium.org +dpapad@chromium.org
diff --git a/third_party/mocha/README.chromium b/third_party/mocha/README.chromium index 3fdb3e4..e5bee35 100644 --- a/third_party/mocha/README.chromium +++ b/third_party/mocha/README.chromium
@@ -1,7 +1,7 @@ Name: Mocha Short Name: mocha URL: https://github.com/mochajs/mocha -Version: 2.5.3 +Version: 6.1.4 License: MIT License File: NOT_SHIPPED Security Critical: no
diff --git a/third_party/mocha/README.md b/third_party/mocha/README.md index e2d0bb9..81285196 100644 --- a/third_party/mocha/README.md +++ b/third_party/mocha/README.md
@@ -1,84 +1,105 @@ -<br><br> <p align="center"> <img src="https://cldup.com/xFVFxOioAU.svg" alt="Mocha test framework"/> </p> -<br><br> -[](http://travis-ci.org/mochajs/mocha) [](https://gitter.im/mochajs/mocha?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -[](#backers) -[](#sponsors) +<p align="center">:coffee: Simple, flexible, fun JavaScript test framework for Node.js & The Browser :coffee:</p> - Mocha is a simple, flexible, fun JavaScript test framework for node.js and the browser. For more information view the [documentation](http://mochajs.org). +<p align="center"><a href="http://travis-ci.org/mochajs/mocha"><img src="https://api.travis-ci.org/mochajs/mocha.svg?branch=master" alt="Build Status"></a> <a href="https://coveralls.io/github/mochajs/mocha"><img src="https://coveralls.io/repos/github/mochajs/mocha/badge.svg" alt="Coverage Status"></a> <a href="https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmochajs%2Fmocha?ref=badge_shield"><img src="https://app.fossa.io/api/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmochajs%2Fmocha.svg?type=shield" alt="FOSSA Status"></a> <a href="https://gitter.im/mochajs/mocha?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge"><img src="https://badges.gitter.im/Join%20Chat.svg" alt="Gitter"></a> <a href="https://github.com/mochajs/mocha#backers"><img src="https://opencollective.com/mochajs/backers/badge.svg" alt="OpenCollective"></a> <a href="https://github.com/mochajs/mocha#sponsors"><img src="https://opencollective.com/mochajs/sponsors/badge.svg" alt="OpenCollective"></a> +</p> + +<p align="center"><br><img alt="Mocha Browser Support h/t SauceLabs" src="https://saucelabs.com/browser-matrix/mochajs.svg" width="354"></p> ## Links - - [Changelog](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md) - - [Google Group](http://groups.google.com/group/mochajs) - - [Wiki](https://github.com/mochajs/mocha/wiki) - - Mocha [Extensions and reporters](https://github.com/mochajs/mocha/wiki) - +- **[Documentation](https://mochajs.org/)** +- **[Release Notes / History / Changes](https://github.com/mochajs/mocha/blob/master/CHANGELOG.md)** +- [Code of Conduct](https://github.com/mochajs/mocha/blob/master/.github/CODE_OF_CONDUCT.md) +- [Contributing](https://github.com/mochajs/mocha/blob/master/.github/CONTRIBUTING.md) +- [Gitter Chatroom](https://gitter.im/mochajs/mocha) (ask questions here!) +- [Google Group](https://groups.google.com/group/mochajs) +- [Issue Tracker](https://github.com/mochajs/mocha/issues) ## Backers -[Become a backer]((https://opencollective.com/mochajs#backer)) and show your support to our open source project. +[Become a backer](https://opencollective.com/mochajs#backer) and show your support to our open source project. -<a href="https://opencollective.com/mochajs/backer/0/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/0/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/1/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/1/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/2/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/2/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/3/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/3/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/4/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/4/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/5/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/5/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/6/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/6/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/7/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/7/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/8/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/8/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/9/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/9/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/10/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/10/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/11/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/11/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/12/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/12/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/13/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/13/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/14/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/14/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/15/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/15/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/16/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/16/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/17/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/17/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/18/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/18/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/19/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/19/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/20/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/20/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/21/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/21/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/22/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/22/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/23/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/23/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/24/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/24/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/25/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/25/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/26/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/26/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/27/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/27/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/28/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/28/avatar"></a> -<a href="https://opencollective.com/mochajs/backer/29/website" target="_blank"><img src="https://opencollective.com/mochajs/backer/29/avatar"></a> - +[](https://opencollective.com/mochajs/backer/0/website) +[](https://opencollective.com/mochajs/backer/1/website) +[](https://opencollective.com/mochajs/backer/2/website) +[](https://opencollective.com/mochajs/backer/3/website) +[](https://opencollective.com/mochajs/backer/4/website) +[](https://opencollective.com/mochajs/backer/5/website) +[](https://opencollective.com/mochajs/backer/6/website) +[](https://opencollective.com/mochajs/backer/7/website) +[](https://opencollective.com/mochajs/backer/8/website) +[](https://opencollective.com/mochajs/backer/9/website) +[](https://opencollective.com/mochajs/backer/10/website) +[](https://opencollective.com/mochajs/backer/11/website) +[](https://opencollective.com/mochajs/backer/12/website) +[](https://opencollective.com/mochajs/backer/13/website) +[](https://opencollective.com/mochajs/backer/14/website) +[](https://opencollective.com/mochajs/backer/15/website) +[](https://opencollective.com/mochajs/backer/16/website) +[](https://opencollective.com/mochajs/backer/17/website) +[](https://opencollective.com/mochajs/backer/18/website) +[](https://opencollective.com/mochajs/backer/19/website) +[](https://opencollective.com/mochajs/backer/20/website) +[](https://opencollective.com/mochajs/backer/21/website) +[](https://opencollective.com/mochajs/backer/22/website) +[](https://opencollective.com/mochajs/backer/23/website) +[](https://opencollective.com/mochajs/backer/24/website) +[](https://opencollective.com/mochajs/backer/25/website) +[](https://opencollective.com/mochajs/backer/26/website) +[](https://opencollective.com/mochajs/backer/27/website) +[](https://opencollective.com/mochajs/backer/28/website) +[](https://opencollective.com/mochajs/backer/29/website) ## Sponsors -Does your company use Mocha? Ask your manager or marketing team if your company would be interested in supporting our project. Support will allow the maintainers to dedicate more time for maintenance and new features for everyone. Also, your company's logo will show [on GitHub](https://github.com/mochajs/mocha#readme) and on [our site](https://mochajs.org)--who doesn't want a little extra exposure? [Here's the info](https://opencollective.com/mochajs#sponsor). +Does your company use Mocha? Ask your manager or marketing team if your company would be interested in supporting our project. Support will allow the maintainers to dedicate more time for maintenance and new features for everyone. Also, your company's logo will show [on GitHub](https://github.com/mochajs/mocha#readme) and on [our site](https://mochajs.org) - who doesn't want a little extra exposure? [Here's the info](https://opencollective.com/mochajs#sponsor). -<a href="https://opencollective.com/mochajs/sponsor/0/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/0/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/1/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/1/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/2/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/2/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/3/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/3/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/4/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/4/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/5/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/5/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/6/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/6/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/7/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/7/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/8/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/8/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/9/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/9/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/10/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/10/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/11/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/11/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/12/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/12/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/13/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/13/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/14/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/14/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/15/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/15/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/16/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/16/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/17/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/17/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/18/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/18/avatar"></a> -<a href="https://opencollective.com/mochajs/sponsor/19/website" target="_blank"><img src="https://opencollective.com/mochajs/sponsor/19/avatar"></a> +[](https://opencollective.com/mochajs/sponsor/0/website) +[](https://opencollective.com/mochajs/sponsor/1/website) +[](https://opencollective.com/mochajs/sponsor/2/website) +[](https://opencollective.com/mochajs/sponsor/3/website) +[](https://opencollective.com/mochajs/sponsor/4/website) +[](https://opencollective.com/mochajs/sponsor/5/website) +[](https://opencollective.com/mochajs/sponsor/6/website) +[](https://opencollective.com/mochajs/sponsor/7/website) +[](https://opencollective.com/mochajs/sponsor/8/website) +[](https://opencollective.com/mochajs/sponsor/9/website) +[](https://opencollective.com/mochajs/sponsor/10/website) +[](https://opencollective.com/mochajs/sponsor/11/website) +[](https://opencollective.com/mochajs/sponsor/12/website) +[](https://opencollective.com/mochajs/sponsor/13/website) +[](https://opencollective.com/mochajs/sponsor/14/website) +[](https://opencollective.com/mochajs/sponsor/15/website) +[](https://opencollective.com/mochajs/sponsor/16/website) +[](https://opencollective.com/mochajs/sponsor/17/website) +[](https://opencollective.com/mochajs/sponsor/18/website) +[](https://opencollective.com/mochajs/sponsor/19/website) + +## Development + +You might want to know that: + +- Mocha is the *most-depended-upon* module on npm (source: [libraries.io](https://libraries.io/search?order=desc&platforms=NPM&sort=dependents_count)), and +- Mocha is an *independent* open-source project, maintained exclusively by volunteers. + +You might want to help: + +- New to contributing to Mocha? Check out this list of [good first issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue+is%3Aopen+label%3Agood-first-issue) +- Mocha could use a hand with [these issues](https://github.com/mochajs/mocha/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) +- The [maintainer's handbook](https://github.com/mochajs/mocha/blob/master/MAINTAINERS.md) explains how things get done + +Finally, come [chat with the maintainers](https://gitter.im/mochajs/contributors) on Gitter if you want to help with: + +- Triaging issues, answering questions +- Review, merging, and closing pull requests +- Other project-maintenance-y things ## License -MIT +[MIT](LICENSE) + +[](https://app.fossa.io/projects/git%2Bhttps%3A%2F%2Fgithub.com%2Fmochajs%2Fmocha?ref=badge_large)
diff --git a/third_party/mocha/mocha.js b/third_party/mocha/mocha.js index af90ada..508a306 100644 --- a/third_party/mocha/mocha.js +++ b/third_party/mocha/mocha.js
@@ -1,10 +1,15 @@ -(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ +(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){ (function (process,global){ +'use strict'; + +/* eslint no-unused-vars: off */ +/* eslint-env commonjs */ + /** * Shim process.stdout. */ -process.stdout = require('browser-stdout')(); +process.stdout = require('browser-stdout')({label: false}); var Mocha = require('./lib/mocha'); @@ -14,7 +19,7 @@ * @return {undefined} */ -var mocha = new Mocha({ reporter: 'html' }); +var mocha = new Mocha({reporter: 'html'}); /** * Save timer references to avoid Sinon interfering (see GH-237). @@ -35,15 +40,17 @@ * Revert to original onerror handler if previously defined. */ -process.removeListener = function(e, fn){ - if ('uncaughtException' == e) { +process.removeListener = function(e, fn) { + if (e === 'uncaughtException') { if (originalOnerrorHandler) { global.onerror = originalOnerrorHandler; } else { global.onerror = function() {}; } - var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); - if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); } + var i = uncaughtExceptionHandlers.indexOf(fn); + if (i !== -1) { + uncaughtExceptionHandlers.splice(i, 1); + } } }; @@ -51,9 +58,9 @@ * Implements uncaughtException listener. */ -process.on = function(e, fn){ - if ('uncaughtException' == e) { - global.onerror = function(err, url, line){ +process.on = function(e, fn) { + if (e === 'uncaughtException') { + global.onerror = function(err, url, line) { fn(new Error(err + ' (' + url + ':' + line + ')')); return !mocha.allowUncaught; }; @@ -66,12 +73,12 @@ // Ensure that this default UI does not expose its methods to the global scope. mocha.suite.removeAllListeners('pre-require'); -var immediateQueue = [] - , immediateTimeout; +var immediateQueue = []; +var immediateTimeout; function timeslice() { var immediateStart = new Date().getTime(); - while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { + while (immediateQueue.length && new Date().getTime() - immediateStart < 100) { immediateQueue.shift()(); } if (immediateQueue.length) { @@ -98,7 +105,7 @@ * only receive the 'message' attribute of the Error. */ mocha.throwError = function(err) { - Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) { + uncaughtExceptionHandlers.forEach(function(fn) { fn(err); }); throw err; @@ -109,7 +116,7 @@ * Normally this would happen in Mocha.prototype.loadFiles. */ -mocha.ui = function(ui){ +mocha.ui = function(ui) { Mocha.prototype.ui.call(this, ui); this.suite.emit('pre-require', global, null, this); return this; @@ -119,9 +126,15 @@ * Setup mocha with the given setting options. */ -mocha.setup = function(opts){ - if ('string' == typeof opts) opts = { ui: opts }; - for (var opt in opts) this[opt](opts[opt]); +mocha.setup = function(opts) { + if (typeof opts === 'string') { + opts = {ui: opts}; + } + for (var opt in opts) { + if (opts.hasOwnProperty(opt)) { + this[opt](opts[opt]); + } + } return this; }; @@ -129,22 +142,34 @@ * Run mocha, returning the Runner. */ -mocha.run = function(fn){ +mocha.run = function(fn) { var options = mocha.options; mocha.globals('location'); var query = Mocha.utils.parseQuery(global.location.search || ''); - if (query.grep) mocha.grep(new RegExp(query.grep)); - if (query.fgrep) mocha.grep(query.fgrep); - if (query.invert) mocha.invert(); + if (query.grep) { + mocha.grep(query.grep); + } + if (query.fgrep) { + mocha.fgrep(query.fgrep); + } + if (query.invert) { + mocha.invert(); + } - return Mocha.prototype.run.call(mocha, function(err){ + return Mocha.prototype.run.call(mocha, function(err) { // The DOM Document is not available in Web Workers. var document = global.document; - if (document && document.getElementById('mocha') && options.noHighlighting !== true) { + if ( + document && + document.getElementById('mocha') && + options.noHighlighting !== true + ) { Mocha.utils.highlightTags('code'); } - if (fn) fn(err); + if (fn) { + fn(err); + } }); }; @@ -168,208 +193,181 @@ module.exports = global; }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./lib/mocha":14,"_process":58,"browser-stdout":42}],2:[function(require,module,exports){ -/* eslint-disable no-unused-vars */ -module.exports = function(type) { - return function() {}; +},{"./lib/mocha":14,"_process":69,"browser-stdout":41}],2:[function(require,module,exports){ +(function (process,global){ +'use strict'; + +/** + * Web Notifications module. + * @module Growl + */ + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ +var Date = global.Date; +var setTimeout = global.setTimeout; +var EVENT_RUN_END = require('../runner').constants.EVENT_RUN_END; + +/** + * Checks if browser notification support exists. + * + * @public + * @see {@link https://caniuse.com/#feat=notifications|Browser support (notifications)} + * @see {@link https://caniuse.com/#feat=promises|Browser support (promises)} + * @see {@link Mocha#growl} + * @see {@link Mocha#isGrowlCapable} + * @return {boolean} whether browser notification support exists + */ +exports.isCapable = function() { + var hasNotificationSupport = 'Notification' in window; + var hasPromiseSupport = typeof Promise === 'function'; + return process.browser && hasNotificationSupport && hasPromiseSupport; }; -},{}],3:[function(require,module,exports){ /** - * Module exports. - */ - -exports.EventEmitter = EventEmitter; - -/** - * Object#toString reference. - */ -var objToString = Object.prototype.toString; - -/** - * Check if a value is an array. + * Implements browser notifications as a pseudo-reporter. * - * @api private - * @param {*} val The value to test. - * @return {boolean} true if the value is an array, otherwise false. + * @public + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/notification|Notification API} + * @see {@link https://developers.google.com/web/fundamentals/push-notifications/display-a-notification|Displaying a Notification} + * @see {@link Growl#isPermitted} + * @see {@link Mocha#_growl} + * @param {Runner} runner - Runner instance. */ -function isArray(val) { - return objToString.call(val) === '[object Array]'; +exports.notify = function(runner) { + var promise = isPermitted(); + + /** + * Attempt notification. + */ + var sendNotification = function() { + // If user hasn't responded yet... "No notification for you!" (Seinfeld) + Promise.race([promise, Promise.resolve(undefined)]) + .then(canNotify) + .then(function() { + display(runner); + }) + .catch(notPermitted); + }; + + runner.once(EVENT_RUN_END, sendNotification); +}; + +/** + * Checks if browser notification is permitted by user. + * + * @private + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Notification/permission|Notification.permission} + * @see {@link Mocha#growl} + * @see {@link Mocha#isGrowlPermitted} + * @returns {Promise<boolean>} promise determining if browser notification + * permissible when fulfilled. + */ +function isPermitted() { + var permitted = { + granted: function allow() { + return Promise.resolve(true); + }, + denied: function deny() { + return Promise.resolve(false); + }, + default: function ask() { + return Notification.requestPermission().then(function(permission) { + return permission === 'granted'; + }); + } + }; + + return permitted[Notification.permission](); } /** - * Event emitter constructor. + * @summary + * Determines if notification should proceed. * - * @api public + * @description + * Notification shall <strong>not</strong> proceed unless `value` is true. + * + * `value` will equal one of: + * <ul> + * <li><code>true</code> (from `isPermitted`)</li> + * <li><code>false</code> (from `isPermitted`)</li> + * <li><code>undefined</code> (from `Promise.race`)</li> + * </ul> + * + * @private + * @param {boolean|undefined} value - Determines if notification permissible. + * @returns {Promise<undefined>} Notification can proceed */ -function EventEmitter() {} +function canNotify(value) { + if (!value) { + var why = value === false ? 'blocked' : 'unacknowledged'; + var reason = 'not permitted by user (' + why + ')'; + return Promise.reject(new Error(reason)); + } + return Promise.resolve(); +} /** - * Add a listener. + * Displays the notification. * - * @api public - * @param {string} name Event name. - * @param {Function} fn Event handler. - * @return {EventEmitter} Emitter instance. + * @private + * @param {Runner} runner - Runner instance. */ -EventEmitter.prototype.on = function(name, fn) { - if (!this.$events) { - this.$events = {}; - } +function display(runner) { + var stats = runner.stats; + var symbol = { + cross: '\u274C', + tick: '\u2705' + }; + var logo = require('../../package').notifyLogo; + var _message; + var message; + var title; - if (!this.$events[name]) { - this.$events[name] = fn; - } else if (isArray(this.$events[name])) { - this.$events[name].push(fn); + if (stats.failures) { + _message = stats.failures + ' of ' + stats.tests + ' tests failed'; + message = symbol.cross + ' ' + _message; + title = 'Failed'; } else { - this.$events[name] = [this.$events[name], fn]; + _message = stats.passes + ' tests passed in ' + stats.duration + 'ms'; + message = symbol.tick + ' ' + _message; + title = 'Passed'; } - return this; -}; + // Send notification + var options = { + badge: logo, + body: message, + dir: 'ltr', + icon: logo, + lang: 'en-US', + name: 'mocha', + requireInteraction: false, + timestamp: Date.now() + }; + var notification = new Notification(title, options); -EventEmitter.prototype.addListener = EventEmitter.prototype.on; + // Autoclose after brief delay (makes various browsers act same) + var FORCE_DURATION = 4000; + setTimeout(notification.close.bind(notification), FORCE_DURATION); +} /** - * Adds a volatile listener. + * As notifications are tangential to our purpose, just log the error. * - * @api public - * @param {string} name Event name. - * @param {Function} fn Event handler. - * @return {EventEmitter} Emitter instance. + * @private + * @param {Error} err - Why notification didn't happen. */ -EventEmitter.prototype.once = function(name, fn) { - var self = this; +function notPermitted(err) { + console.error('notification error:', err.message); +} - function on() { - self.removeListener(name, on); - fn.apply(this, arguments); - } +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../../package":90,"../runner":34,"_process":69}],3:[function(require,module,exports){ +'use strict'; - on.listener = fn; - this.on(name, on); - - return this; -}; - -/** - * Remove a listener. - * - * @api public - * @param {string} name Event name. - * @param {Function} fn Event handler. - * @return {EventEmitter} Emitter instance. - */ -EventEmitter.prototype.removeListener = function(name, fn) { - if (this.$events && this.$events[name]) { - var list = this.$events[name]; - - if (isArray(list)) { - var pos = -1; - - for (var i = 0, l = list.length; i < l; i++) { - if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { - pos = i; - break; - } - } - - if (pos < 0) { - return this; - } - - list.splice(pos, 1); - - if (!list.length) { - delete this.$events[name]; - } - } else if (list === fn || (list.listener && list.listener === fn)) { - delete this.$events[name]; - } - } - - return this; -}; - -/** - * Remove all listeners for an event. - * - * @api public - * @param {string} name Event name. - * @return {EventEmitter} Emitter instance. - */ -EventEmitter.prototype.removeAllListeners = function(name) { - if (name === undefined) { - this.$events = {}; - return this; - } - - if (this.$events && this.$events[name]) { - this.$events[name] = null; - } - - return this; -}; - -/** - * Get all listeners for a given event. - * - * @api public - * @param {string} name Event name. - * @return {EventEmitter} Emitter instance. - */ -EventEmitter.prototype.listeners = function(name) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = []; - } - - if (!isArray(this.$events[name])) { - this.$events[name] = [this.$events[name]]; - } - - return this.$events[name]; -}; - -/** - * Emit an event. - * - * @api public - * @param {string} name Event name. - * @return {boolean} true if at least one handler was invoked, else false. - */ -EventEmitter.prototype.emit = function(name) { - if (!this.$events) { - return false; - } - - var handler = this.$events[name]; - - if (!handler) { - return false; - } - - var args = Array.prototype.slice.call(arguments, 1); - - if (typeof handler === 'function') { - handler.apply(this, args); - } else if (isArray(handler)) { - var listeners = handler.slice(); - - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - } else { - return false; - } - - return true; -}; - -},{}],4:[function(require,module,exports){ /** * Expose `Progress`. */ @@ -389,7 +387,7 @@ /** * Set progress size to `size`. * - * @api public + * @public * @param {number} size * @return {Progress} Progress instance. */ @@ -401,7 +399,7 @@ /** * Set text to `text`. * - * @api public + * @public * @param {string} text * @return {Progress} Progress instance. */ @@ -413,7 +411,7 @@ /** * Set font size to `size`. * - * @api public + * @public * @param {number} size * @return {Progress} Progress instance. */ @@ -482,14 +480,16 @@ var w = ctx.measureText(text).width; ctx.fillText(text, x - w / 2 + 1, y + fontSize / 2 - 1); - } catch (err) { + } catch (ignore) { // don't fail if we can't render progress } return this; }; -},{}],5:[function(require,module,exports){ +},{}],4:[function(require,module,exports){ (function (global){ +'use strict'; + exports.isatty = function isatty() { return true; }; @@ -503,7 +503,11 @@ }; }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],6:[function(require,module,exports){ +},{}],5:[function(require,module,exports){ +'use strict'; +/** + * @module Context + */ /** * Expose `Context`. */ @@ -513,16 +517,16 @@ /** * Initialize a new `Context`. * - * @api private + * @private */ function Context() {} /** * Set or get the context `Runnable` to `runnable`. * - * @api private + * @private * @param {Runnable} runnable - * @return {Context} + * @return {Context} context */ Context.prototype.runnable = function(runnable) { if (!arguments.length) { @@ -533,9 +537,9 @@ }; /** - * Set test timeout `ms`. + * Set or get test timeout `ms`. * - * @api private + * @private * @param {number} ms * @return {Context} self */ @@ -550,23 +554,29 @@ /** * Set test timeout `enabled`. * - * @api private + * @private * @param {boolean} enabled * @return {Context} self */ Context.prototype.enableTimeouts = function(enabled) { + if (!arguments.length) { + return this.runnable().enableTimeouts(); + } this.runnable().enableTimeouts(enabled); return this; }; /** - * Set test slowness threshold `ms`. + * Set or get test slowness threshold `ms`. * - * @api private + * @private * @param {number} ms * @return {Context} self */ Context.prototype.slow = function(ms) { + if (!arguments.length) { + return this.runnable().slow(); + } this.runnable().slow(ms); return this; }; @@ -574,18 +584,17 @@ /** * Mark a test as skipped. * - * @api private - * @return {Context} self + * @private + * @throws Pending */ Context.prototype.skip = function() { this.runnable().skip(); - return this; }; /** - * Allow a number of retries on failed tests + * Set or get a number of allowed retries on failed tests * - * @api private + * @private * @param {number} n * @return {Context} self */ @@ -597,22 +606,151 @@ return this; }; +},{}],6:[function(require,module,exports){ +'use strict'; /** - * Inspect the context void of `._runnable`. - * - * @api private - * @return {string} + * @module Errors */ -Context.prototype.inspect = function() { - return JSON.stringify(this, function(key, val) { - return key === 'runnable' || key === 'test' ? undefined : val; - }, 2); +/** + * Factory functions to create throwable error objects + */ + +/** + * Creates an error object to be thrown when no files to be tested could be found using specified pattern. + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} pattern - User-specified argument value. + * @returns {Error} instance detailing the error condition + */ +function createNoFilesMatchPatternError(message, pattern) { + var err = new Error(message); + err.code = 'ERR_MOCHA_NO_FILES_MATCH_PATTERN'; + err.pattern = pattern; + return err; +} + +/** + * Creates an error object to be thrown when the reporter specified in the options was not found. + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} reporter - User-specified reporter value. + * @returns {Error} instance detailing the error condition + */ +function createInvalidReporterError(message, reporter) { + var err = new TypeError(message); + err.code = 'ERR_MOCHA_INVALID_REPORTER'; + err.reporter = reporter; + return err; +} + +/** + * Creates an error object to be thrown when the interface specified in the options was not found. + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} ui - User-specified interface value. + * @returns {Error} instance detailing the error condition + */ +function createInvalidInterfaceError(message, ui) { + var err = new Error(message); + err.code = 'ERR_MOCHA_INVALID_INTERFACE'; + err.interface = ui; + return err; +} + +/** + * Creates an error object to be thrown when a behavior, option, or parameter is unsupported. + * + * @public + * @param {string} message - Error message to be displayed. + * @returns {Error} instance detailing the error condition + */ +function createUnsupportedError(message) { + var err = new Error(message); + err.code = 'ERR_MOCHA_UNSUPPORTED'; + return err; +} + +/** + * Creates an error object to be thrown when an argument is missing. + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} argument - Argument name. + * @param {string} expected - Expected argument datatype. + * @returns {Error} instance detailing the error condition + */ +function createMissingArgumentError(message, argument, expected) { + return createInvalidArgumentTypeError(message, argument, expected); +} + +/** + * Creates an error object to be thrown when an argument did not use the supported type + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} argument - Argument name. + * @param {string} expected - Expected argument datatype. + * @returns {Error} instance detailing the error condition + */ +function createInvalidArgumentTypeError(message, argument, expected) { + var err = new TypeError(message); + err.code = 'ERR_MOCHA_INVALID_ARG_TYPE'; + err.argument = argument; + err.expected = expected; + err.actual = typeof argument; + return err; +} + +/** + * Creates an error object to be thrown when an argument did not use the supported value + * + * @public + * @param {string} message - Error message to be displayed. + * @param {string} argument - Argument name. + * @param {string} value - Argument value. + * @param {string} [reason] - Why value is invalid. + * @returns {Error} instance detailing the error condition + */ +function createInvalidArgumentValueError(message, argument, value, reason) { + var err = new TypeError(message); + err.code = 'ERR_MOCHA_INVALID_ARG_VALUE'; + err.argument = argument; + err.value = value; + err.reason = typeof reason !== 'undefined' ? reason : 'is invalid'; + return err; +} + +/** + * Creates an error object to be thrown when an exception was caught, but the `Error` is falsy or undefined. + * + * @public + * @param {string} message - Error message to be displayed. + * @returns {Error} instance detailing the error condition + */ +function createInvalidExceptionError(message, value) { + var err = new Error(message); + err.code = 'ERR_MOCHA_INVALID_EXCEPTION'; + err.valueType = typeof value; + err.value = value; + return err; +} + +module.exports = { + createInvalidArgumentTypeError: createInvalidArgumentTypeError, + createInvalidArgumentValueError: createInvalidArgumentValueError, + createInvalidExceptionError: createInvalidExceptionError, + createInvalidInterfaceError: createInvalidInterfaceError, + createInvalidReporterError: createInvalidReporterError, + createMissingArgumentError: createMissingArgumentError, + createNoFilesMatchPatternError: createNoFilesMatchPatternError, + createUnsupportedError: createUnsupportedError }; },{}],7:[function(require,module,exports){ -/** - * Module dependencies. - */ +'use strict'; var Runnable = require('./runnable'); var inherits = require('./utils').inherits; @@ -624,11 +762,12 @@ module.exports = Hook; /** - * Initialize a new `Hook` with the given `title` and callback `fn`. + * Initialize a new `Hook` with the given `title` and callback `fn` * + * @class + * @extends Runnable * @param {String} title * @param {Function} fn - * @api private */ function Hook(title, fn) { Runnable.call(this, title, fn); @@ -643,9 +782,10 @@ /** * Get or set the test `err`. * + * @memberof Hook + * @public * @param {Error} err * @return {Error} - * @api public */ Hook.prototype.error = function(err) { if (!arguments.length) { @@ -657,14 +797,12 @@ this._error = err; }; -},{"./runnable":35,"./utils":39}],8:[function(require,module,exports){ -/** - * Module dependencies. - */ +},{"./runnable":33,"./utils":38}],8:[function(require,module,exports){ +'use strict'; -var Suite = require('../suite'); var Test = require('../test'); -var escapeRe = require('escape-string-regexp'); +var EVENT_FILE_PRE_REQUIRE = require('../suite').constants + .EVENT_FILE_PRE_REQUIRE; /** * BDD-style interface: @@ -683,11 +821,11 @@ * * @param {Suite} suite Root suite. */ -module.exports = function(suite) { +module.exports = function bddInterface(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha) { - var common = require('./common')(suites, context); + suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) { + var common = require('./common')(suites, context, mocha); context.before = common.before; context.after = common.after; @@ -701,24 +839,26 @@ */ context.describe = context.context = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; + return common.suite.create({ + title: title, + file: file, + fn: fn + }); }; /** * Pending describe. */ - context.xdescribe = context.xcontext = context.describe.skip = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); + context.xdescribe = context.xcontext = context.describe.skip = function( + title, + fn + ) { + return common.suite.skip({ + title: title, + file: file, + fn: fn + }); }; /** @@ -726,9 +866,11 @@ */ context.describe.only = function(title, fn) { - var suite = context.describe(title, fn); - mocha.grep(suite.fullTitle()); - return suite; + return common.suite.only({ + title: title, + file: file, + fn: fn + }); }; /** @@ -737,7 +879,7 @@ * acting as a thunk. */ - var it = context.it = context.specify = function(title, fn) { + context.it = context.specify = function(title, fn) { var suite = suites[0]; if (suite.isPending()) { fn = null; @@ -753,10 +895,7 @@ */ context.it.only = function(title, fn) { - var test = it(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - return test; + return common.test.only(mocha, context.it(title, fn)); }; /** @@ -764,7 +903,7 @@ */ context.xit = context.xspecify = context.it.skip = function(title) { - context.it(title); + return context.it(title); }; /** @@ -776,23 +915,46 @@ }); }; -},{"../suite":37,"../test":38,"./common":9,"escape-string-regexp":49}],9:[function(require,module,exports){ +module.exports.description = 'BDD or RSpec style [default]'; + +},{"../suite":36,"../test":37,"./common":9}],9:[function(require,module,exports){ 'use strict'; +var Suite = require('../suite'); +var errors = require('../errors'); +var createMissingArgumentError = errors.createMissingArgumentError; + /** * Functions common to more than one interface. * * @param {Suite[]} suites * @param {Context} context + * @param {Mocha} mocha * @return {Object} An object containing common functions. */ -module.exports = function(suites, context) { +module.exports = function(suites, context, mocha) { + /** + * Check if the suite should be tested. + * + * @private + * @param {Suite} suite - suite to check + * @returns {boolean} + */ + function shouldBeTested(suite) { + return ( + !mocha.options.grep || + (mocha.options.grep && + mocha.options.grep.test(suite.fullTitle()) && + !mocha.options.invert) + ); + } + return { /** * This is only present if flag --delay is passed into Mocha. It triggers * root suite execution. * - * @param {Suite} suite The root wuite. + * @param {Suite} suite The root suite. * @return {Function} A function which runs the root suite */ runWithSuite: function runWithSuite(suite) { @@ -841,8 +1003,93 @@ suites[0].afterEach(name, fn); }, + suite: { + /** + * Create an exclusive Suite; convenience function + * See docstring for create() below. + * + * @param {Object} opts + * @returns {Suite} + */ + only: function only(opts) { + opts.isOnly = true; + return this.create(opts); + }, + + /** + * Create a Suite, but skip it; convenience function + * See docstring for create() below. + * + * @param {Object} opts + * @returns {Suite} + */ + skip: function skip(opts) { + opts.pending = true; + return this.create(opts); + }, + + /** + * Creates a suite. + * + * @param {Object} opts Options + * @param {string} opts.title Title of Suite + * @param {Function} [opts.fn] Suite Function (not always applicable) + * @param {boolean} [opts.pending] Is Suite pending? + * @param {string} [opts.file] Filepath where this Suite resides + * @param {boolean} [opts.isOnly] Is Suite exclusive? + * @returns {Suite} + */ + create: function create(opts) { + var suite = Suite.create(suites[0], opts.title); + suite.pending = Boolean(opts.pending); + suite.file = opts.file; + suites.unshift(suite); + if (opts.isOnly) { + if (mocha.options.forbidOnly && shouldBeTested(suite)) { + throw new Error('`.only` forbidden'); + } + + suite.parent.appendOnlySuite(suite); + } + if (suite.pending) { + if (mocha.options.forbidPending && shouldBeTested(suite)) { + throw new Error('Pending test forbidden'); + } + } + if (typeof opts.fn === 'function') { + opts.fn.call(suite); + suites.shift(); + } else if (typeof opts.fn === 'undefined' && !suite.pending) { + throw createMissingArgumentError( + 'Suite "' + + suite.fullTitle() + + '" was defined but no callback was supplied. ' + + 'Supply a callback or explicitly skip the suite.', + 'callback', + 'function' + ); + } else if (!opts.fn && suite.pending) { + suites.shift(); + } + + return suite; + } + }, + test: { /** + * Exclusive test-case. + * + * @param {Object} mocha + * @param {Function} test + * @returns {*} + */ + only: function(mocha, test) { + test.parent.appendOnlyTest(test); + return test; + }, + + /** * Pending test case. * * @param {string} title @@ -863,11 +1110,8 @@ }; }; -},{}],10:[function(require,module,exports){ -/** - * Module dependencies. - */ - +},{"../errors":6,"../suite":36}],10:[function(require,module,exports){ +'use strict'; var Suite = require('../suite'); var Test = require('../test'); @@ -891,7 +1135,7 @@ module.exports = function(suite) { var suites = [suite]; - suite.on('require', visit); + suite.on(Suite.constants.EVENT_FILE_REQUIRE, visit); function visit(obj, file) { var suite; @@ -926,20 +1170,22 @@ } }; -},{"../suite":37,"../test":38}],11:[function(require,module,exports){ +module.exports.description = 'Node.js module ("exports") style'; + +},{"../suite":36,"../test":37}],11:[function(require,module,exports){ +'use strict'; + exports.bdd = require('./bdd'); exports.tdd = require('./tdd'); exports.qunit = require('./qunit'); exports.exports = require('./exports'); },{"./bdd":8,"./exports":10,"./qunit":12,"./tdd":13}],12:[function(require,module,exports){ -/** - * Module dependencies. - */ +'use strict'; -var Suite = require('../suite'); var Test = require('../test'); -var escapeRe = require('escape-string-regexp'); +var EVENT_FILE_PRE_REQUIRE = require('../suite').constants + .EVENT_FILE_PRE_REQUIRE; /** * QUnit-style interface: @@ -966,11 +1212,11 @@ * * @param {Suite} suite Root suite. */ -module.exports = function(suite) { +module.exports = function qUnitInterface(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha) { - var common = require('./common')(suites, context); + suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) { + var common = require('./common')(suites, context, mocha); context.before = common.before; context.after = common.after; @@ -985,19 +1231,26 @@ if (suites.length > 1) { suites.shift(); } - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - return suite; + return common.suite.create({ + title: title, + file: file, + fn: false + }); }; /** - * Exclusive test-case. + * Exclusive Suite. */ - context.suite.only = function(title, fn) { - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); + context.suite.only = function(title) { + if (suites.length > 1) { + suites.shift(); + } + return common.suite.only({ + title: title, + file: file, + fn: false + }); }; /** @@ -1018,9 +1271,7 @@ */ context.test.only = function(title, fn) { - var test = context.test(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); + return common.test.only(mocha, context.test(title, fn)); }; context.test.skip = common.test.skip; @@ -1028,14 +1279,14 @@ }); }; -},{"../suite":37,"../test":38,"./common":9,"escape-string-regexp":49}],13:[function(require,module,exports){ -/** - * Module dependencies. - */ +module.exports.description = 'QUnit style'; -var Suite = require('../suite'); +},{"../suite":36,"../test":37,"./common":9}],13:[function(require,module,exports){ +'use strict'; + var Test = require('../test'); -var escapeRe = require('escape-string-regexp'); +var EVENT_FILE_PRE_REQUIRE = require('../suite').constants + .EVENT_FILE_PRE_REQUIRE; /** * TDD-style interface: @@ -1065,8 +1316,8 @@ module.exports = function(suite) { var suites = [suite]; - suite.on('pre-require', function(context, file, mocha) { - var common = require('./common')(suites, context); + suite.on(EVENT_FILE_PRE_REQUIRE, function(context, file, mocha) { + var common = require('./common')(suites, context, mocha); context.setup = common.beforeEach; context.teardown = common.afterEach; @@ -1079,31 +1330,33 @@ * nested suites and/or tests. */ context.suite = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.file = file; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; + return common.suite.create({ + title: title, + file: file, + fn: fn + }); }; /** * Pending suite. */ context.suite.skip = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); + return common.suite.skip({ + title: title, + file: file, + fn: fn + }); }; /** * Exclusive test-case. */ context.suite.only = function(title, fn) { - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); + return common.suite.only({ + title: title, + file: file, + fn: fn + }); }; /** @@ -1126,9 +1379,7 @@ */ context.test.only = function(title, fn) { - var test = context.test(title, fn); - var reString = '^' + escapeRe(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); + return common.test.only(mocha, context.test(title, fn)); }; context.test.skip = common.test.skip; @@ -1136,26 +1387,34 @@ }); }; -},{"../suite":37,"../test":38,"./common":9,"escape-string-regexp":49}],14:[function(require,module,exports){ -(function (process,global,__dirname){ +module.exports.description = + 'traditional "suite"/"test" instead of BDD\'s "describe"/"it"'; + +},{"../suite":36,"../test":37,"./common":9}],14:[function(require,module,exports){ +(function (process,global){ +'use strict'; + /*! * mocha * Copyright(c) 2011 TJ Holowaychuk <tj@vision-media.ca> * MIT Licensed */ -/** - * Module dependencies. - */ - var escapeRe = require('escape-string-regexp'); var path = require('path'); -var reporters = require('./reporters'); +var builtinReporters = require('./reporters'); +var growl = require('./growl'); var utils = require('./utils'); - -/** - * Expose `Mocha`. - */ +var mocharc = require('./mocharc.json'); +var errors = require('./errors'); +var Suite = require('./suite'); +var createStatsCollector = require('./stats-collector'); +var createInvalidReporterError = errors.createInvalidReporterError; +var createInvalidInterfaceError = errors.createInvalidInterfaceError; +var EVENT_FILE_PRE_REQUIRE = Suite.constants.EVENT_FILE_PRE_REQUIRE; +var EVENT_FILE_POST_REQUIRE = Suite.constants.EVENT_FILE_POST_REQUIRE; +var EVENT_FILE_REQUIRE = Suite.constants.EVENT_FILE_REQUIRE; +var sQuote = utils.sQuote; exports = module.exports = Mocha; @@ -1172,80 +1431,132 @@ * Expose internals. */ +/** + * @public + * @class utils + * @memberof Mocha + */ exports.utils = utils; exports.interfaces = require('./interfaces'); -exports.reporters = reporters; +/** + * @public + * @memberof Mocha + */ +exports.reporters = builtinReporters; exports.Runnable = require('./runnable'); exports.Context = require('./context'); +/** + * + * @memberof Mocha + */ exports.Runner = require('./runner'); -exports.Suite = require('./suite'); +exports.Suite = Suite; exports.Hook = require('./hook'); exports.Test = require('./test'); /** - * Return image `name` path. + * Constructs a new Mocha instance with `options`. * - * @api private - * @param {string} name - * @return {string} - */ -function image(name) { - return path.join(__dirname, '../images', name + '.png'); -} - -/** - * Set up mocha with `options`. - * - * Options: - * - * - `ui` name "bdd", "tdd", "exports" etc - * - `reporter` reporter instance, defaults to `mocha.reporters.spec` - * - `globals` array of accepted globals - * - `timeout` timeout in milliseconds - * - `retries` number of times to retry failed tests - * - `bail` bail on the first test failure - * - `slow` milliseconds to wait before considering a test slow - * - `ignoreLeaks` ignore global leaks - * - `fullTrace` display the full stack-trace on failing - * - `grep` string or regexp to filter tests with - * - * @param {Object} options - * @api public + * @public + * @class Mocha + * @param {Object} [options] - Settings object. + * @param {boolean} [options.allowUncaught] - Propagate uncaught errors? + * @param {boolean} [options.asyncOnly] - Force `done` callback or promise? + * @param {boolean} [options.bail] - Bail after first test failure? + * @param {boolean} [options.checkLeaks] - If true, check leaks. + * @param {boolean} [options.delay] - Delay root suite execution? + * @param {boolean} [options.enableTimeouts] - Enable timeouts? + * @param {string} [options.fgrep] - Test filter given string. + * @param {boolean} [options.forbidOnly] - Tests marked `only` fail the suite? + * @param {boolean} [options.forbidPending] - Pending tests fail the suite? + * @param {boolean} [options.fullStackTrace] - Full stacktrace upon failure? + * @param {string[]} [options.global] - Variables expected in global scope. + * @param {RegExp|string} [options.grep] - Test filter given regular expression. + * @param {boolean} [options.growl] - Enable desktop notifications? + * @param {boolean} [options.hideDiff] - Suppress diffs from failures? + * @param {boolean} [options.ignoreLeaks] - Ignore global leaks? + * @param {boolean} [options.invert] - Invert test filter matches? + * @param {boolean} [options.noHighlighting] - Disable syntax highlighting? + * @param {string} [options.reporter] - Reporter name. + * @param {Object} [options.reporterOption] - Reporter settings object. + * @param {number} [options.retries] - Number of times to retry failed tests. + * @param {number} [options.slow] - Slow threshold value. + * @param {number|string} [options.timeout] - Timeout threshold value. + * @param {string} [options.ui] - Interface name. + * @param {boolean} [options.color] - Color TTY output from reporter? + * @param {boolean} [options.useInlineDiffs] - Use inline diffs? */ function Mocha(options) { - options = options || {}; + options = utils.assign({}, mocharc, options || {}); this.files = []; this.options = options; - if (options.grep) { - this.grep(new RegExp(options.grep)); + // root suite + this.suite = new exports.Suite('', new exports.Context(), true); + + if ('useColors' in options) { + utils.deprecate( + 'useColors is DEPRECATED and will be removed from a future version of Mocha. Instead, use the "color" option' + ); + options.color = 'color' in options ? options.color : options.useColors; } - if (options.fgrep) { - this.grep(options.fgrep); + + this.grep(options.grep) + .fgrep(options.fgrep) + .ui(options.ui) + .bail(options.bail) + .reporter(options.reporter, options.reporterOptions) + .useColors(options.color) + .slow(options.slow) + .useInlineDiffs(options.inlineDiffs) + .globals(options.globals); + + if ('enableTimeouts' in options) { + utils.deprecate( + 'enableTimeouts is DEPRECATED and will be removed from a future version of Mocha. Instead, use "timeout: false" to disable timeouts.' + ); + if (options.enableTimeouts === false) { + this.timeout(0); + } } - this.suite = new exports.Suite('', new exports.Context()); - this.ui(options.ui); - this.bail(options.bail); - this.reporter(options.reporter, options.reporterOptions); - if (typeof options.timeout !== 'undefined' && options.timeout !== null) { - this.timeout(options.timeout); + + // this guard exists because Suite#timeout does not consider `undefined` to be valid input + if (typeof options.timeout !== 'undefined') { + this.timeout(options.timeout === false ? 0 : options.timeout); } - if (typeof options.retries !== 'undefined' && options.retries !== null) { + + if ('retries' in options) { this.retries(options.retries); } - this.useColors(options.useColors); - if (options.enableTimeouts !== null) { - this.enableTimeouts(options.enableTimeouts); + + if ('diff' in options) { + this.hideDiff(!options.diff); } - if (options.slow) { - this.slow(options.slow); - } + + [ + 'allowUncaught', + 'asyncOnly', + 'checkLeaks', + 'delay', + 'forbidOnly', + 'forbidPending', + 'fullTrace', + 'growl', + 'invert' + ].forEach(function(opt) { + if (options[opt]) { + this[opt](); + } + }, this); } /** - * Enable or disable bailing on the first failure. + * Enables or disables bailing on the first failure. * - * @api public - * @param {boolean} [bail] + * @public + * @see {@link https://mochajs.org/#-b---bail|CLI option} + * @param {boolean} [bail=true] - Whether to bail on first error. + * @returns {Mocha} this + * @chainable */ Mocha.prototype.bail = function(bail) { if (!arguments.length) { @@ -1256,10 +1567,17 @@ }; /** - * Add test `file`. + * @summary + * Adds `file` to be loaded for execution. * - * @api public - * @param {string} file + * @description + * Useful for generic setup code that must be included within test suite. + * + * @public + * @see {@link https://mochajs.org/#--file-file|CLI option} + * @param {string} file - Pathname of file to be loaded. + * @returns {Mocha} this + * @chainable */ Mocha.prototype.addFile = function(file) { this.files.push(file); @@ -1267,13 +1585,20 @@ }; /** - * Set reporter to `reporter`, defaults to "spec". + * Sets reporter to `reporter`, defaults to "spec". * - * @param {String|Function} reporter name or constructor - * @param {Object} reporterOptions optional options - * @api public - * @param {string|Function} reporter name or constructor - * @param {Object} reporterOptions optional options + * @public + * @see {@link https://mochajs.org/#-r---reporter-name|CLI option} + * @see {@link https://mochajs.org/#reporters|Reporters} + * @param {String|Function} reporter - Reporter name or constructor. + * @param {Object} [reporterOptions] - Options used to configure the reporter. + * @returns {Mocha} this + * @chainable + * @throws {Error} if requested reporter cannot be loaded + * @example + * + * // Use XUnit reporter and direct its output to file + * mocha.reporter('xunit', { output: '/path/to/testspec.xunit.xml' }); */ Mocha.prototype.reporter = function(reporter, reporterOptions) { if (typeof reporter === 'function') { @@ -1282,26 +1607,43 @@ reporter = reporter || 'spec'; var _reporter; // Try to load a built-in reporter. - if (reporters[reporter]) { - _reporter = reporters[reporter]; + if (builtinReporters[reporter]) { + _reporter = builtinReporters[reporter]; } // Try to load reporters from process.cwd() and node_modules if (!_reporter) { try { _reporter = require(reporter); } catch (err) { - err.message.indexOf('Cannot find module') !== -1 - ? console.warn('"' + reporter + '" reporter not found') - : console.warn('"' + reporter + '" reporter blew up with error:\n' + err.stack); + if ( + err.code !== 'MODULE_NOT_FOUND' || + err.message.indexOf('Cannot find module') !== -1 + ) { + // Try to load reporters from a path (absolute or relative) + try { + _reporter = require(path.resolve(process.cwd(), reporter)); + } catch (_err) { + _err.code !== 'MODULE_NOT_FOUND' || + _err.message.indexOf('Cannot find module') !== -1 + ? console.warn(sQuote(reporter) + ' reporter not found') + : console.warn( + sQuote(reporter) + + ' reporter blew up with error:\n' + + err.stack + ); + } + } else { + console.warn( + sQuote(reporter) + ' reporter blew up with error:\n' + err.stack + ); + } } } - if (!_reporter && reporter === 'teamcity') { - console.warn('The Teamcity reporter was moved to a package named ' - + 'mocha-teamcity-reporter ' - + '(https://npmjs.org/package/mocha-teamcity-reporter).'); - } if (!_reporter) { - throw new Error('invalid reporter "' + reporter + '"'); + throw createInvalidReporterError( + 'invalid reporter ' + sQuote(reporter), + reporter + ); } this._reporter = _reporter; } @@ -1310,30 +1652,44 @@ }; /** - * Set test UI `name`, defaults to "bdd". + * Sets test UI `name`, defaults to "bdd". * - * @api public - * @param {string} bdd + * @public + * @see {@link https://mochajs.org/#-u---ui-name|CLI option} + * @see {@link https://mochajs.org/#interfaces|Interface DSLs} + * @param {string|Function} [ui=bdd] - Interface name or class. + * @returns {Mocha} this + * @chainable + * @throws {Error} if requested interface cannot be loaded */ -Mocha.prototype.ui = function(name) { - name = name || 'bdd'; - this._ui = exports.interfaces[name]; - if (!this._ui) { - try { - this._ui = require(name); - } catch (err) { - throw new Error('invalid interface "' + name + '"'); +Mocha.prototype.ui = function(ui) { + var bindInterface; + if (typeof ui === 'function') { + bindInterface = ui; + } else { + ui = ui || 'bdd'; + bindInterface = exports.interfaces[ui]; + if (!bindInterface) { + try { + bindInterface = require(ui); + } catch (err) { + throw createInvalidInterfaceError( + 'invalid interface ' + sQuote(ui), + ui + ); + } } } - this._ui = this._ui(this.suite); + bindInterface(this.suite); - this.suite.on('pre-require', function(context) { + this.suite.on(EVENT_FILE_PRE_REQUIRE, function(context) { exports.afterEach = context.afterEach || context.teardown; exports.after = context.after || context.suiteTeardown; exports.beforeEach = context.beforeEach || context.setup; exports.before = context.before || context.suiteSetup; exports.describe = context.describe || context.suite; exports.it = context.it || context.test; + exports.xit = context.xit || (context.test && context.test.skip); exports.setup = context.setup || context.beforeEach; exports.suiteSetup = context.suiteSetup || context.before; exports.suiteTeardown = context.suiteTeardown || context.after; @@ -1347,64 +1703,139 @@ }; /** - * Load registered files. + * Loads `files` prior to execution. * - * @api private + * @description + * The implementation relies on Node's `require` to execute + * the test interface functions and will be subject to its cache. + * + * @private + * @see {@link Mocha#addFile} + * @see {@link Mocha#run} + * @see {@link Mocha#unloadFiles} + * @param {Function} [fn] - Callback invoked upon completion. */ Mocha.prototype.loadFiles = function(fn) { var self = this; var suite = this.suite; this.files.forEach(function(file) { file = path.resolve(file); - suite.emit('pre-require', global, file, self); - suite.emit('require', require(file), file, self); - suite.emit('post-require', global, file, self); + suite.emit(EVENT_FILE_PRE_REQUIRE, global, file, self); + suite.emit(EVENT_FILE_REQUIRE, require(file), file, self); + suite.emit(EVENT_FILE_POST_REQUIRE, global, file, self); }); fn && fn(); }; /** - * Enable growl support. + * Removes a previously loaded file from Node's `require` cache. * - * @api private + * @private + * @static + * @see {@link Mocha#unloadFiles} + * @param {string} file - Pathname of file to be unloaded. */ -Mocha.prototype._growl = function(runner, reporter) { - var notify = require('growl'); - - runner.on('end', function() { - var stats = reporter.stats; - if (stats.failures) { - var msg = stats.failures + ' of ' + runner.total + ' tests failed'; - notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); - } else { - notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { - name: 'mocha', - title: 'Passed', - image: image('ok') - }); - } - }); +Mocha.unloadFile = function(file) { + delete require.cache[require.resolve(file)]; }; /** - * Add regexp to grep, if `re` is a string it is escaped. + * Unloads `files` from Node's `require` cache. * - * @param {RegExp|String} re - * @return {Mocha} - * @api public - * @param {RegExp|string} re - * @return {Mocha} + * @description + * This allows files to be "freshly" reloaded, providing the ability + * to reuse a Mocha instance programmatically. + * + * <strong>Intended for consumers — not used internally</strong> + * + * @public + * @see {@link Mocha.unloadFile} + * @see {@link Mocha#loadFiles} + * @see {@link Mocha#run} + * @returns {Mocha} this + * @chainable */ -Mocha.prototype.grep = function(re) { - this.options.grep = typeof re === 'string' ? new RegExp(escapeRe(re)) : re; +Mocha.prototype.unloadFiles = function() { + this.files.forEach(Mocha.unloadFile); return this; }; /** - * Invert `.grep()` matches. + * Sets `grep` filter after escaping RegExp special characters. * - * @return {Mocha} - * @api public + * @public + * @see {@link Mocha#grep} + * @param {string} str - Value to be converted to a regexp. + * @returns {Mocha} this + * @chainable + * @example + * + * // Select tests whose full title begins with `"foo"` followed by a period + * mocha.fgrep('foo.'); + */ +Mocha.prototype.fgrep = function(str) { + if (!str) { + return this; + } + return this.grep(new RegExp(escapeRe(str))); +}; + +/** + * @summary + * Sets `grep` filter used to select specific tests for execution. + * + * @description + * If `re` is a regexp-like string, it will be converted to regexp. + * The regexp is tested against the full title of each test (i.e., the + * name of the test preceded by titles of each its ancestral suites). + * As such, using an <em>exact-match</em> fixed pattern against the + * test name itself will not yield any matches. + * <br> + * <strong>Previous filter value will be overwritten on each call!</strong> + * + * @public + * @see {@link https://mochajs.org/#-g---grep-pattern|CLI option} + * @see {@link Mocha#fgrep} + * @see {@link Mocha#invert} + * @param {RegExp|String} re - Regular expression used to select tests. + * @return {Mocha} this + * @chainable + * @example + * + * // Select tests whose full title contains `"match"`, ignoring case + * mocha.grep(/match/i); + * @example + * + * // Same as above but with regexp-like string argument + * mocha.grep('/match/i'); + * @example + * + * // ## Anti-example + * // Given embedded test `it('only-this-test')`... + * mocha.grep('/^only-this-test$/'); // NO! Use `.only()` to do this! + */ +Mocha.prototype.grep = function(re) { + if (utils.isString(re)) { + // extract args if it's regex-like, i.e: [string, pattern, flag] + var arg = re.match(/^\/(.*)\/(g|i|)$|.*/); + this.options.grep = new RegExp(arg[1] || arg[0], arg[2]); + } else { + this.options.grep = re; + } + return this; +}; + +/** + * Inverts `grep` matches. + * + * @public + * @see {@link Mocha#grep} + * @return {Mocha} this + * @chainable + * @example + * + * // Select tests whose full title does *not* contain `"match"`, ignoring case + * mocha.grep(/match/i).invert(); */ Mocha.prototype.invert = function() { this.options.invert = true; @@ -1412,24 +1843,31 @@ }; /** - * Ignore global leaks. + * Enables or disables ignoring global leaks. * - * @param {Boolean} ignore - * @return {Mocha} - * @api public - * @param {boolean} ignore - * @return {Mocha} + * @public + * @see {@link Mocha#checkLeaks} + * @param {boolean} ignoreLeaks - Whether to ignore global leaks. + * @return {Mocha} this + * @chainable + * @example + * + * // Ignore global leaks + * mocha.ignoreLeaks(true); */ -Mocha.prototype.ignoreLeaks = function(ignore) { - this.options.ignoreLeaks = Boolean(ignore); +Mocha.prototype.ignoreLeaks = function(ignoreLeaks) { + this.options.ignoreLeaks = Boolean(ignoreLeaks); return this; }; /** - * Enable global leak checking. + * Enables checking for global variables leaked while running tests. * - * @return {Mocha} - * @api public + * @public + * @see {@link https://mochajs.org/#--check-leaks|CLI option} + * @see {@link Mocha#ignoreLeaks} + * @return {Mocha} this + * @chainable */ Mocha.prototype.checkLeaks = function() { this.options.ignoreLeaks = false; @@ -1437,10 +1875,11 @@ }; /** - * Display long stack-trace on failing + * Displays full stack trace upon test failure. * - * @return {Mocha} - * @api public + * @public + * @return {Mocha} this + * @chainable */ Mocha.prototype.fullTrace = function() { this.options.fullStackTrace = true; @@ -1448,38 +1887,77 @@ }; /** - * Enable growl support. + * Enables desktop notification support if prerequisite software installed. * - * @return {Mocha} - * @api public + * @public + * @see {@link Mocha#isGrowlCapable} + * @see {@link Mocha#_growl} + * @return {Mocha} this + * @chainable */ Mocha.prototype.growl = function() { - this.options.growl = true; + this.options.growl = this.isGrowlCapable(); + if (!this.options.growl) { + var detail = process.browser + ? 'notification support not available in this browser...' + : 'notification support prerequisites not installed...'; + console.error(detail + ' cannot enable!'); + } return this; }; /** - * Ignore `globals` array or string. + * @summary + * Determines if Growl support seems likely. * - * @param {Array|String} globals - * @return {Mocha} - * @api public - * @param {Array|string} globals - * @return {Mocha} + * @description + * <strong>Not available when run in browser.</strong> + * + * @private + * @see {@link Growl#isCapable} + * @see {@link Mocha#growl} + * @return {boolean} whether Growl support can be expected + */ +Mocha.prototype.isGrowlCapable = growl.isCapable; + +/** + * Implements desktop notifications using a pseudo-reporter. + * + * @private + * @see {@link Mocha#growl} + * @see {@link Growl#notify} + * @param {Runner} runner - Runner instance. + */ +Mocha.prototype._growl = growl.notify; + +/** + * Specifies whitelist of variable names to be expected in global scope. + * + * @public + * @see {@link https://mochajs.org/#--globals-names|CLI option} + * @see {@link Mocha#checkLeaks} + * @param {String[]|String} globals - Accepted global variable name(s). + * @return {Mocha} this + * @chainable + * @example + * + * // Specify variables to be expected in global scope + * mocha.globals(['jQuery', 'MyLib']); */ Mocha.prototype.globals = function(globals) { - this.options.globals = (this.options.globals || []).concat(globals); + this.options.globals = (this.options.globals || []) + .concat(globals) + .filter(Boolean); return this; }; /** - * Emit color output. + * Enables or disables TTY color output by screen-oriented reporters. * - * @param {Boolean} colors - * @return {Mocha} - * @api public - * @param {boolean} colors - * @return {Mocha} + * @public + * @param {boolean} colors - Whether to enable color output. + * @return {Mocha} this + * @chainable */ Mocha.prototype.useColors = function(colors) { if (colors !== undefined) { @@ -1489,13 +1967,13 @@ }; /** - * Use inline diffs rather than +/-. + * Determines if reporter should use inline diffs (rather than +/-) + * in test failure output. * - * @param {Boolean} inlineDiffs - * @return {Mocha} - * @api public - * @param {boolean} inlineDiffs - * @return {Mocha} + * @public + * @param {boolean} inlineDiffs - Whether to use inline diffs. + * @return {Mocha} this + * @chainable */ Mocha.prototype.useInlineDiffs = function(inlineDiffs) { this.options.useInlineDiffs = inlineDiffs !== undefined && inlineDiffs; @@ -1503,25 +1981,60 @@ }; /** - * Set the timeout in milliseconds. + * Determines if reporter should include diffs in test failure output. * - * @param {Number} timeout - * @return {Mocha} - * @api public - * @param {number} timeout - * @return {Mocha} + * @public + * @param {boolean} hideDiff - Whether to hide diffs. + * @return {Mocha} this + * @chainable */ -Mocha.prototype.timeout = function(timeout) { - this.suite.timeout(timeout); +Mocha.prototype.hideDiff = function(hideDiff) { + this.options.hideDiff = hideDiff !== undefined && hideDiff; return this; }; /** - * Set the number of times to retry failed tests. + * @summary + * Sets timeout threshold value. * - * @param {Number} retry times - * @return {Mocha} - * @api public + * @description + * A string argument can use shorthand (such as "2s") and will be converted. + * If the value is `0`, timeouts will be disabled. + * + * @public + * @see {@link https://mochajs.org/#-t---timeout-ms|CLI option} + * @see {@link https://mochajs.org/#--no-timeouts|CLI option} + * @see {@link https://mochajs.org/#timeouts|Timeouts} + * @see {@link Mocha#enableTimeouts} + * @param {number|string} msecs - Timeout threshold value. + * @return {Mocha} this + * @chainable + * @example + * + * // Sets timeout to one second + * mocha.timeout(1000); + * @example + * + * // Same as above but using string argument + * mocha.timeout('1s'); + */ +Mocha.prototype.timeout = function(msecs) { + this.suite.timeout(msecs); + return this; +}; + +/** + * Sets the number of times to retry failed tests. + * + * @public + * @see {@link https://mochajs.org/#retry-tests|Retry Tests} + * @param {number} retry - Number of times to retry failed tests. + * @return {Mocha} this + * @chainable + * @example + * + * // Allow any failed test to retry one more time + * mocha.retries(1); */ Mocha.prototype.retries = function(n) { this.suite.retries(n); @@ -1529,38 +2042,50 @@ }; /** - * Set slowness threshold in milliseconds. + * Sets slowness threshold value. * - * @param {Number} slow - * @return {Mocha} - * @api public - * @param {number} slow - * @return {Mocha} + * @public + * @see {@link https://mochajs.org/#-s---slow-ms|CLI option} + * @param {number} msecs - Slowness threshold value. + * @return {Mocha} this + * @chainable + * @example + * + * // Sets "slow" threshold to half a second + * mocha.slow(500); + * @example + * + * // Same as above but using string argument + * mocha.slow('0.5s'); */ -Mocha.prototype.slow = function(slow) { - this.suite.slow(slow); +Mocha.prototype.slow = function(msecs) { + this.suite.slow(msecs); return this; }; /** - * Enable timeouts. + * Enables or disables timeouts. * - * @param {Boolean} enabled - * @return {Mocha} - * @api public - * @param {boolean} enabled - * @return {Mocha} + * @public + * @see {@link https://mochajs.org/#-t---timeout-ms|CLI option} + * @see {@link https://mochajs.org/#--no-timeouts|CLI option} + * @param {boolean} enableTimeouts - Whether to enable timeouts. + * @return {Mocha} this + * @chainable */ -Mocha.prototype.enableTimeouts = function(enabled) { - this.suite.enableTimeouts(arguments.length && enabled !== undefined ? enabled : true); +Mocha.prototype.enableTimeouts = function(enableTimeouts) { + this.suite.enableTimeouts( + arguments.length && enableTimeouts !== undefined ? enableTimeouts : true + ); return this; }; /** - * Makes all tests async (accepting a callback) + * Forces all tests to either accept a `done` callback or return a promise. * - * @return {Mocha} - * @api public + * @public + * @return {Mocha} this + * @chainable */ Mocha.prototype.asyncOnly = function() { this.options.asyncOnly = true; @@ -1568,9 +2093,11 @@ }; /** - * Disable syntax highlighting (in browser). + * Disables syntax highlighting (in browser). * - * @api public + * @public + * @return {Mocha} this + * @chainable */ Mocha.prototype.noHighlighting = function() { this.options.noHighlighting = true; @@ -1578,10 +2105,11 @@ }; /** - * Enable uncaught errors to propagate (in browser). + * Enables uncaught errors to propagate (in browser). * - * @return {Mocha} - * @api public + * @public + * @return {Mocha} this + * @chainable */ Mocha.prototype.allowUncaught = function() { this.options.allowUncaught = true; @@ -1589,8 +2117,16 @@ }; /** - * Delay root suite execution. - * @returns {Mocha} + * @summary + * Delays root suite execution. + * + * @description + * Used to perform asynch operations before any suites are run. + * + * @public + * @see {@link https://mochajs.org/#delayed-root-suite|delayed root suite} + * @returns {Mocha} this + * @chainable */ Mocha.prototype.delay = function delay() { this.options.delay = true; @@ -1598,11 +2134,64 @@ }; /** - * Run tests and invoke `fn()` when complete. + * Causes tests marked `only` to fail the suite. * - * @api public - * @param {Function} fn - * @return {Runner} + * @public + * @returns {Mocha} this + * @chainable + */ +Mocha.prototype.forbidOnly = function() { + this.options.forbidOnly = true; + return this; +}; + +/** + * Causes pending tests and tests marked `skip` to fail the suite. + * + * @public + * @returns {Mocha} this + * @chainable + */ +Mocha.prototype.forbidPending = function() { + this.options.forbidPending = true; + return this; +}; + +/** + * Mocha version as specified by "package.json". + * + * @name Mocha#version + * @type string + * @readonly + */ +Object.defineProperty(Mocha.prototype, 'version', { + value: require('../package.json').version, + configurable: false, + enumerable: true, + writable: false +}); + +/** + * Callback to be invoked when test execution is complete. + * + * @callback DoneCB + * @param {number} failures - Number of failures that occurred. + */ + +/** + * Runs root suite and invokes `fn()` when complete. + * + * @description + * To run tests multiple times (or to run tests in files that are + * already in the `require` cache), make sure to clear them from + * the cache first! + * + * @public + * @see {@link Mocha#loadFiles} + * @see {@link Mocha#unloadFiles} + * @see {@link Runner#run} + * @param {DoneCB} [fn] - Callback invoked when test execution completed. + * @return {Runner} runner instance */ Mocha.prototype.run = function(fn) { if (this.files.length) { @@ -1612,11 +2201,14 @@ var options = this.options; options.files = this.files; var runner = new exports.Runner(suite, options.delay); + createStatsCollector(runner); var reporter = new this._reporter(runner, options); runner.ignoreLeaks = options.ignoreLeaks !== false; runner.fullStackTrace = options.fullStackTrace; runner.asyncOnly = options.asyncOnly; runner.allowUncaught = options.allowUncaught; + runner.forbidOnly = options.forbidOnly; + runner.forbidPending = options.forbidPending; if (options.grep) { runner.grep(options.grep, options.invert); } @@ -1624,160 +2216,41 @@ runner.globals(options.globals); } if (options.growl) { - this._growl(runner, reporter); + this._growl(runner); } if (options.useColors !== undefined) { exports.reporters.Base.useColors = options.useColors; } exports.reporters.Base.inlineDiffs = options.useInlineDiffs; + exports.reporters.Base.hideDiff = options.hideDiff; function done(failures) { + fn = fn || utils.noop; if (reporter.done) { reporter.done(failures, fn); } else { - fn && fn(failures); + fn(failures); } } return runner.run(done); }; -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},"/lib") -},{"./context":6,"./hook":7,"./interfaces":11,"./reporters":22,"./runnable":35,"./runner":36,"./suite":37,"./test":38,"./utils":39,"_process":58,"escape-string-regexp":49,"growl":51,"path":43}],15:[function(require,module,exports){ -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @api public - * @param {string|number} val - * @param {Object} options - * @return {string|number} - */ -module.exports = function(val, options) { - options = options || {}; - if (typeof val === 'string') { - return parse(val); - } - // https://github.com/mochajs/mocha/pull/1035 - return options['long'] ? longFormat(val) : shortFormat(val); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @api private - * @param {string} str - * @return {number} - */ -function parse(str) { - var match = (/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i).exec(str); - if (!match) { - return; - } - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 's': - return n * s; - case 'ms': - return n; - default: - // No default case - } -} - -/** - * Short format for `ms`. - * - * @api private - * @param {number} ms - * @return {string} - */ -function shortFormat(ms) { - if (ms >= d) { - return Math.round(ms / d) + 'd'; - } - if (ms >= h) { - return Math.round(ms / h) + 'h'; - } - if (ms >= m) { - return Math.round(ms / m) + 'm'; - } - if (ms >= s) { - return Math.round(ms / s) + 's'; - } - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @api private - * @param {number} ms - * @return {string} - */ -function longFormat(ms) { - return plural(ms, d, 'day') - || plural(ms, h, 'hour') - || plural(ms, m, 'minute') - || plural(ms, s, 'second') - || ms + ' ms'; -} - -/** - * Pluralization helper. - * - * @api private - * @param {number} ms - * @param {number} n - * @param {string} name - */ -function plural(ms, n, name) { - if (ms < n) { - return; - } - if (ms < n * 1.5) { - return Math.floor(ms / n) + ' ' + name; - } - return Math.ceil(ms / n) + ' ' + name + 's'; +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"../package.json":90,"./context":5,"./errors":6,"./growl":2,"./hook":7,"./interfaces":11,"./mocharc.json":15,"./reporters":21,"./runnable":33,"./runner":34,"./stats-collector":35,"./suite":36,"./test":37,"./utils":38,"_process":69,"escape-string-regexp":49,"path":42}],15:[function(require,module,exports){ +module.exports={ + "diff": true, + "extension": ["js"], + "opts": "./test/mocha.opts", + "package": "./package.json", + "reporter": "spec", + "slow": 75, + "timeout": 2000, + "ui": "bdd" } },{}],16:[function(require,module,exports){ - -/** - * Expose `Pending`. - */ +'use strict'; module.exports = Pending; @@ -1791,16 +2264,23 @@ } },{}],17:[function(require,module,exports){ -(function (process,global){ +(function (process){ +'use strict'; +/** + * @module Base + */ /** * Module dependencies. */ var tty = require('tty'); var diff = require('diff'); -var ms = require('../ms'); +var milliseconds = require('ms'); var utils = require('../utils'); var supportsColor = process.browser ? null : require('supports-color'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; /** * Expose `Base`. @@ -1809,19 +2289,6 @@ exports = module.exports = Base; /** - * Save timer references to avoid Sinon interfering. - * See: https://github.com/mochajs/mocha/issues/237 - */ - -/* eslint-disable no-unused-vars, no-native-reassign */ -var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ - -/** * Check if both stdio streams are associated with a tty. */ @@ -1831,7 +2298,9 @@ * Enable coloring by default, except in the browser interface. */ -exports.useColors = !process.browser && (supportsColor || (process.env.MOCHA_COLORS !== undefined)); +exports.useColors = + !process.browser && + (supportsColor.stdout || process.env.MOCHA_COLORS !== undefined); /** * Inline diffs instead of +/- @@ -1872,7 +2341,9 @@ exports.symbols = { ok: '✓', err: '✖', - dot: '․' + dot: '․', + comma: ',', + bang: '!' }; // With node.js on Windows: use symbols available in terminal default fonts @@ -1888,17 +2359,17 @@ * as well as user-defined color * schemes. * + * @private * @param {string} type * @param {string} str * @return {string} - * @api private */ -var color = exports.color = function(type, str) { +var color = (exports.color = function(type, str) { if (!exports.useColors) { return String(str); } return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; -}; +}); /** * Expose term window size, with some defaults for when stderr is not a tty. @@ -1910,8 +2381,8 @@ if (isatty) { exports.window.width = process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1]; + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1]; } /** @@ -1945,20 +2416,56 @@ } }; -/** - * Outut the given `failures` as a list. - * - * @param {Array} failures - * @api public - */ +function showDiff(err) { + return ( + err && + err.showDiff !== false && + sameType(err.actual, err.expected) && + err.expected !== undefined + ); +} +function stringifyDiffObjs(err) { + if (!utils.isString(err.actual) || !utils.isString(err.expected)) { + err.actual = utils.stringify(err.actual); + err.expected = utils.stringify(err.expected); + } +} + +/** + * Returns a diff between 2 strings with coloured ANSI output. + * + * @description + * The diff will be either inline or unified dependent on the value + * of `Base.inlineDiff`. + * + * @param {string} actual + * @param {string} expected + * @return {string} Diff + */ +var generateDiff = (exports.generateDiff = function(actual, expected) { + return exports.inlineDiffs + ? inlineDiff(actual, expected) + : unifiedDiff(actual, expected); +}); + +/** + * Outputs the given `failures` as a list. + * + * @public + * @memberof Mocha.reporters.Base + * @variation 1 + * @param {Object[]} failures - Each is Test instance with corresponding + * Error property + */ exports.list = function(failures) { console.log(); failures.forEach(function(test, i) { // format - var fmt = color('error title', ' %s) %s:\n') - + color('error message', ' %s') - + color('error stack', '\n%s\n'); + var fmt = + color('error title', ' %s) %s:\n') + + color('error message', ' %s') + + color('error stack', '\n%s\n'); // msg var msg; @@ -1972,10 +2479,7 @@ message = ''; } var stack = err.stack || message; - var index = stack.indexOf(message); - var actual = err.actual; - var expected = err.expected; - var escape = true; + var index = message ? stack.indexOf(message) : -1; if (index === -1) { msg = message; @@ -1991,71 +2495,58 @@ msg = 'Uncaught ' + msg; } // explicitly show diff - if (err.showDiff !== false && sameType(actual, expected) && expected !== undefined) { - escape = false; - if (!(utils.isString(actual) && utils.isString(expected))) { - err.actual = actual = utils.stringify(actual); - err.expected = expected = utils.stringify(expected); - } - - fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); + if (!exports.hideDiff && showDiff(err)) { + stringifyDiffObjs(err); + fmt = + color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); var match = message.match(/^([^:]+): expected/); msg = '\n ' + color('error message', match ? match[1] : msg); - if (exports.inlineDiffs) { - msg += inlineDiff(err, escape); - } else { - msg += unifiedDiff(err, escape); - } + msg += generateDiff(err.actual, err.expected); } // indent stack trace stack = stack.replace(/^/gm, ' '); - console.log(fmt, (i + 1), test.fullTitle(), msg, stack); + // indented test title + var testTitle = ''; + test.titlePath().forEach(function(str, index) { + if (index !== 0) { + testTitle += '\n '; + } + for (var i = 0; i < index; i++) { + testTitle += ' '; + } + testTitle += str; + }); + + console.log(fmt, i + 1, testTitle, msg, stack); }); }; /** - * Initialize a new `Base` reporter. + * Constructs a new `Base` reporter instance. * - * All other reporters generally - * inherit from this reporter, providing - * stats such as test duration, number - * of tests passed / failed etc. + * @description + * All other reporters generally inherit from this reporter. * - * @param {Runner} runner - * @api public + * @public + * @class + * @memberof Mocha.reporters + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ - -function Base(runner) { - var stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 }; - var failures = this.failures = []; +function Base(runner, options) { + var failures = (this.failures = []); if (!runner) { - return; + throw new TypeError('Missing runner argument'); } + this.options = options || {}; this.runner = runner; + this.stats = runner.stats; // assigned so Reporters keep a closer reference - runner.stats = stats; - - runner.on('start', function() { - stats.start = new Date(); - }); - - runner.on('suite', function(suite) { - stats.suites = stats.suites || 0; - suite.root || stats.suites++; - }); - - runner.on('test end', function() { - stats.tests = stats.tests || 0; - stats.tests++; - }); - - runner.on('pass', function(test) { - stats.passes = stats.passes || 0; - + runner.on(EVENT_TEST_PASS, function(test) { if (test.duration > test.slow()) { test.speed = 'slow'; } else if (test.duration > test.slow() / 2) { @@ -2063,32 +2554,22 @@ } else { test.speed = 'fast'; } - - stats.passes++; }); - runner.on('fail', function(test, err) { - stats.failures = stats.failures || 0; - stats.failures++; + runner.on(EVENT_TEST_FAIL, function(test, err) { + if (showDiff(err)) { + stringifyDiffObjs(err); + } test.err = err; failures.push(test); }); - - runner.on('end', function() { - stats.end = new Date(); - stats.duration = new Date() - stats.start; - }); - - runner.on('pending', function() { - stats.pending++; - }); } /** - * Output common epilogue used by many of - * the bundled reporters. + * Outputs common epilogue used by many of the bundled reporters. * - * @api public + * @public + * @memberof Mocha.reporters.Base */ Base.prototype.epilogue = function() { var stats = this.stats; @@ -2097,18 +2578,16 @@ console.log(); // passes - fmt = color('bright pass', ' ') - + color('green', ' %d passing') - + color('light', ' (%s)'); + fmt = + color('bright pass', ' ') + + color('green', ' %d passing') + + color('light', ' (%s)'); - console.log(fmt, - stats.passes || 0, - ms(stats.duration)); + console.log(fmt, stats.passes || 0, milliseconds(stats.duration)); // pending if (stats.pending) { - fmt = color('pending', ' ') - + color('pending', ' %d pending'); + fmt = color('pending', ' ') + color('pending', ' %d pending'); console.log(fmt, stats.pending); } @@ -2127,9 +2606,9 @@ }; /** - * Pad the given `str` to `len`. + * Pads the given `str` to `len`. * - * @api private + * @private * @param {string} str * @param {string} len * @return {string} @@ -2140,33 +2619,36 @@ } /** - * Returns an inline diff between 2 strings with coloured ANSI output + * Returns inline diff between 2 strings with coloured ANSI output. * - * @api private - * @param {Error} err with actual/expected - * @param {boolean} escape + * @private + * @param {String} actual + * @param {String} expected * @return {string} Diff */ -function inlineDiff(err, escape) { - var msg = errorDiff(err, 'WordsWithSpace', escape); +function inlineDiff(actual, expected) { + var msg = errorDiff(actual, expected); // linenos var lines = msg.split('\n'); if (lines.length > 4) { var width = String(lines.length).length; - msg = lines.map(function(str, i) { - return pad(++i, width) + ' |' + ' ' + str; - }).join('\n'); + msg = lines + .map(function(str, i) { + return pad(++i, width) + ' |' + ' ' + str; + }) + .join('\n'); } // legend - msg = '\n' - + color('diff removed', 'actual') - + ' ' - + color('diff added', 'expected') - + '\n\n' - + msg - + '\n'; + msg = + '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; // indent msg = msg.replace(/^/gm, ' '); @@ -2174,27 +2656,24 @@ } /** - * Returns a unified diff between two strings. + * Returns unified diff between two strings with coloured ANSI output. * - * @api private - * @param {Error} err with actual/expected - * @param {boolean} escape + * @private + * @param {String} actual + * @param {String} expected * @return {string} The diff. */ -function unifiedDiff(err, escape) { +function unifiedDiff(actual, expected) { var indent = ' '; function cleanUp(line) { - if (escape) { - line = escapeInvisibles(line); - } if (line[0] === '+') { return indent + colorLines('diff added', line); } if (line[0] === '-') { return indent + colorLines('diff removed', line); } - if (line.match(/\@\@/)) { - return null; + if (line.match(/@@/)) { + return '--'; } if (line.match(/\\ No newline/)) { return null; @@ -2204,63 +2683,59 @@ function notBlank(line) { return typeof line !== 'undefined' && line !== null; } - var msg = diff.createPatch('string', err.actual, err.expected); - var lines = msg.split('\n').splice(4); - return '\n ' - + colorLines('diff added', '+ expected') + ' ' - + colorLines('diff removed', '- actual') - + '\n\n' - + lines.map(cleanUp).filter(notBlank).join('\n'); + var msg = diff.createPatch('string', actual, expected); + var lines = msg.split('\n').splice(5); + return ( + '\n ' + + colorLines('diff added', '+ expected') + + ' ' + + colorLines('diff removed', '- actual') + + '\n\n' + + lines + .map(cleanUp) + .filter(notBlank) + .join('\n') + ); } /** - * Return a character diff for `err`. + * Returns character diff for `err`. * - * @api private - * @param {Error} err - * @param {string} type - * @param {boolean} escape - * @return {string} + * @private + * @param {String} actual + * @param {String} expected + * @return {string} the diff */ -function errorDiff(err, type, escape) { - var actual = escape ? escapeInvisibles(err.actual) : err.actual; - var expected = escape ? escapeInvisibles(err.expected) : err.expected; - return diff['diff' + type](actual, expected).map(function(str) { - if (str.added) { - return colorLines('diff added', str.value); - } - if (str.removed) { - return colorLines('diff removed', str.value); - } - return str.value; - }).join(''); +function errorDiff(actual, expected) { + return diff + .diffWordsWithSpace(actual, expected) + .map(function(str) { + if (str.added) { + return colorLines('diff added', str.value); + } + if (str.removed) { + return colorLines('diff removed', str.value); + } + return str.value; + }) + .join(''); } /** - * Returns a string with all invisible characters in plain text + * Colors lines for `str`, using the color `name`. * - * @api private - * @param {string} line - * @return {string} - */ -function escapeInvisibles(line) { - return line.replace(/\t/g, '<tab>') - .replace(/\r/g, '<CR>') - .replace(/\n/g, '<LF>\n'); -} - -/** - * Color lines for `str`, using the color `name`. - * - * @api private + * @private * @param {string} name * @param {string} str * @return {string} */ function colorLines(name, str) { - return str.split('\n').map(function(str) { - return color(name, str); - }).join('\n'); + return str + .split('\n') + .map(function(str) { + return color(name, str); + }) + .join('\n'); } /** @@ -2269,9 +2744,9 @@ var objToString = Object.prototype.toString; /** - * Check that a / b have the same type. + * Checks that a / b have the same type. * - * @api private + * @private * @param {Object} a * @param {Object} b * @return {boolean} @@ -2280,14 +2755,25 @@ return objToString.call(a) === objToString.call(b); } -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../ms":15,"../utils":39,"_process":58,"diff":48,"supports-color":43,"tty":5}],18:[function(require,module,exports){ +Base.abstract = true; + +}).call(this,require('_process')) +},{"../runner":34,"../utils":38,"_process":69,"diff":48,"ms":60,"supports-color":42,"tty":4}],18:[function(require,module,exports){ +'use strict'; +/** + * @module Doc + */ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_SUITE_END = constants.EVENT_SUITE_END; /** * Expose `Doc`. @@ -2296,13 +2782,17 @@ exports = module.exports = Doc; /** - * Initialize a new `Doc` reporter. + * Constructs a new `Doc` reporter instance. * - * @param {Runner} runner - * @api public + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Doc(runner) { - Base.call(this, runner); +function Doc(runner, options) { + Base.call(this, runner, options); var indents = 2; @@ -2310,7 +2800,7 @@ return Array(indents).join(' '); } - runner.on('suite', function(suite) { + runner.on(EVENT_SUITE_BEGIN, function(suite) { if (suite.root) { return; } @@ -2321,7 +2811,7 @@ console.log('%s<dl>', indent()); }); - runner.on('suite end', function(suite) { + runner.on(EVENT_SUITE_END, function(suite) { if (suite.root) { return; } @@ -2331,29 +2821,48 @@ --indents; }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { console.log('%s <dt>%s</dt>', indent(), utils.escape(test.title)); var code = utils.escape(utils.clean(test.body)); console.log('%s <dd><pre><code>%s</code></pre></dd>', indent(), code); }); - runner.on('fail', function(test, err) { - console.log('%s <dt class="error">%s</dt>', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.body)); - console.log('%s <dd class="error"><pre><code>%s</code></pre></dd>', indent(), code); + runner.on(EVENT_TEST_FAIL, function(test, err) { + console.log( + '%s <dt class="error">%s</dt>', + indent(), + utils.escape(test.title) + ); + var code = utils.escape(utils.clean(test.body)); + console.log( + '%s <dd class="error"><pre><code>%s</code></pre></dd>', + indent(), + code + ); console.log('%s <dd class="error">%s</dd>', indent(), utils.escape(err)); }); } -},{"../utils":39,"./base":17}],19:[function(require,module,exports){ +Doc.description = 'HTML documentation'; + +},{"../runner":34,"../utils":38,"./base":17}],19:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Dot + */ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; -var color = Base.color; +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var EVENT_RUN_END = constants.EVENT_RUN_END; /** * Expose `Dot`. @@ -2362,48 +2871,52 @@ exports = module.exports = Dot; /** - * Initialize a new `Dot` matrix test reporter. + * Constructs a new `Dot` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Dot(runner) { - Base.call(this, runner); +function Dot(runner, options) { + Base.call(this, runner, options); var self = this; - var width = Base.window.width * .75 | 0; + var width = (Base.window.width * 0.75) | 0; var n = -1; - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { process.stdout.write('\n'); }); - runner.on('pending', function() { + runner.on(EVENT_TEST_PENDING, function() { if (++n % width === 0) { process.stdout.write('\n '); } - process.stdout.write(color('pending', Base.symbols.dot)); + process.stdout.write(Base.color('pending', Base.symbols.comma)); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { if (++n % width === 0) { process.stdout.write('\n '); } if (test.speed === 'slow') { - process.stdout.write(color('bright yellow', Base.symbols.dot)); + process.stdout.write(Base.color('bright yellow', Base.symbols.dot)); } else { - process.stdout.write(color(test.speed, Base.symbols.dot)); + process.stdout.write(Base.color(test.speed, Base.symbols.dot)); } }); - runner.on('fail', function() { + runner.on(EVENT_TEST_FAIL, function() { if (++n % width === 0) { process.stdout.write('\n '); } - process.stdout.write(color('fail', Base.symbols.dot)); + process.stdout.write(Base.color('fail', Base.symbols.bang)); }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { console.log(); self.epilogue(); }); @@ -2414,71 +2927,17 @@ */ inherits(Dot, Base); +Dot.description = 'dot matrix representation'; + }).call(this,require('_process')) -},{"../utils":39,"./base":17,"_process":58}],20:[function(require,module,exports){ -(function (process,__dirname){ -/** - * Module dependencies. - */ - -var JSONCov = require('./json-cov'); -var readFileSync = require('fs').readFileSync; -var join = require('path').join; - -/** - * Expose `HTMLCov`. - */ - -exports = module.exports = HTMLCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @api public - * @param {Runner} runner - */ -function HTMLCov(runner) { - var jade = require('jade'); - var file = join(__dirname, '/templates/coverage.jade'); - var str = readFileSync(file, 'utf8'); - var fn = jade.compile(str, { filename: file }); - var self = this; - - JSONCov.call(this, runner, false); - - runner.on('end', function() { - process.stdout.write(fn({ - cov: self.cov, - coverageClass: coverageClass - })); - }); -} - -/** - * Return coverage class for a given coverage percentage. - * - * @api private - * @param {number} coveragePctg - * @return {string} - */ -function coverageClass(coveragePctg) { - if (coveragePctg >= 75) { - return 'high'; - } - if (coveragePctg >= 50) { - return 'medium'; - } - if (coveragePctg >= 25) { - return 'low'; - } - return 'terrible'; -} - -}).call(this,require('_process'),"/lib/reporters") -},{"./json-cov":23,"_process":58,"fs":43,"jade":43,"path":43}],21:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],20:[function(require,module,exports){ (function (global){ -/* eslint-env browser */ +'use strict'; +/* eslint-env browser */ +/** + * @module HTML + */ /** * Module dependencies. */ @@ -2487,19 +2946,19 @@ var utils = require('../utils'); var Progress = require('../browser/progress'); var escapeRe = require('escape-string-regexp'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_SUITE_END = constants.EVENT_SUITE_END; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; var escape = utils.escape; /** * Save timer references to avoid Sinon interfering (see GH-237). */ -/* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ /** * Expose `HTML`. @@ -2511,21 +2970,28 @@ * Stats template. */ -var statsTemplate = '<ul id="mocha-stats">' - + '<li class="progress"><canvas width="40" height="40"></canvas></li>' - + '<li class="passes"><a href="javascript:void(0);">passes:</a> <em>0</em></li>' - + '<li class="failures"><a href="javascript:void(0);">failures:</a> <em>0</em></li>' - + '<li class="duration">duration: <em>0</em>s</li>' - + '</ul>'; +var statsTemplate = + '<ul id="mocha-stats">' + + '<li class="progress"><canvas width="40" height="40"></canvas></li>' + + '<li class="passes"><a href="javascript:void(0);">passes:</a> <em>0</em></li>' + + '<li class="failures"><a href="javascript:void(0);">failures:</a> <em>0</em></li>' + + '<li class="duration">duration: <em>0</em>s</li>' + + '</ul>'; + +var playIcon = '‣'; /** - * Initialize a new `HTML` reporter. + * Constructs a new `HTML` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function HTML(runner) { - Base.call(this, runner); +function HTML(runner, options) { + Base.call(this, runner, options); var self = this; var stats = this.stats; @@ -2562,7 +3028,7 @@ on(passesLink, 'click', function(evt) { evt.preventDefault(); unhide(); - var name = (/pass/).test(report.className) ? '' : ' pass'; + var name = /pass/.test(report.className) ? '' : ' pass'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test pass'); @@ -2573,7 +3039,7 @@ on(failuresLink, 'click', function(evt) { evt.preventDefault(); unhide(); - var name = (/fail/).test(report.className) ? '' : ' fail'; + var name = /fail/.test(report.className) ? '' : ' fail'; report.className = report.className.replace(/fail|pass/g, '') + name; if (report.className.trim()) { hideSuitesWithout('test fail'); @@ -2587,14 +3053,18 @@ progress.size(40); } - runner.on('suite', function(suite) { + runner.on(EVENT_SUITE_BEGIN, function(suite) { if (suite.root) { return; } // suite var url = self.suiteURL(suite); - var el = fragment('<li class="suite"><h1><a href="%s">%s</a></h1></li>', url, escape(suite.title)); + var el = fragment( + '<li class="suite"><h1><a href="%s">%s</a></h1></li>', + url, + escape(suite.title) + ); // container stack[0].appendChild(el); @@ -2602,26 +3072,35 @@ el.appendChild(stack[0]); }); - runner.on('suite end', function(suite) { + runner.on(EVENT_SUITE_END, function(suite) { if (suite.root) { + updateStats(); return; } stack.shift(); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { var url = self.testURL(test); - var markup = '<li class="test pass %e"><h2>%e<span class="duration">%ems</span> ' - + '<a href="%s" class="replay">‣</a></h2></li>'; + var markup = + '<li class="test pass %e"><h2>%e<span class="duration">%ems</span> ' + + '<a href="%s" class="replay">' + + playIcon + + '</a></h2></li>'; var el = fragment(markup, test.speed, test.title, test.duration, url); self.addCodeToggle(el, test.body); appendToStack(el); updateStats(); }); - runner.on('fail', function(test) { - var el = fragment('<li class="test fail"><h2>%e <a href="%e" class="replay">‣</a></h2></li>', - test.title, self.testURL(test)); + runner.on(EVENT_TEST_FAIL, function(test) { + var el = fragment( + '<li class="test fail"><h2>%e <a href="%e" class="replay">' + + playIcon + + '</a></h2></li>', + test.title, + self.testURL(test) + ); var stackString; // Note: Includes leading newline var message = test.err.toString(); @@ -2636,7 +3115,9 @@ if (indexOfMessage === -1) { stackString = test.err.stack; } else { - stackString = test.err.stack.substr(test.err.message.length + indexOfMessage); + stackString = test.err.stack.substr( + test.err.message.length + indexOfMessage + ); } } else if (test.err.sourceURL && test.err.line !== undefined) { // Safari doesn't give you a stack. Let's at least provide a source line. @@ -2646,12 +3127,21 @@ stackString = stackString || ''; if (test.err.htmlMessage && stackString) { - el.appendChild(fragment('<div class="html-error">%s\n<pre class="error">%e</pre></div>', - test.err.htmlMessage, stackString)); + el.appendChild( + fragment( + '<div class="html-error">%s\n<pre class="error">%e</pre></div>', + test.err.htmlMessage, + stackString + ) + ); } else if (test.err.htmlMessage) { - el.appendChild(fragment('<div class="html-error">%s</div>', test.err.htmlMessage)); + el.appendChild( + fragment('<div class="html-error">%s</div>', test.err.htmlMessage) + ); } else { - el.appendChild(fragment('<pre class="error">%e%e</pre>', message, stackString)); + el.appendChild( + fragment('<pre class="error">%e%e</pre>', message, stackString) + ); } self.addCodeToggle(el, test.body); @@ -2659,8 +3149,11 @@ updateStats(); }); - runner.on('pending', function(test) { - var el = fragment('<li class="test pass pending"><h2>%e</h2></li>', test.title); + runner.on(EVENT_TEST_PENDING, function(test) { + var el = fragment( + '<li class="test pass pending"><h2>%e</h2></li>', + test.title + ); appendToStack(el); updateStats(); }); @@ -2674,7 +3167,7 @@ function updateStats() { // TODO: add to stats - var percent = stats.tests / this.total * 100 | 0; + var percent = ((stats.tests / runner.total) * 100) | 0; if (progress) { progress.update(percent).draw(ctx); } @@ -2701,7 +3194,12 @@ search = search.replace(/[?&]grep=[^&\s]*/g, '').replace(/^&/, '?'); } - return window.location.pathname + (search ? search + '&' : '?') + 'grep=' + encodeURIComponent(escapeRe(s)); + return ( + window.location.pathname + + (search ? search + '&' : '?') + + 'grep=' + + encodeURIComponent(escapeRe(s)) + ); } /** @@ -2761,8 +3259,10 @@ div.innerHTML = html.replace(/%([se])/g, function(_, type) { switch (type) { - case 's': return String(args[i++]); - case 'e': return escape(args[i++]); + case 's': + return String(args[i++]); + case 'e': + return escape(args[i++]); // no default } }); @@ -2821,8 +3321,12 @@ } } +HTML.browserOnly = true; + }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../browser/progress":4,"../utils":39,"./base":17,"escape-string-regexp":49}],22:[function(require,module,exports){ +},{"../browser/progress":3,"../runner":34,"../utils":38,"./base":17,"escape-string-regexp":49}],21:[function(require,module,exports){ +'use strict'; + // Alias exports to a their normalized format Mocha#reporter to prevent a need // for dynamic (try/catch) requires, which Browserify doesn't handle. exports.Base = exports.base = require('./base'); @@ -2839,218 +3343,89 @@ exports.Markdown = exports.markdown = require('./markdown'); exports.Progress = exports.progress = require('./progress'); exports.Landing = exports.landing = require('./landing'); -exports.JSONCov = exports['json-cov'] = require('./json-cov'); -exports.HTMLCov = exports['html-cov'] = require('./html-cov'); exports.JSONStream = exports['json-stream'] = require('./json-stream'); -},{"./base":17,"./doc":18,"./dot":19,"./html":21,"./html-cov":20,"./json":25,"./json-cov":23,"./json-stream":24,"./landing":26,"./list":27,"./markdown":28,"./min":29,"./nyan":30,"./progress":31,"./spec":32,"./tap":33,"./xunit":34}],23:[function(require,module,exports){ -(function (process,global){ -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `JSONCov`. - */ - -exports = module.exports = JSONCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @api public - * @param {Runner} runner - * @param {boolean} output - */ -function JSONCov(runner, output) { - Base.call(this, runner); - - output = arguments.length === 1 || output; - var self = this; - var tests = []; - var failures = []; - var passes = []; - - runner.on('test end', function(test) { - tests.push(test); - }); - - runner.on('pass', function(test) { - passes.push(test); - }); - - runner.on('fail', function(test) { - failures.push(test); - }); - - runner.on('end', function() { - var cov = global._$jscoverage || {}; - var result = self.cov = map(cov); - result.stats = self.stats; - result.tests = tests.map(clean); - result.failures = failures.map(clean); - result.passes = passes.map(clean); - if (!output) { - return; - } - process.stdout.write(JSON.stringify(result, null, 2)); - }); -} - -/** - * Map jscoverage data to a JSON structure - * suitable for reporting. - * - * @api private - * @param {Object} cov - * @return {Object} - */ - -function map(cov) { - var ret = { - instrumentation: 'node-jscoverage', - sloc: 0, - hits: 0, - misses: 0, - coverage: 0, - files: [] - }; - - for (var filename in cov) { - if (Object.prototype.hasOwnProperty.call(cov, filename)) { - var data = coverage(filename, cov[filename]); - ret.files.push(data); - ret.hits += data.hits; - ret.misses += data.misses; - ret.sloc += data.sloc; - } - } - - ret.files.sort(function(a, b) { - return a.filename.localeCompare(b.filename); - }); - - if (ret.sloc > 0) { - ret.coverage = (ret.hits / ret.sloc) * 100; - } - - return ret; -} - -/** - * Map jscoverage data for a single source file - * to a JSON structure suitable for reporting. - * - * @api private - * @param {string} filename name of the source file - * @param {Object} data jscoverage coverage data - * @return {Object} - */ -function coverage(filename, data) { - var ret = { - filename: filename, - coverage: 0, - hits: 0, - misses: 0, - sloc: 0, - source: {} - }; - - data.source.forEach(function(line, num) { - num++; - - if (data[num] === 0) { - ret.misses++; - ret.sloc++; - } else if (data[num] !== undefined) { - ret.hits++; - ret.sloc++; - } - - ret.source[num] = { - source: line, - coverage: data[num] === undefined ? '' : data[num] - }; - }); - - ret.coverage = ret.hits / ret.sloc * 100; - - return ret; -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @api private - * @param {Object} test - * @return {Object} - */ -function clean(test) { - return { - duration: test.duration, - currentRetry: test.currentRetry(), - fullTitle: test.fullTitle(), - title: test.title - }; -} - -}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./base":17,"_process":58}],24:[function(require,module,exports){ +},{"./base":17,"./doc":18,"./dot":19,"./html":20,"./json":23,"./json-stream":22,"./landing":24,"./list":25,"./markdown":26,"./min":27,"./nyan":28,"./progress":29,"./spec":30,"./tap":31,"./xunit":32}],22:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module JSONStream + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; /** - * Expose `List`. + * Expose `JSONStream`. */ -exports = module.exports = List; +exports = module.exports = JSONStream; /** - * Initialize a new `List` test reporter. + * Constructs a new `JSONStream` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function List(runner) { - Base.call(this, runner); +function JSONStream(runner, options) { + Base.call(this, runner, options); var self = this; var total = runner.total; - runner.on('start', function() { - console.log(JSON.stringify(['start', { total: total }])); + runner.once(EVENT_RUN_BEGIN, function() { + writeEvent(['start', {total: total}]); }); - runner.on('pass', function(test) { - console.log(JSON.stringify(['pass', clean(test)])); + runner.on(EVENT_TEST_PASS, function(test) { + writeEvent(['pass', clean(test)]); }); - runner.on('fail', function(test, err) { + runner.on(EVENT_TEST_FAIL, function(test, err) { test = clean(test); test.err = err.message; test.stack = err.stack || null; - console.log(JSON.stringify(['fail', test])); + writeEvent(['fail', test]); }); - runner.on('end', function() { - process.stdout.write(JSON.stringify(['end', self.stats])); + runner.once(EVENT_RUN_END, function() { + writeEvent(['end', self.stats]); }); } /** - * Return a plain-object representation of `test` - * free of cyclic properties etc. + * Mocha event to be written to the output stream. + * @typedef {Array} JSONStream~MochaEvent + */ + +/** + * Writes Mocha event to reporter output stream. * - * @api private - * @param {Object} test - * @return {Object} + * @private + * @param {JSONStream~MochaEvent} event - Mocha event to be output. + */ +function writeEvent(event) { + process.stdout.write(JSON.stringify(event) + '\n'); +} + +/** + * Returns an object literal representation of `test` + * free of cyclic properties, etc. + * + * @private + * @param {Test} test - Instance used as data source. + * @return {Object} object containing pared-down test instance data */ function clean(test) { return { @@ -3061,14 +3436,26 @@ }; } +JSONStream.description = 'newline delimited JSON events'; + }).call(this,require('_process')) -},{"./base":17,"_process":58}],25:[function(require,module,exports){ +},{"../runner":34,"./base":17,"_process":69}],23:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module JSON + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_TEST_END = constants.EVENT_TEST_END; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; /** * Expose `JSON`. @@ -3077,13 +3464,17 @@ exports = module.exports = JSONReporter; /** - * Initialize a new `JSON` reporter. + * Constructs a new `JSON` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class JSON + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function JSONReporter(runner) { - Base.call(this, runner); +function JSONReporter(runner, options) { + Base.call(this, runner, options); var self = this; var tests = []; @@ -3091,23 +3482,23 @@ var failures = []; var passes = []; - runner.on('test end', function(test) { + runner.on(EVENT_TEST_END, function(test) { tests.push(test); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { passes.push(test); }); - runner.on('fail', function(test) { + runner.on(EVENT_TEST_FAIL, function(test) { failures.push(test); }); - runner.on('pending', function(test) { + runner.on(EVENT_TEST_PENDING, function(test) { pending.push(test); }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { var obj = { stats: self.stats, tests: tests.map(clean), @@ -3126,24 +3517,53 @@ * Return a plain-object representation of `test` * free of cyclic properties etc. * - * @api private + * @private * @param {Object} test * @return {Object} */ function clean(test) { + var err = test.err || {}; + if (err instanceof Error) { + err = errorJSON(err); + } + return { title: test.title, fullTitle: test.fullTitle(), duration: test.duration, currentRetry: test.currentRetry(), - err: errorJSON(test.err || {}) + err: cleanCycles(err) }; } /** - * Transform `error` into a JSON object. + * Replaces any circular references inside `obj` with '[object Object]' * - * @api private + * @private + * @param {Object} obj + * @return {Object} + */ +function cleanCycles(obj) { + var cache = []; + return JSON.parse( + JSON.stringify(obj, function(key, value) { + if (typeof value === 'object' && value !== null) { + if (cache.indexOf(value) !== -1) { + // Instead of going in a circle, we'll print [object Object] + return '' + value; + } + cache.push(value); + } + + return value; + }) + ); +} + +/** + * Transform an Error object into a JSON object. + * + * @private * @param {Error} err * @return {Object} */ @@ -3155,15 +3575,27 @@ return res; } +JSONReporter.description = 'single JSON object'; + }).call(this,require('_process')) -},{"./base":17,"_process":58}],26:[function(require,module,exports){ +},{"../runner":34,"./base":17,"_process":69}],24:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Landing + */ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; +var constants = require('../runner').constants; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_END = constants.EVENT_TEST_END; +var STATE_FAILED = require('../runnable').constants.STATE_FAILED; + var cursor = Base.cursor; var color = Base.color; @@ -3192,16 +3624,20 @@ Base.colors.runway = 90; /** - * Initialize a new `Landing` reporter. + * Constructs a new `Landing` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Landing(runner) { - Base.call(this, runner); +function Landing(runner, options) { + Base.call(this, runner, options); var self = this; - var width = Base.window.width * .75 | 0; + var width = (Base.window.width * 0.75) | 0; var total = runner.total; var stream = process.stdout; var plane = color('plane', '✈'); @@ -3213,17 +3649,17 @@ return ' ' + color('runway', buf); } - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { stream.write('\n\n\n '); cursor.hide(); }); - runner.on('test end', function(test) { + runner.on(EVENT_TEST_END, function(test) { // check if the plane crashed - var col = crashed === -1 ? width * ++n / total | 0 : crashed; + var col = crashed === -1 ? ((width * ++n) / total) | 0 : crashed; // show the crash - if (test.state === 'failed') { + if (test.state === STATE_FAILED) { plane = color('plane crash', '✈'); crashed = col; } @@ -3239,7 +3675,7 @@ stream.write('\u001b[0m'); }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { cursor.show(); console.log(); self.epilogue(); @@ -3251,15 +3687,28 @@ */ inherits(Landing, Base); +Landing.description = 'Unicode landing strip'; + }).call(this,require('_process')) -},{"../utils":39,"./base":17,"_process":58}],27:[function(require,module,exports){ +},{"../runnable":33,"../runner":34,"../utils":38,"./base":17,"_process":69}],25:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module List + */ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; +var constants = require('../runner').constants; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_BEGIN = constants.EVENT_TEST_BEGIN; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; var color = Base.color; var cursor = Base.cursor; @@ -3270,45 +3719,49 @@ exports = module.exports = List; /** - * Initialize a new `List` test reporter. + * Constructs a new `List` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function List(runner) { - Base.call(this, runner); +function List(runner, options) { + Base.call(this, runner, options); var self = this; var n = 0; - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { console.log(); }); - runner.on('test', function(test) { + runner.on(EVENT_TEST_BEGIN, function(test) { process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); }); - runner.on('pending', function(test) { - var fmt = color('checkmark', ' -') - + color('pending', ' %s'); + runner.on(EVENT_TEST_PENDING, function(test) { + var fmt = color('checkmark', ' -') + color('pending', ' %s'); console.log(fmt, test.fullTitle()); }); - runner.on('pass', function(test) { - var fmt = color('checkmark', ' ' + Base.symbols.dot) - + color('pass', ' %s: ') - + color(test.speed, '%dms'); + runner.on(EVENT_TEST_PASS, function(test) { + var fmt = + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s: ') + + color(test.speed, '%dms'); cursor.CR(); console.log(fmt, test.fullTitle(), test.duration); }); - runner.on('fail', function(test) { + runner.on(EVENT_TEST_FAIL, function(test) { cursor.CR(); console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); }); - runner.on('end', self.epilogue.bind(self)); + runner.once(EVENT_RUN_END, self.epilogue.bind(self)); } /** @@ -3316,15 +3769,26 @@ */ inherits(List, Base); +List.description = 'like "spec" reporter but flat'; + }).call(this,require('_process')) -},{"../utils":39,"./base":17,"_process":58}],28:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],26:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Markdown + */ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); +var constants = require('../runner').constants; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_SUITE_END = constants.EVENT_SUITE_END; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; /** * Constants @@ -3339,13 +3803,17 @@ exports = module.exports = Markdown; /** - * Initialize a new `Markdown` reporter. + * Constructs a new `Markdown` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Markdown(runner) { - Base.call(this, runner); +function Markdown(runner, options) { + Base.call(this, runner, options); var level = 0; var buf = ''; @@ -3358,7 +3826,7 @@ var ret = obj; var key = SUITE_PREFIX + suite.title; - obj = obj[key] = obj[key] || { suite: suite }; + obj = obj[key] = obj[key] || {suite: suite}; suite.suites.forEach(function(suite) { mapTOC(suite, obj); }); @@ -3391,18 +3859,18 @@ generateTOC(runner.suite); - runner.on('suite', function(suite) { + runner.on(EVENT_SUITE_BEGIN, function(suite) { ++level; var slug = utils.slug(suite.fullTitle()); buf += '<a name="' + slug + '"></a>' + '\n'; buf += title(suite.title) + '\n'; }); - runner.on('suite end', function() { + runner.on(EVENT_SUITE_END, function() { --level; }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { var code = utils.clean(test.body); buf += test.title + '.\n'; buf += '\n```js\n'; @@ -3410,22 +3878,31 @@ buf += '```\n\n'; }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { process.stdout.write('# TOC\n'); process.stdout.write(generateTOC(runner.suite)); process.stdout.write(buf); }); } +Markdown.description = 'GitHub Flavored Markdown'; + }).call(this,require('_process')) -},{"../utils":39,"./base":17,"_process":58}],29:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],27:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Min + */ /** * Module dependencies. */ var Base = require('./base'); var inherits = require('../utils').inherits; +var constants = require('../runner').constants; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; /** * Expose `Min`. @@ -3434,22 +3911,29 @@ exports = module.exports = Min; /** - * Initialize a new `Min` minimal test reporter (best used with --watch). + * Constructs a new `Min` reporter instance. * - * @api public - * @param {Runner} runner + * @description + * This minimal test reporter is best used with '--watch'. + * + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Min(runner) { - Base.call(this, runner); +function Min(runner, options) { + Base.call(this, runner, options); - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { // clear screen process.stdout.write('\u001b[2J'); // set cursor position process.stdout.write('\u001b[1;3H'); }); - runner.on('end', this.epilogue.bind(this)); + runner.once(EVENT_RUN_END, this.epilogue.bind(this)); } /** @@ -3457,15 +3941,27 @@ */ inherits(Min, Base); +Min.description = 'essentially just a summary'; + }).call(this,require('_process')) -},{"../utils":39,"./base":17,"_process":58}],30:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],28:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Nyan + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; var inherits = require('../utils').inherits; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; /** * Expose `Dot`. @@ -3474,18 +3970,21 @@ exports = module.exports = NyanCat; /** - * Initialize a new `Dot` matrix test reporter. + * Constructs a new `Nyan` reporter instance. * - * @param {Runner} runner - * @api public + * @public + * @class Nyan + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ - -function NyanCat(runner) { - Base.call(this, runner); +function NyanCat(runner, options) { + Base.call(this, runner, options); var self = this; - var width = Base.window.width * .75 | 0; - var nyanCatWidth = this.nyanCatWidth = 11; + var width = (Base.window.width * 0.75) | 0; + var nyanCatWidth = (this.nyanCatWidth = 11); this.colorIndex = 0; this.numberOfLines = 4; @@ -3493,26 +3992,26 @@ this.scoreboardWidth = 5; this.tick = 0; this.trajectories = [[], [], [], []]; - this.trajectoryWidthMax = (width - nyanCatWidth); + this.trajectoryWidthMax = width - nyanCatWidth; - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { Base.cursor.hide(); self.draw(); }); - runner.on('pending', function() { + runner.on(EVENT_TEST_PENDING, function() { self.draw(); }); - runner.on('pass', function() { + runner.on(EVENT_TEST_PASS, function() { self.draw(); }); - runner.on('fail', function() { + runner.on(EVENT_TEST_FAIL, function() { self.draw(); }); - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { Base.cursor.show(); for (var i = 0; i < self.numberOfLines; i++) { write('\n'); @@ -3529,7 +4028,7 @@ /** * Draw the nyan cat * - * @api private + * @private */ NyanCat.prototype.draw = function() { @@ -3544,7 +4043,7 @@ * Draw the "scoreboard" showing the number * of passes, failures and pending tests. * - * @api private + * @private */ NyanCat.prototype.drawScoreboard = function() { @@ -3567,7 +4066,7 @@ /** * Append the rainbow. * - * @api private + * @private */ NyanCat.prototype.appendRainbow = function() { @@ -3586,7 +4085,7 @@ /** * Draw the rainbow. * - * @api private + * @private */ NyanCat.prototype.drawRainbow = function() { @@ -3604,7 +4103,7 @@ /** * Draw the nyan cat * - * @api private + * @private */ NyanCat.prototype.drawNyanCat = function() { var self = this; @@ -3638,7 +4137,7 @@ /** * Draw nyan cat face. * - * @api private + * @private * @return {string} */ @@ -3657,7 +4156,7 @@ /** * Move cursor up `n`. * - * @api private + * @private * @param {number} n */ @@ -3668,7 +4167,7 @@ /** * Move cursor down `n`. * - * @api private + * @private * @param {number} n */ @@ -3679,15 +4178,15 @@ /** * Generate rainbow colors. * - * @api private + * @private * @return {Array} */ NyanCat.prototype.generateColors = function() { var colors = []; - for (var i = 0; i < (6 * 7); i++) { + for (var i = 0; i < 6 * 7; i++) { var pi3 = Math.floor(Math.PI / 3); - var n = (i * (1.0 / 6)); + var n = i * (1.0 / 6); var r = Math.floor(3 * Math.sin(n) + 3); var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); @@ -3700,7 +4199,7 @@ /** * Apply rainbow to the given `str`. * - * @api private + * @private * @param {string} str * @return {string} */ @@ -3722,14 +4221,24 @@ process.stdout.write(string); } +NyanCat.description = '"nyan cat"'; + }).call(this,require('_process')) -},{"../utils":39,"./base":17,"_process":58}],31:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],29:[function(require,module,exports){ (function (process){ +'use strict'; +/** + * @module Progress + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_TEST_END = constants.EVENT_TEST_END; +var EVENT_RUN_END = constants.EVENT_RUN_END; var inherits = require('../utils').inherits; var color = Base.color; var cursor = Base.cursor; @@ -3747,41 +4256,46 @@ Base.colors.progress = 90; /** - * Initialize a new `Progress` bar test reporter. + * Constructs a new `Progress` reporter instance. * - * @api public - * @param {Runner} runner - * @param {Object} options + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ function Progress(runner, options) { - Base.call(this, runner); + Base.call(this, runner, options); var self = this; - var width = Base.window.width * .50 | 0; + var width = (Base.window.width * 0.5) | 0; var total = runner.total; var complete = 0; var lastN = -1; // default chars options = options || {}; - options.open = options.open || '['; - options.complete = options.complete || '▬'; - options.incomplete = options.incomplete || Base.symbols.dot; - options.close = options.close || ']'; - options.verbose = false; + var reporterOptions = options.reporterOptions || {}; + + options.open = reporterOptions.open || '['; + options.complete = reporterOptions.complete || '▬'; + options.incomplete = reporterOptions.incomplete || Base.symbols.dot; + options.close = reporterOptions.close || ']'; + options.verbose = reporterOptions.verbose || false; // tests started - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { console.log(); cursor.hide(); }); // tests complete - runner.on('test end', function() { + runner.on(EVENT_TEST_END, function() { complete++; var percent = complete / total; - var n = width * percent | 0; + var n = (width * percent) | 0; var i = width - n; if (n === lastN && !options.verbose) { @@ -3803,7 +4317,7 @@ // tests are complete, output some stats // and the failures if any - runner.on('end', function() { + runner.once(EVENT_RUN_END, function() { cursor.show(); console.log(); self.epilogue(); @@ -3815,16 +4329,29 @@ */ inherits(Progress, Base); +Progress.description = 'a progress bar'; + }).call(this,require('_process')) -},{"../utils":39,"./base":17,"_process":58}],32:[function(require,module,exports){ +},{"../runner":34,"../utils":38,"./base":17,"_process":69}],30:[function(require,module,exports){ +'use strict'; +/** + * @module Spec + */ /** * Module dependencies. */ var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_SUITE_END = constants.EVENT_SUITE_END; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; var inherits = require('../utils').inherits; var color = Base.color; -var cursor = Base.cursor; /** * Expose `Spec`. @@ -3833,13 +4360,17 @@ exports = module.exports = Spec; /** - * Initialize a new `Spec` test reporter. + * Constructs a new `Spec` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function Spec(runner) { - Base.call(this, runner); +function Spec(runner, options) { + Base.call(this, runner, options); var self = this; var indents = 0; @@ -3849,51 +4380,50 @@ return Array(indents).join(' '); } - runner.on('start', function() { + runner.on(EVENT_RUN_BEGIN, function() { console.log(); }); - runner.on('suite', function(suite) { + runner.on(EVENT_SUITE_BEGIN, function(suite) { ++indents; console.log(color('suite', '%s%s'), indent(), suite.title); }); - runner.on('suite end', function() { + runner.on(EVENT_SUITE_END, function() { --indents; if (indents === 1) { console.log(); } }); - runner.on('pending', function(test) { + runner.on(EVENT_TEST_PENDING, function(test) { var fmt = indent() + color('pending', ' - %s'); console.log(fmt, test.title); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { var fmt; if (test.speed === 'fast') { - fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s'); - cursor.CR(); + fmt = + indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s'); console.log(fmt, test.title); } else { - fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s') - + color(test.speed, ' (%dms)'); - cursor.CR(); + fmt = + indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s') + + color(test.speed, ' (%dms)'); console.log(fmt, test.title, test.duration); } }); - runner.on('fail', function(test) { - cursor.CR(); + runner.on(EVENT_TEST_FAIL, function(test) { console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); }); - runner.on('end', self.epilogue.bind(self)); + runner.once(EVENT_RUN_END, self.epilogue.bind(self)); } /** @@ -3901,12 +4431,29 @@ */ inherits(Spec, Base); -},{"../utils":39,"./base":17}],33:[function(require,module,exports){ +Spec.description = 'hierarchical & verbose [default]'; + +},{"../runner":34,"../utils":38,"./base":17}],31:[function(require,module,exports){ +(function (process){ +'use strict'; +/** + * @module TAP + */ /** * Module dependencies. */ +var util = require('util'); var Base = require('./base'); +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var EVENT_TEST_END = constants.EVENT_TEST_END; +var inherits = require('../utils').inherits; +var sprintf = util.format; /** * Expose `TAP`. @@ -3915,87 +4462,305 @@ exports = module.exports = TAP; /** - * Initialize a new `TAP` reporter. + * Constructs a new `TAP` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ -function TAP(runner) { - Base.call(this, runner); +function TAP(runner, options) { + Base.call(this, runner, options); + var self = this; var n = 1; - var passes = 0; - var failures = 0; - runner.on('start', function() { - var total = runner.grepTotal(runner.suite); - console.log('%d..%d', 1, total); + var tapVersion = '12'; + if (options && options.reporterOptions) { + if (options.reporterOptions.tapVersion) { + tapVersion = options.reporterOptions.tapVersion.toString(); + } + } + + this._producer = createProducer(tapVersion); + + runner.once(EVENT_RUN_BEGIN, function() { + var ntests = runner.grepTotal(runner.suite); + self._producer.writeVersion(); + self._producer.writePlan(ntests); }); - runner.on('test end', function() { + runner.on(EVENT_TEST_END, function() { ++n; }); - runner.on('pending', function(test) { - console.log('ok %d %s # SKIP -', n, title(test)); + runner.on(EVENT_TEST_PENDING, function(test) { + self._producer.writePending(n, test); }); - runner.on('pass', function(test) { - passes++; - console.log('ok %d %s', n, title(test)); + runner.on(EVENT_TEST_PASS, function(test) { + self._producer.writePass(n, test); }); - runner.on('fail', function(test, err) { - failures++; - console.log('not ok %d %s', n, title(test)); - if (err.stack) { - console.log(err.stack.replace(/^/gm, ' ')); - } + runner.on(EVENT_TEST_FAIL, function(test, err) { + self._producer.writeFail(n, test, err); }); - runner.on('end', function() { - console.log('# tests ' + (passes + failures)); - console.log('# pass ' + passes); - console.log('# fail ' + failures); + runner.once(EVENT_RUN_END, function() { + self._producer.writeEpilogue(runner.stats); }); } /** - * Return a TAP-safe title of `test` + * Inherit from `Base.prototype`. + */ +inherits(TAP, Base); + +/** + * Returns a TAP-safe title of `test`. * - * @api private - * @param {Object} test - * @return {String} + * @private + * @param {Test} test - Test instance. + * @return {String} title with any hash character removed */ function title(test) { return test.fullTitle().replace(/#/g, ''); } -},{"./base":17}],34:[function(require,module,exports){ +/** + * Writes newline-terminated formatted string to reporter output stream. + * + * @private + * @param {string} format - `printf`-like format string + * @param {...*} [varArgs] - Format string arguments + */ +function println(format, varArgs) { + var vargs = Array.from(arguments); + vargs[0] += '\n'; + process.stdout.write(sprintf.apply(null, vargs)); +} + +/** + * Returns a `tapVersion`-appropriate TAP producer instance, if possible. + * + * @private + * @param {string} tapVersion - Version of TAP specification to produce. + * @returns {TAPProducer} specification-appropriate instance + * @throws {Error} if specification version has no associated producer. + */ +function createProducer(tapVersion) { + var producers = { + '12': new TAP12Producer(), + '13': new TAP13Producer() + }; + var producer = producers[tapVersion]; + + if (!producer) { + throw new Error( + 'invalid or unsupported TAP version: ' + JSON.stringify(tapVersion) + ); + } + + return producer; +} + +/** + * @summary + * Constructs a new TAPProducer. + * + * @description + * <em>Only</em> to be used as an abstract base class. + * + * @private + * @constructor + */ +function TAPProducer() {} + +/** + * Writes the TAP version to reporter output stream. + * + * @abstract + */ +TAPProducer.prototype.writeVersion = function() {}; + +/** + * Writes the plan to reporter output stream. + * + * @abstract + * @param {number} ntests - Number of tests that are planned to run. + */ +TAPProducer.prototype.writePlan = function(ntests) { + println('%d..%d', 1, ntests); +}; + +/** + * Writes that test passed to reporter output stream. + * + * @abstract + * @param {number} n - Index of test that passed. + * @param {Test} test - Instance containing test information. + */ +TAPProducer.prototype.writePass = function(n, test) { + println('ok %d %s', n, title(test)); +}; + +/** + * Writes that test was skipped to reporter output stream. + * + * @abstract + * @param {number} n - Index of test that was skipped. + * @param {Test} test - Instance containing test information. + */ +TAPProducer.prototype.writePending = function(n, test) { + println('ok %d %s # SKIP -', n, title(test)); +}; + +/** + * Writes that test failed to reporter output stream. + * + * @abstract + * @param {number} n - Index of test that failed. + * @param {Test} test - Instance containing test information. + * @param {Error} err - Reason the test failed. + */ +TAPProducer.prototype.writeFail = function(n, test, err) { + println('not ok %d %s', n, title(test)); +}; + +/** + * Writes the summary epilogue to reporter output stream. + * + * @abstract + * @param {Object} stats - Object containing run statistics. + */ +TAPProducer.prototype.writeEpilogue = function(stats) { + // :TBD: Why is this not counting pending tests? + println('# tests ' + (stats.passes + stats.failures)); + println('# pass ' + stats.passes); + // :TBD: Why are we not showing pending results? + println('# fail ' + stats.failures); +}; + +/** + * @summary + * Constructs a new TAP12Producer. + * + * @description + * Produces output conforming to the TAP12 specification. + * + * @private + * @constructor + * @extends TAPProducer + * @see {@link https://testanything.org/tap-specification.html|Specification} + */ +function TAP12Producer() { + /** + * Writes that test failed to reporter output stream, with error formatting. + * @override + */ + this.writeFail = function(n, test, err) { + TAPProducer.prototype.writeFail.call(this, n, test, err); + if (err.message) { + println(err.message.replace(/^/gm, ' ')); + } + if (err.stack) { + println(err.stack.replace(/^/gm, ' ')); + } + }; +} + +/** + * Inherit from `TAPProducer.prototype`. + */ +inherits(TAP12Producer, TAPProducer); + +/** + * @summary + * Constructs a new TAP13Producer. + * + * @description + * Produces output conforming to the TAP13 specification. + * + * @private + * @constructor + * @extends TAPProducer + * @see {@link https://testanything.org/tap-version-13-specification.html|Specification} + */ +function TAP13Producer() { + /** + * Writes the TAP version to reporter output stream. + * @override + */ + this.writeVersion = function() { + println('TAP version 13'); + }; + + /** + * Writes that test failed to reporter output stream, with error formatting. + * @override + */ + this.writeFail = function(n, test, err) { + TAPProducer.prototype.writeFail.call(this, n, test, err); + var emitYamlBlock = err.message != null || err.stack != null; + if (emitYamlBlock) { + println(indent(1) + '---'); + if (err.message) { + println(indent(2) + 'message: |-'); + println(err.message.replace(/^/gm, indent(3))); + } + if (err.stack) { + println(indent(2) + 'stack: |-'); + println(err.stack.replace(/^/gm, indent(3))); + } + println(indent(1) + '...'); + } + }; + + function indent(level) { + return Array(level + 1).join(' '); + } +} + +/** + * Inherit from `TAPProducer.prototype`. + */ +inherits(TAP13Producer, TAPProducer); + +TAP.description = 'TAP-compatible output'; + +}).call(this,require('_process')) +},{"../runner":34,"../utils":38,"./base":17,"_process":69,"util":89}],32:[function(require,module,exports){ (function (process,global){ +'use strict'; +/** + * @module XUnit + */ /** * Module dependencies. */ var Base = require('./base'); var utils = require('../utils'); -var inherits = utils.inherits; var fs = require('fs'); -var escape = utils.escape; var mkdirp = require('mkdirp'); var path = require('path'); +var errors = require('../errors'); +var createUnsupportedError = errors.createUnsupportedError; +var constants = require('../runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var STATE_FAILED = require('../runnable').constants.STATE_FAILED; +var inherits = utils.inherits; +var escape = utils.escape; /** * Save timer references to avoid Sinon interfering (see GH-237). */ - -/* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ /** * Expose `XUnit`. @@ -4004,48 +4769,73 @@ exports = module.exports = XUnit; /** - * Initialize a new `XUnit` reporter. + * Constructs a new `XUnit` reporter instance. * - * @api public - * @param {Runner} runner + * @public + * @class + * @memberof Mocha.reporters + * @extends Mocha.reporters.Base + * @param {Runner} runner - Instance triggers reporter actions. + * @param {Object} [options] - runner options */ function XUnit(runner, options) { - Base.call(this, runner); + Base.call(this, runner, options); var stats = this.stats; var tests = []; var self = this; - if (options.reporterOptions && options.reporterOptions.output) { - if (!fs.createWriteStream) { - throw new Error('file output not supported in browser'); + // the name of the test suite, as it will appear in the resulting XML file + var suiteName; + + // the default name of the test suite if none is provided + var DEFAULT_SUITE_NAME = 'Mocha Tests'; + + if (options && options.reporterOptions) { + if (options.reporterOptions.output) { + if (!fs.createWriteStream) { + throw createUnsupportedError('file output not supported in browser'); + } + + mkdirp.sync(path.dirname(options.reporterOptions.output)); + self.fileStream = fs.createWriteStream(options.reporterOptions.output); } - mkdirp.sync(path.dirname(options.reporterOptions.output)); - self.fileStream = fs.createWriteStream(options.reporterOptions.output); + + // get the suite name from the reporter options (if provided) + suiteName = options.reporterOptions.suiteName; } - runner.on('pending', function(test) { + // fall back to the default suite name + suiteName = suiteName || DEFAULT_SUITE_NAME; + + runner.on(EVENT_TEST_PENDING, function(test) { tests.push(test); }); - runner.on('pass', function(test) { + runner.on(EVENT_TEST_PASS, function(test) { tests.push(test); }); - runner.on('fail', function(test) { + runner.on(EVENT_TEST_FAIL, function(test) { tests.push(test); }); - runner.on('end', function() { - self.write(tag('testsuite', { - name: 'Mocha Tests', - tests: stats.tests, - failures: stats.failures, - errors: stats.failures, - skipped: stats.tests - stats.failures - stats.passes, - timestamp: (new Date()).toUTCString(), - time: (stats.duration / 1000) || 0 - }, false)); + runner.once(EVENT_RUN_END, function() { + self.write( + tag( + 'testsuite', + { + name: suiteName, + tests: stats.tests, + failures: 0, + errors: stats.failures, + skipped: stats.tests - stats.failures - stats.passes, + timestamp: new Date().toUTCString(), + time: stats.duration / 1000 || 0 + }, + false + ) + ); tests.forEach(function(t) { self.test(t); @@ -4097,15 +4887,33 @@ * @param {Test} test */ XUnit.prototype.test = function(test) { + Base.useColors = false; + var attrs = { classname: test.parent.fullTitle(), name: test.title, - time: (test.duration / 1000) || 0 + time: test.duration / 1000 || 0 }; - if (test.state === 'failed') { + if (test.state === STATE_FAILED) { var err = test.err; - this.write(tag('testcase', attrs, false, tag('failure', {}, false, escape(err.message) + '\n' + escape(err.stack)))); + var diff = + Base.hideDiff || !err.actual || !err.expected + ? '' + : '\n' + Base.generateDiff(err.actual, err.expected); + this.write( + tag( + 'testcase', + attrs, + false, + tag( + 'failure', + {}, + false, + escape(err.message) + escape(diff) + '\n' + escape(err.stack) + ) + ) + ); } else if (test.isPending()) { this.write(tag('testcase', attrs, false, tag('skipped', {}, true))); } else { @@ -4140,52 +4948,39 @@ return tag; } +XUnit.description = 'XUnit-compatible XML output'; + }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"../utils":39,"./base":17,"_process":58,"fs":43,"mkdirp":55,"path":43}],35:[function(require,module,exports){ +},{"../errors":6,"../runnable":33,"../runner":34,"../utils":38,"./base":17,"_process":69,"fs":42,"mkdirp":59,"path":42}],33:[function(require,module,exports){ (function (global){ -/** - * Module dependencies. - */ +'use strict'; var EventEmitter = require('events').EventEmitter; var Pending = require('./pending'); var debug = require('debug')('mocha:runnable'); -var milliseconds = require('./ms'); +var milliseconds = require('ms'); var utils = require('./utils'); -var inherits = utils.inherits; +var createInvalidExceptionError = require('./errors') + .createInvalidExceptionError; /** * Save timer references to avoid Sinon interfering (see GH-237). */ - -/* eslint-disable no-unused-vars, no-native-reassign */ var Date = global.Date; var setTimeout = global.setTimeout; -var setInterval = global.setInterval; var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; -/* eslint-enable no-unused-vars, no-native-reassign */ - -/** - * Object#toString(). - */ - var toString = Object.prototype.toString; -/** - * Expose `Runnable`. - */ - module.exports = Runnable; /** * Initialize a new `Runnable` with the given `title` and callback `fn`. * + * @class + * @extends external:EventEmitter + * @public * @param {String} title * @param {Function} fn - * @api private - * @param {string} title - * @param {Function} fn */ function Runnable(title, fn) { this.title = title; @@ -4197,7 +4992,6 @@ this._slow = 75; this._enableTimeouts = true; this.timedOut = false; - this._trace = new Error('done() called multiple times'); this._retries = -1; this._currentRetry = 0; this.pending = false; @@ -4206,25 +5000,46 @@ /** * Inherit from `EventEmitter.prototype`. */ -inherits(Runnable, EventEmitter); +utils.inherits(Runnable, EventEmitter); /** - * Set & get timeout `ms`. + * Get current timeout value in msecs. * - * @api private - * @param {number|string} ms - * @return {Runnable|number} ms or Runnable instance. + * @private + * @returns {number} current timeout threshold value + */ +/** + * @summary + * Set timeout threshold value (msecs). + * + * @description + * A string argument can use shorthand (e.g., "2s") and will be converted. + * The value will be clamped to range [<code>0</code>, <code>2^<sup>31</sup>-1</code>]. + * If clamped value matches either range endpoint, timeouts will be disabled. + * + * @private + * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/setTimeout#Maximum_delay_value} + * @param {number|string} ms - Timeout threshold value. + * @returns {Runnable} this + * @chainable */ Runnable.prototype.timeout = function(ms) { if (!arguments.length) { return this._timeout; } - if (ms === 0) { - this._enableTimeouts = false; - } if (typeof ms === 'string') { ms = milliseconds(ms); } + + // Clamp to range + var INT_MAX = Math.pow(2, 31) - 1; + var range = [0, INT_MAX]; + ms = utils.clamp(ms, range); + + // see #1652 for reasoning + if (ms === range[0] || ms === range[1]) { + this._enableTimeouts = false; + } debug('timeout %d', ms); this._timeout = ms; if (this.timer) { @@ -4234,20 +5049,20 @@ }; /** - * Set & get slow `ms`. + * Set or get slow `ms`. * - * @api private + * @private * @param {number|string} ms * @return {Runnable|number} ms or Runnable instance. */ Runnable.prototype.slow = function(ms) { - if (!arguments.length) { + if (!arguments.length || typeof ms === 'undefined') { return this._slow; } if (typeof ms === 'string') { ms = milliseconds(ms); } - debug('timeout %d', ms); + debug('slow %d', ms); this._slow = ms; return this; }; @@ -4255,7 +5070,7 @@ /** * Set and get whether timeout is `enabled`. * - * @api private + * @private * @param {boolean} enabled * @return {Runnable|boolean} enabled or Runnable instance. */ @@ -4271,25 +5086,44 @@ /** * Halt and mark as pending. * - * @api public + * @memberof Mocha.Runnable + * @public */ Runnable.prototype.skip = function() { - throw new Pending(); + throw new Pending('sync skip'); }; /** * Check if this runnable or its parent suite is marked as pending. * - * @api private + * @private */ Runnable.prototype.isPending = function() { return this.pending || (this.parent && this.parent.isPending()); }; /** - * Set number of retries. + * Return `true` if this Runnable has failed. + * @return {boolean} + * @private + */ +Runnable.prototype.isFailed = function() { + return !this.isPending() && this.state === constants.STATE_FAILED; +}; + +/** + * Return `true` if this Runnable has passed. + * @return {boolean} + * @private + */ +Runnable.prototype.isPassed = function() { + return !this.isPending() && this.state === constants.STATE_PASSED; +}; + +/** + * Set or get number of retries. * - * @api private + * @private */ Runnable.prototype.retries = function(n) { if (!arguments.length) { @@ -4299,9 +5133,9 @@ }; /** - * Get current retry + * Set or get current retry * - * @api private + * @private */ Runnable.prototype.currentRetry = function(n) { if (!arguments.length) { @@ -4314,17 +5148,29 @@ * Return the full title generated by recursively concatenating the parent's * full title. * - * @api public + * @memberof Mocha.Runnable + * @public * @return {string} */ Runnable.prototype.fullTitle = function() { - return this.parent.fullTitle() + ' ' + this.title; + return this.titlePath().join(' '); +}; + +/** + * Return the title path generated by concatenating the parent's title path with the title. + * + * @memberof Mocha.Runnable + * @public + * @return {string} + */ +Runnable.prototype.titlePath = function() { + return this.parent.titlePath().concat([this.title]); }; /** * Clear the timeout. * - * @api private + * @private */ Runnable.prototype.clearTimeout = function() { clearTimeout(this.timer); @@ -4333,28 +5179,32 @@ /** * Inspect the runnable void of private properties. * - * @api private + * @private * @return {string} */ Runnable.prototype.inspect = function() { - return JSON.stringify(this, function(key, val) { - if (key[0] === '_') { - return; - } - if (key === 'parent') { - return '#<Suite>'; - } - if (key === 'ctx') { - return '#<Context>'; - } - return val; - }, 2); + return JSON.stringify( + this, + function(key, val) { + if (key[0] === '_') { + return; + } + if (key === 'parent') { + return '#<Suite>'; + } + if (key === 'ctx') { + return '#<Context>'; + } + return val; + }, + 2 + ); }; /** * Reset the timeout. * - * @api private + * @private */ Runnable.prototype.resetTimeout = function() { var self = this; @@ -4368,15 +5218,15 @@ if (!self._enableTimeouts) { return; } - self.callback(new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.')); + self.callback(self._timeoutError(ms)); self.timedOut = true; }, ms); }; /** - * Whitelist a list of globals for this test run. + * Set or get a list of whitelisted globals for this test run. * - * @api private + * @private * @param {string[]} globals */ Runnable.prototype.globals = function(globals) { @@ -4390,7 +5240,7 @@ * Run the test and invoke `fn(err)`. * * @param {Function} fn - * @api private + * @private */ Runnable.prototype.run = function(fn) { var self = this; @@ -4410,7 +5260,13 @@ return; } emitted = true; - self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); + var msg = 'done() called multiple times'; + if (err && err.message) { + err.message += " (and Mocha's " + msg + ')'; + self.emit('error', err); + } else { + self.emit('error', new Error(msg)); + } } // finished @@ -4419,15 +5275,16 @@ if (self.timedOut) { return; } + if (finished) { - return multiple(err || self._trace); + return multiple(err); } self.clearTimeout(); self.duration = new Date() - start; finished = true; if (!err && self.duration > ms && self._enableTimeouts) { - err = new Error('timeout of ' + ms + 'ms exceeded. Ensure the done() callback is being called in this test.'); + err = self._timeoutError(ms); } fn(err); } @@ -4439,20 +5296,33 @@ if (this.async) { this.resetTimeout(); + // allows skip() to be used in an explicit async context + this.skip = function asyncSkip() { + done(new Pending('async skip call')); + // halt execution. the Runnable will be marked pending + // by the previous call, and the uncaught handler will ignore + // the failure. + throw new Pending('async skip; aborting execution'); + }; + if (this.allowUncaught) { return callFnAsync(this.fn); } try { callFnAsync(this.fn); } catch (err) { - done(utils.getError(err)); + emitted = true; + done(Runnable.toValueOrError(err)); } return; } if (this.allowUncaught) { - callFn(this.fn); - done(); + if (this.isPending()) { + done(); + } else { + callFn(this.fn); + } return; } @@ -4464,15 +5334,16 @@ callFn(this.fn); } } catch (err) { - done(utils.getError(err)); + emitted = true; + done(Runnable.toValueOrError(err)); } function callFn(fn) { var result = fn.call(ctx); if (result && typeof result.then === 'function') { self.resetTimeout(); - result - .then(function() { + result.then( + function() { done(); // Return null so libraries like bluebird do not warn about // subsequently constructed Promises. @@ -4480,10 +5351,15 @@ }, function(reason) { done(reason || new Error('Promise rejected with no or falsy reason')); - }); + } + ); } else { if (self.asyncOnly) { - return done(new Error('--async-only option in use without declaring `done()` or returning a promise')); + return done( + new Error( + '--async-only option in use without declaring `done()` or returning a promise' + ) + ); } done(); @@ -4491,48 +5367,125 @@ } function callFnAsync(fn) { - fn.call(ctx, function(err) { + var result = fn.call(ctx, function(err) { if (err instanceof Error || toString.call(err) === '[object Error]') { return done(err); } if (err) { if (Object.prototype.toString.call(err) === '[object Object]') { - return done(new Error('done() invoked with non-Error: ' - + JSON.stringify(err))); + return done( + new Error('done() invoked with non-Error: ' + JSON.stringify(err)) + ); } return done(new Error('done() invoked with non-Error: ' + err)); } + if (result && utils.isPromise(result)) { + return done( + new Error( + 'Resolution method is overspecified. Specify a callback *or* return a Promise; not both.' + ) + ); + } + done(); }); } }; +/** + * Instantiates a "timeout" error + * + * @param {number} ms - Timeout (in milliseconds) + * @returns {Error} a "timeout" error + * @private + */ +Runnable.prototype._timeoutError = function(ms) { + var msg = + 'Timeout of ' + + ms + + 'ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.'; + if (this.file) { + msg += ' (' + this.file + ')'; + } + return new Error(msg); +}; + +var constants = utils.defineConstants( + /** + * {@link Runnable}-related constants. + * @public + * @memberof Runnable + * @readonly + * @static + * @alias constants + * @enum {string} + */ + { + /** + * Value of `state` prop when a `Runnable` has failed + */ + STATE_FAILED: 'failed', + /** + * Value of `state` prop when a `Runnable` has passed + */ + STATE_PASSED: 'passed' + } +); + +/** + * Given `value`, return identity if truthy, otherwise create an "invalid exception" error and return that. + * @param {*} [value] - Value to return, if present + * @returns {*|Error} `value`, otherwise an `Error` + * @private + */ +Runnable.toValueOrError = function(value) { + return ( + value || + createInvalidExceptionError( + 'Runnable failed with falsy or undefined exception. Please throw an Error instead.', + value + ) + ); +}; + +Runnable.constants = constants; + }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./ms":15,"./pending":16,"./utils":39,"debug":2,"events":3}],36:[function(require,module,exports){ +},{"./errors":6,"./pending":16,"./utils":38,"debug":45,"events":50,"ms":60}],34:[function(require,module,exports){ (function (process,global){ +'use strict'; + /** * Module dependencies. */ - +var util = require('util'); var EventEmitter = require('events').EventEmitter; var Pending = require('./pending'); var utils = require('./utils'); var inherits = utils.inherits; var debug = require('debug')('mocha:runner'); var Runnable = require('./runnable'); -var filter = utils.filter; -var indexOf = utils.indexOf; -var keys = utils.keys; +var Suite = require('./suite'); +var HOOK_TYPE_BEFORE_EACH = Suite.constants.HOOK_TYPE_BEFORE_EACH; +var HOOK_TYPE_AFTER_EACH = Suite.constants.HOOK_TYPE_AFTER_EACH; +var HOOK_TYPE_AFTER_ALL = Suite.constants.HOOK_TYPE_AFTER_ALL; +var HOOK_TYPE_BEFORE_ALL = Suite.constants.HOOK_TYPE_BEFORE_ALL; +var EVENT_ROOT_SUITE_RUN = Suite.constants.EVENT_ROOT_SUITE_RUN; +var STATE_FAILED = Runnable.constants.STATE_FAILED; +var STATE_PASSED = Runnable.constants.STATE_PASSED; +var dQuote = utils.dQuote; +var ngettext = utils.ngettext; +var sQuote = utils.sQuote; var stackFilter = utils.stackTraceFilter(); var stringify = utils.stringify; var type = utils.type; -var undefinedError = utils.undefinedError; -var isArray = utils.isArray; +var createInvalidExceptionError = require('./errors') + .createInvalidExceptionError; /** * Non-enumerable globals. + * @readonly */ - var globals = [ 'setTimeout', 'clearTimeout', @@ -4544,30 +5497,84 @@ 'clearImmediate' ]; -/** - * Expose `Runner`. - */ +var constants = utils.defineConstants( + /** + * {@link Runner}-related constants. + * @public + * @memberof Runner + * @readonly + * @alias constants + * @static + * @enum {string} + */ + { + /** + * Emitted when {@link Hook} execution begins + */ + EVENT_HOOK_BEGIN: 'hook', + /** + * Emitted when {@link Hook} execution ends + */ + EVENT_HOOK_END: 'hook end', + /** + * Emitted when Root {@link Suite} execution begins (all files have been parsed and hooks/tests are ready for execution) + */ + EVENT_RUN_BEGIN: 'start', + /** + * Emitted when Root {@link Suite} execution has been delayed via `delay` option + */ + EVENT_DELAY_BEGIN: 'waiting', + /** + * Emitted when delayed Root {@link Suite} execution is triggered by user via `global.run()` + */ + EVENT_DELAY_END: 'ready', + /** + * Emitted when Root {@link Suite} execution ends + */ + EVENT_RUN_END: 'end', + /** + * Emitted when {@link Suite} execution begins + */ + EVENT_SUITE_BEGIN: 'suite', + /** + * Emitted when {@link Suite} execution ends + */ + EVENT_SUITE_END: 'suite end', + /** + * Emitted when {@link Test} execution begins + */ + EVENT_TEST_BEGIN: 'test', + /** + * Emitted when {@link Test} execution ends + */ + EVENT_TEST_END: 'test end', + /** + * Emitted when {@link Test} execution fails + */ + EVENT_TEST_FAIL: 'fail', + /** + * Emitted when {@link Test} execution succeeds + */ + EVENT_TEST_PASS: 'pass', + /** + * Emitted when {@link Test} becomes pending + */ + EVENT_TEST_PENDING: 'pending', + /** + * Emitted when {@link Test} execution has failed, but will retry + */ + EVENT_TEST_RETRY: 'retry' + } +); module.exports = Runner; /** - * Initialize a `Runner` for the given `suite`. + * Initialize a `Runner` at the Root {@link Suite}, which represents a hierarchy of {@link Suite|Suites} and {@link Test|Tests}. * - * Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - `pending` (test) test pending - * - * @api public + * @extends external:EventEmitter + * @public + * @class * @param {Suite} suite Root suite * @param {boolean} [delay] Whether or not to delay execution of root suite * until ready. @@ -4581,10 +5588,10 @@ this.started = false; this.total = suite.total(); this.failures = 0; - this.on('test end', function(test) { + this.on(constants.EVENT_TEST_END, function(test) { self.checkGlobals(test); }); - this.on('hook end', function(hook) { + this.on(constants.EVENT_HOOK_END, function(hook) { self.checkGlobals(hook); }); this._defaultGrep = /.*/; @@ -4596,7 +5603,7 @@ * Wrapper for setImmediate, process.nextTick, or browser polyfill. * * @param {Function} fn - * @api private + * @private */ Runner.immediately = global.setImmediate || process.nextTick; @@ -4609,10 +5616,8 @@ * Run tests with full titles matching `re`. Updates runner.total * with number of tests matched. * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining - * @api public + * @public + * @memberof Runner * @param {RegExp} re * @param {boolean} invert * @return {Runner} Runner instance. @@ -4629,9 +5634,8 @@ * Returns the number of tests matching the grep search for the * given suite. * - * @param {Suite} suite - * @return {Number} - * @api public + * @memberof Runner + * @public * @param {Suite} suite * @return {number} */ @@ -4656,14 +5660,14 @@ * Return a list of global properties. * * @return {Array} - * @api private + * @private */ Runner.prototype.globalProps = function() { - var props = keys(global); + var props = Object.keys(global); // non-enumerables for (var i = 0; i < globals.length; ++i) { - if (~indexOf(props, globals[i])) { + if (~props.indexOf(globals[i])) { continue; } props.push(globals[i]); @@ -4675,9 +5679,8 @@ /** * Allow the given `arr` of globals. * - * @param {Array} arr - * @return {Runner} for chaining - * @api public + * @public + * @memberof Runner * @param {Array} arr * @return {Runner} Runner instance. */ @@ -4693,7 +5696,7 @@ /** * Check for global variable leaks. * - * @api private + * @private */ Runner.prototype.checkGlobals = function(test) { if (this.ignoreLeaks) { @@ -4716,40 +5719,52 @@ leaks = filterLeaks(ok, globals); this._globals = this._globals.concat(leaks); - if (leaks.length > 1) { - this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); - } else if (leaks.length) { - this.fail(test, new Error('global leak detected: ' + leaks[0])); + if (leaks.length) { + var format = ngettext( + leaks.length, + 'global leak detected: %s', + 'global leaks detected: %s' + ); + var error = new Error(util.format(format, leaks.map(sQuote).join(', '))); + this.fail(test, error); } }; /** * Fail the given `test`. * - * @api private + * @private * @param {Test} test * @param {Error} err */ Runner.prototype.fail = function(test, err) { - ++this.failures; - test.state = 'failed'; - - if (!(err instanceof Error || err && typeof err.message === 'string')) { - err = new Error('the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)'); + if (test.isPending()) { + return; } - err.stack = (this.fullStackTrace || !err.stack) - ? err.stack - : stackFilter(err.stack); + ++this.failures; + test.state = STATE_FAILED; - this.emit('fail', test, err); + if (!isError(err)) { + err = thrown2Error(err); + } + + try { + err.stack = + this.fullStackTrace || !err.stack ? err.stack : stackFilter(err.stack); + } catch (ignore) { + // some environments do not take kindly to monkeying with the stack + } + + this.emit(constants.EVENT_TEST_FAIL, test, err); }; /** * Fail the given `hook` with `err`. * * Hook failures work in the following pattern: - * - If bail, then exit + * - If bail, run corresponding `after each` and `after` hooks, + * then exit * - Failed `before` hook skips all tests in a suite and subsuites, * but jumps to corresponding `after` hook * - Failed `before each` hook skips remaining tests in a @@ -4761,33 +5776,39 @@ * suite and subsuites, but executes other `after each` * hooks * - * @api private + * @private * @param {Hook} hook * @param {Error} err */ Runner.prototype.failHook = function(hook, err) { + hook.originalTitle = hook.originalTitle || hook.title; if (hook.ctx && hook.ctx.currentTest) { - hook.originalTitle = hook.originalTitle || hook.title; - hook.title = hook.originalTitle + ' for "' + hook.ctx.currentTest.title + '"'; + hook.title = + hook.originalTitle + ' for ' + dQuote(hook.ctx.currentTest.title); + } else { + var parentTitle; + if (hook.parent.title) { + parentTitle = hook.parent.title; + } else { + parentTitle = hook.parent.root ? '{root}' : ''; + } + hook.title = hook.originalTitle + ' in ' + dQuote(parentTitle); } this.fail(hook, err); - if (this.suite.bail()) { - this.emit('end'); - } }; /** * Run hook `name` callbacks and then invoke `fn()`. * - * @api private + * @private * @param {string} name * @param {Function} fn */ Runner.prototype.hook = function(name, fn) { var suite = this.suite; - var hooks = suite['_' + name]; + var hooks = suite.getHooks(name); var self = this; function next(i) { @@ -4797,9 +5818,17 @@ } self.currentRunnable = hook; - hook.ctx.currentTest = self.test; + if (name === HOOK_TYPE_BEFORE_ALL) { + hook.ctx.currentTest = hook.parent.tests[0]; + } else if (name === HOOK_TYPE_AFTER_ALL) { + hook.ctx.currentTest = hook.parent.tests[hook.parent.tests.length - 1]; + } else { + hook.ctx.currentTest = self.test; + } - self.emit('hook', hook); + hook.allowUncaught = self.allowUncaught; + + self.emit(constants.EVENT_HOOK_BEGIN, hook); if (!hook.listeners('error').length) { hook.on('error', function(err) { @@ -4814,7 +5843,26 @@ } if (err) { if (err instanceof Pending) { - suite.pending = true; + if (name === HOOK_TYPE_AFTER_ALL) { + utils.deprecate( + 'Skipping a test within an "after all" hook is DEPRECATED and will throw an exception in a future version of Mocha. ' + + 'Use a return statement or other means to abort hook execution.' + ); + } + if (name === HOOK_TYPE_BEFORE_EACH || name === HOOK_TYPE_AFTER_EACH) { + if (self.test) { + self.test.pending = true; + } + } else { + suite.tests.forEach(function(test) { + test.pending = true; + }); + suite.suites.forEach(function(suite) { + suite.pending = true; + }); + // a pending hook won't be executed twice. + hook.pending = true; + } } else { self.failHook(hook, err); @@ -4822,7 +5870,7 @@ return fn(err); } } - self.emit('hook end', hook); + self.emit(constants.EVENT_HOOK_END, hook); delete hook.ctx.currentTest; next(++i); }); @@ -4837,7 +5885,7 @@ * Run hook `name` for the given array of `suites` * in order, and callback `fn(err, errSuite)`. * - * @api private + * @private * @param {string} name * @param {Array} suites * @param {Function} fn @@ -4873,7 +5921,7 @@ * * @param {String} name * @param {Function} fn - * @api private + * @private */ Runner.prototype.hookUp = function(name, fn) { var suites = [this.suite].concat(this.parents()).reverse(); @@ -4885,7 +5933,7 @@ * * @param {String} name * @param {Function} fn - * @api private + * @private */ Runner.prototype.hookDown = function(name, fn) { var suites = [this.suite].concat(this.parents()); @@ -4897,7 +5945,7 @@ * closest to furthest. * * @return {Array} - * @api private + * @private */ Runner.prototype.parents = function() { var suite = this.suite; @@ -4913,24 +5961,32 @@ * Run the current test and callback `fn(err)`. * * @param {Function} fn - * @api private + * @private */ Runner.prototype.runTest = function(fn) { var self = this; var test = this.test; + if (!test) { + return; + } + + var suite = this.parents().reverse()[0] || this.suite; + if (this.forbidOnly && suite.hasOnly()) { + fn(new Error('`.only` forbidden')); + return; + } if (this.asyncOnly) { test.asyncOnly = true; } - + test.on('error', function(err) { + self.fail(test, err); + }); if (this.allowUncaught) { test.allowUncaught = true; return test.run(fn); } try { - test.on('error', function(err) { - self.fail(test, err); - }); test.run(fn); } catch (err) { fn(err); @@ -4940,7 +5996,7 @@ /** * Run tests in the given `suite` and invoke the callback `fn()` when complete. * - * @api private + * @private * @param {Suite} suite * @param {Function} fn */ @@ -4959,7 +6015,7 @@ if (self.suite) { // call hookUp afterEach - self.hookUp('afterEach', function(err2, errSuite2) { + self.hookUp(HOOK_TYPE_AFTER_EACH, function(err2, errSuite2) { self.suite = orig; // some hooks may fail even now if (err2) { @@ -4978,7 +6034,7 @@ function next(err, errSuite) { // if we bail after first err if (self.failures && suite._bail) { - return fn(); + tests = []; } if (self._abort) { @@ -5020,17 +6076,29 @@ } if (test.isPending()) { - self.emit('pending', test); - self.emit('test end', test); + if (self.forbidPending) { + test.isPending = alwaysFalse; + self.fail(test, new Error('Pending test forbidden')); + delete test.isPending; + } else { + self.emit(constants.EVENT_TEST_PENDING, test); + } + self.emit(constants.EVENT_TEST_END, test); return next(); } // execute test and hook(s) - self.emit('test', self.test = test); - self.hookDown('beforeEach', function(err, errSuite) { - if (suite.isPending()) { - self.emit('pending', test); - self.emit('test end', test); + self.emit(constants.EVENT_TEST_BEGIN, (self.test = test)); + self.hookDown(HOOK_TYPE_BEFORE_EACH, function(err, errSuite) { + if (test.isPending()) { + if (self.forbidPending) { + test.isPending = alwaysFalse; + self.fail(test, new Error('Pending test forbidden')); + delete test.isPending; + } else { + self.emit(constants.EVENT_TEST_PENDING, test); + } + self.emit(constants.EVENT_TEST_END, test); return next(); } if (err) { @@ -5041,33 +6109,37 @@ test = self.test; if (err) { var retry = test.currentRetry(); - if (err instanceof Pending) { + if (err instanceof Pending && self.forbidPending) { + self.fail(test, new Error('Pending test forbidden')); + } else if (err instanceof Pending) { test.pending = true; - self.emit('pending', test); + self.emit(constants.EVENT_TEST_PENDING, test); } else if (retry < test.retries()) { var clonedTest = test.clone(); clonedTest.currentRetry(retry + 1); tests.unshift(clonedTest); + self.emit(constants.EVENT_TEST_RETRY, test, err); + // Early return + hook trigger so that it doesn't // increment the count wrong - return self.hookUp('afterEach', next); + return self.hookUp(HOOK_TYPE_AFTER_EACH, next); } else { self.fail(test, err); } - self.emit('test end', test); + self.emit(constants.EVENT_TEST_END, test); if (err instanceof Pending) { return next(); } - return self.hookUp('afterEach', next); + return self.hookUp(HOOK_TYPE_AFTER_EACH, next); } - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); + test.state = STATE_PASSED; + self.emit(constants.EVENT_TEST_PASS, test); + self.emit(constants.EVENT_TEST_END, test); + self.hookUp(HOOK_TYPE_AFTER_EACH, next); }); }); } @@ -5077,10 +6149,14 @@ next(); }; +function alwaysFalse() { + return false; +} + /** * Run the given `suite` and invoke the callback `fn()` when complete. * - * @api private + * @private * @param {Suite} suite * @param {Function} fn */ @@ -5096,7 +6172,7 @@ return fn(); } - this.emit('suite', this.suite = suite); + this.emit(constants.EVENT_SUITE_BEGIN, (this.suite = suite)); function next(errSuite) { if (errSuite) { @@ -5146,8 +6222,8 @@ // remove reference to test delete self.test; - self.hook('afterAll', function() { - self.emit('suite end', suite); + self.hook(HOOK_TYPE_AFTER_ALL, function() { + self.emit(constants.EVENT_SUITE_END, suite); fn(errSuite); }); } @@ -5155,7 +6231,7 @@ this.nextSuite = next; - this.hook('beforeAll', function(err) { + this.hook(HOOK_TYPE_BEFORE_ALL, function(err) { if (err) { return done(); } @@ -5167,16 +6243,24 @@ * Handle uncaught exceptions. * * @param {Error} err - * @api private + * @private */ Runner.prototype.uncaught = function(err) { + if (err instanceof Pending) { + return; + } if (err) { - debug('uncaught exception %s', err !== function() { - return this; - }.call(err) ? err : (err.message || err)); + debug('uncaught exception %O', err); } else { - debug('uncaught undefined exception'); - err = undefinedError(); + debug('uncaught undefined/falsy exception'); + err = createInvalidExceptionError( + 'Caught falsy/undefined exception which would otherwise be uncaught. No stack trace found; try a debugger', + err + ); + } + + if (!isError(err)) { + err = thrown2Error(err); } err.uncaught = true; @@ -5190,9 +6274,9 @@ this.fail(runnable, err); } else { // Can't recover from this failure - this.emit('start'); + this.emit(constants.EVENT_RUN_BEGIN); this.fail(runnable, err); - this.emit('end'); + this.emit(constants.EVENT_RUN_END); } return; @@ -5200,22 +6284,29 @@ runnable.clearTimeout(); - // Ignore errors if complete - if (runnable.state) { + // Ignore errors if already failed or pending + // See #3226 + if (runnable.isFailed() || runnable.isPending()) { return; } + // we cannot recover gracefully if a Runnable has already passed + // then fails asynchronously + var alreadyPassed = runnable.isPassed(); + // this will change the state to "failed" regardless of the current value this.fail(runnable, err); + if (!alreadyPassed) { + // recover from test + if (runnable.type === constants.EVENT_TEST_BEGIN) { + this.emit(constants.EVENT_TEST_END, runnable); + this.hookUp(HOOK_TYPE_AFTER_EACH, this.next); + return; + } + debug(runnable); - // recover from test - if (runnable.type === 'test') { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // recover from hooks - if (runnable.type === 'hook') { + // recover from hooks var errSuite = this.suite; + + // XXX how about a less awful way to determine this? // if hook failure is in afterEach block if (runnable.fullTitle().indexOf('after each') > -1) { return this.hookErr(err, errSuite, true); @@ -5229,54 +6320,15 @@ } // bail - this.emit('end'); + this.emit(constants.EVENT_RUN_END); }; /** - * Cleans up the references to all the deferred functions - * (before/after/beforeEach/afterEach) and tests of a Suite. - * These must be deleted otherwise a memory leak can happen, - * as those functions may reference variables from closures, - * thus those variables can never be garbage collected as long - * as the deferred functions exist. - * - * @param {Suite} suite - */ -function cleanSuiteReferences(suite) { - function cleanArrReferences(arr) { - for (var i = 0; i < arr.length; i++) { - delete arr[i].fn; - } - } - - if (isArray(suite._beforeAll)) { - cleanArrReferences(suite._beforeAll); - } - - if (isArray(suite._beforeEach)) { - cleanArrReferences(suite._beforeEach); - } - - if (isArray(suite._afterAll)) { - cleanArrReferences(suite._afterAll); - } - - if (isArray(suite._afterEach)) { - cleanArrReferences(suite._afterEach); - } - - for (var i = 0; i < suite.tests.length; i++) { - delete suite.tests[i].fn; - } -} - -/** * Run the root suite and invoke `fn(failures)` * on completion. * - * @param {Function} fn - * @return {Runner} for chaining - * @api public + * @public + * @memberof Runner * @param {Function} fn * @return {Runner} Runner instance. */ @@ -5291,22 +6343,32 @@ } function start() { + // If there is an `only` filter + if (rootSuite.hasOnly()) { + rootSuite.filterOnly(); + } self.started = true; - self.emit('start'); + if (self._delay) { + self.emit(constants.EVENT_DELAY_END); + } + self.emit(constants.EVENT_RUN_BEGIN); + self.runSuite(rootSuite, function() { debug('finished running'); - self.emit('end'); + self.emit(constants.EVENT_RUN_END); }); } - debug('start'); + debug(constants.EVENT_RUN_BEGIN); // references cleanup to avoid memory leaks - this.on('suite end', cleanSuiteReferences); + this.on(constants.EVENT_SUITE_END, function(suite) { + suite.cleanReferences(); + }); // callback - this.on('end', function() { - debug('end'); + this.on(constants.EVENT_RUN_END, function() { + debug(constants.EVENT_RUN_END); process.removeListener('uncaughtException', uncaught); fn(self.failures); }); @@ -5317,8 +6379,8 @@ if (this._delay) { // for reporters, I guess. // might be nice to debounce some dots while we wait. - this.emit('waiting', rootSuite); - rootSuite.once('run', start); + this.emit(constants.EVENT_DELAY_BEGIN, rootSuite); + rootSuite.once(EVENT_ROOT_SUITE_RUN, start); } else { start(); } @@ -5329,7 +6391,8 @@ /** * Cleanly abort execution. * - * @api public + * @memberof Runner + * @public * @return {Runner} Runner instance. */ Runner.prototype.abort = function() { @@ -5342,28 +6405,28 @@ /** * Filter leaks with the given globals flagged as `ok`. * - * @api private + * @private * @param {Array} ok * @param {Array} globals * @return {Array} */ function filterLeaks(ok, globals) { - return filter(globals, function(key) { + return globals.filter(function(key) { // Firefox and Chrome exposes iframes as index inside the window object - if (/^d+/.test(key)) { + if (/^\d+/.test(key)) { return false; } // in firefox - // if runner runs in an iframe, this iframe's window.getInterface method not init at first - // it is assigned in some seconds - if (global.navigator && (/^getInterface/).test(key)) { + // if runner runs in an iframe, this iframe's window.getInterface method + // not init at first it is assigned in some seconds + if (global.navigator && /^getInterface/.test(key)) { return false; } // an iframe could be approached by window[iframeIndex] // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak - if (global.navigator && (/^\d+/).test(key)) { + if (global.navigator && /^\d+/.test(key)) { return false; } @@ -5372,7 +6435,7 @@ return false; } - var matched = filter(ok, function(ok) { + var matched = ok.filter(function(ok) { if (~ok.indexOf('*')) { return key.indexOf(ok.split('*')[0]) === 0; } @@ -5383,21 +6446,48 @@ } /** + * Check if argument is an instance of Error object or a duck-typed equivalent. + * + * @private + * @param {Object} err - object to check + * @param {string} err.message - error message + * @returns {boolean} + */ +function isError(err) { + return err instanceof Error || (err && typeof err.message === 'string'); +} + +/** + * + * Converts thrown non-extensible type into proper Error. + * + * @private + * @param {*} thrown - Non-extensible type thrown by code + * @return {Error} + */ +function thrown2Error(err) { + return new Error( + 'the ' + type(err) + ' ' + stringify(err) + ' was thrown, throw an Error :)' + ); +} + +/** * Array of globals dependent on the environment. * * @return {Array} - * @api private + * @deprecated + * @todo remove; long since unsupported + * @private */ function extraGlobals() { if (typeof process === 'object' && typeof process.version === 'string') { var parts = process.version.split('.'); - var nodeVersion = utils.reduce(parts, function(a, v) { - return a << 8 | v; + var nodeVersion = parts.reduce(function(a, v) { + return (a << 8) | v; }); // 'errno' was renamed to process._errno in v0.9.11. - - if (nodeVersion < 0x00090B) { + if (nodeVersion < 0x00090b) { return ['errno']; } } @@ -5405,18 +6495,116 @@ return []; } +Runner.constants = constants; + +/** + * Node.js' `EventEmitter` + * @external EventEmitter + * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter} + */ + }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./pending":16,"./runnable":35,"./utils":39,"_process":58,"debug":2,"events":3}],37:[function(require,module,exports){ +},{"./errors":6,"./pending":16,"./runnable":33,"./suite":36,"./utils":38,"_process":69,"debug":45,"events":50,"util":89}],35:[function(require,module,exports){ +(function (global){ +'use strict'; + +/** + * Provides a factory function for a {@link StatsCollector} object. + * @module + */ + +var constants = require('./runner').constants; +var EVENT_TEST_PASS = constants.EVENT_TEST_PASS; +var EVENT_TEST_FAIL = constants.EVENT_TEST_FAIL; +var EVENT_SUITE_BEGIN = constants.EVENT_SUITE_BEGIN; +var EVENT_RUN_BEGIN = constants.EVENT_RUN_BEGIN; +var EVENT_TEST_PENDING = constants.EVENT_TEST_PENDING; +var EVENT_RUN_END = constants.EVENT_RUN_END; +var EVENT_TEST_END = constants.EVENT_TEST_END; + +/** + * Test statistics collector. + * + * @public + * @typedef {Object} StatsCollector + * @property {number} suites - integer count of suites run. + * @property {number} tests - integer count of tests run. + * @property {number} passes - integer count of passing tests. + * @property {number} pending - integer count of pending tests. + * @property {number} failures - integer count of failed tests. + * @property {Date} start - time when testing began. + * @property {Date} end - time when testing concluded. + * @property {number} duration - number of msecs that testing took. + */ + +var Date = global.Date; + +/** + * Provides stats such as test duration, number of tests passed / failed etc., by listening for events emitted by `runner`. + * + * @private + * @param {Runner} runner - Runner instance + * @throws {TypeError} If falsy `runner` + */ +function createStatsCollector(runner) { + /** + * @type StatsCollector + */ + var stats = { + suites: 0, + tests: 0, + passes: 0, + pending: 0, + failures: 0 + }; + + if (!runner) { + throw new TypeError('Missing runner argument'); + } + + runner.stats = stats; + + runner.once(EVENT_RUN_BEGIN, function() { + stats.start = new Date(); + }); + runner.on(EVENT_SUITE_BEGIN, function(suite) { + suite.root || stats.suites++; + }); + runner.on(EVENT_TEST_PASS, function() { + stats.passes++; + }); + runner.on(EVENT_TEST_FAIL, function() { + stats.failures++; + }); + runner.on(EVENT_TEST_PENDING, function() { + stats.pending++; + }); + runner.on(EVENT_TEST_END, function() { + stats.tests++; + }); + runner.once(EVENT_RUN_END, function() { + stats.end = new Date(); + stats.duration = stats.end - stats.start; + }); +} + +module.exports = createStatsCollector; + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./runner":34}],36:[function(require,module,exports){ +'use strict'; + /** * Module dependencies. */ - var EventEmitter = require('events').EventEmitter; var Hook = require('./hook'); var utils = require('./utils'); var inherits = utils.inherits; var debug = require('debug')('mocha:suite'); -var milliseconds = require('./ms'); +var milliseconds = require('ms'); +var errors = require('./errors'); +var createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError; /** * Expose `Suite`. @@ -5425,16 +6613,14 @@ exports = module.exports = Suite; /** - * Create a new `Suite` with the given `title` and parent `Suite`. When a suite - * with the same title is already present, that suite is returned to provide - * nicer reporter and more flexible meta-testing. + * Create a new `Suite` with the given `title` and parent `Suite`. * - * @api public - * @param {Suite} parent - * @param {string} title + * @public + * @param {Suite} parent - Parent suite (required!) + * @param {string} title - Title * @return {Suite} */ -exports.create = function(parent, title) { +Suite.create = function(parent, title) { var suite = new Suite(title, parent.ctx); suite.parent = parent; title = suite.fullTitle(); @@ -5443,13 +6629,26 @@ }; /** - * Initialize a new `Suite` with the given `title` and `ctx`. + * Constructs a new `Suite` instance with the given `title`, `ctx`, and `isRoot`. * - * @api private - * @param {string} title - * @param {Context} parentContext + * @public + * @class + * @extends EventEmitter + * @see {@link https://nodejs.org/api/events.html#events_class_eventemitter|EventEmitter} + * @param {string} title - Suite title. + * @param {Context} parentContext - Parent context instance. + * @param {boolean} [isRoot=false] - Whether this is the root suite. */ -function Suite(title, parentContext) { +function Suite(title, parentContext, isRoot) { + if (!utils.isString(title)) { + throw createInvalidArgumentTypeError( + 'Suite argument "title" must be a string. Received type "' + + typeof title + + '"', + 'title', + 'string' + ); + } this.title = title; function Context() {} Context.prototype = parentContext; @@ -5461,13 +6660,25 @@ this._beforeAll = []; this._afterEach = []; this._afterAll = []; - this.root = !title; + this.root = isRoot === true; this._timeout = 2000; this._enableTimeouts = true; this._slow = 75; this._bail = false; this._retries = -1; + this._onlyTests = []; + this._onlySuites = []; this.delayed = false; + + this.on('newListener', function(event) { + if (deprecatedEvents[event]) { + utils.deprecate( + 'Event "' + + event + + '" is deprecated. Please let the Mocha team know about your use case: https://git.io/v6Lwm' + ); + } + }); } /** @@ -5478,13 +6689,14 @@ /** * Return a clone of this `Suite`. * - * @api private + * @private * @return {Suite} */ Suite.prototype.clone = function() { var suite = new Suite(this.title); debug('clone'); suite.ctx = this.ctx; + suite.root = this.root; suite.timeout(this.timeout()); suite.retries(this.retries()); suite.enableTimeouts(this.enableTimeouts()); @@ -5494,9 +6706,10 @@ }; /** - * Set timeout `ms` or short-hand such as "2s". + * Set or get timeout `ms` or short-hand such as "2s". * - * @api private + * @private + * @todo Do not attempt to set value if `ms` is undefined * @param {number|string} ms * @return {Suite|number} for chaining */ @@ -5516,9 +6729,9 @@ }; /** - * Set number of times to retry a failed test. + * Set or get number of times to retry a failed test. * - * @api private + * @private * @param {number|string} n * @return {Suite|number} for chaining */ @@ -5532,12 +6745,12 @@ }; /** - * Set timeout to `enabled`. - * - * @api private - * @param {boolean} enabled - * @return {Suite|boolean} self or enabled - */ + * Set or get timeout to `enabled`. + * + * @private + * @param {boolean} enabled + * @return {Suite|boolean} self or enabled + */ Suite.prototype.enableTimeouts = function(enabled) { if (!arguments.length) { return this._enableTimeouts; @@ -5548,9 +6761,9 @@ }; /** - * Set slow `ms` or short-hand such as "2s". + * Set or get slow `ms` or short-hand such as "2s". * - * @api private + * @private * @param {number|string} ms * @return {Suite|number} for chaining */ @@ -5567,9 +6780,9 @@ }; /** - * Sets whether to bail after first error. + * Set or get whether to bail after first error. * - * @api private + * @private * @param {boolean} bail * @return {Suite|number} for chaining */ @@ -5585,16 +6798,35 @@ /** * Check if this suite or its parent suite is marked as pending. * - * @api private + * @private */ Suite.prototype.isPending = function() { return this.pending || (this.parent && this.parent.isPending()); }; /** + * Generic hook-creator. + * @private + * @param {string} title - Title of hook + * @param {Function} fn - Hook callback + * @returns {Hook} A new hook + */ +Suite.prototype._createHook = function(title, fn) { + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.retries(this.retries()); + hook.enableTimeouts(this.enableTimeouts()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + hook.file = this.file; + return hook; +}; + +/** * Run `fn(test[, done])` before running tests. * - * @api private + * @private * @param {string} title * @param {Function} fn * @return {Suite} for chaining @@ -5609,22 +6841,16 @@ } title = '"before all" hook' + (title ? ': ' + title : ''); - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; + var hook = this._createHook(title, fn); this._beforeAll.push(hook); - this.emit('beforeAll', hook); + this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_ALL, hook); return this; }; /** * Run `fn(test[, done])` after running tests. * - * @api private + * @private * @param {string} title * @param {Function} fn * @return {Suite} for chaining @@ -5639,22 +6865,16 @@ } title = '"after all" hook' + (title ? ': ' + title : ''); - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; + var hook = this._createHook(title, fn); this._afterAll.push(hook); - this.emit('afterAll', hook); + this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_ALL, hook); return this; }; /** * Run `fn(test[, done])` before each test case. * - * @api private + * @private * @param {string} title * @param {Function} fn * @return {Suite} for chaining @@ -5669,22 +6889,16 @@ } title = '"before each" hook' + (title ? ': ' + title : ''); - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; + var hook = this._createHook(title, fn); this._beforeEach.push(hook); - this.emit('beforeEach', hook); + this.emit(constants.EVENT_SUITE_ADD_HOOK_BEFORE_EACH, hook); return this; }; /** * Run `fn(test[, done])` after each test case. * - * @api private + * @private * @param {string} title * @param {Function} fn * @return {Suite} for chaining @@ -5699,41 +6913,36 @@ } title = '"after each" hook' + (title ? ': ' + title : ''); - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.retries(this.retries()); - hook.enableTimeouts(this.enableTimeouts()); - hook.slow(this.slow()); - hook.ctx = this.ctx; + var hook = this._createHook(title, fn); this._afterEach.push(hook); - this.emit('afterEach', hook); + this.emit(constants.EVENT_SUITE_ADD_HOOK_AFTER_EACH, hook); return this; }; /** * Add a test `suite`. * - * @api private + * @private * @param {Suite} suite * @return {Suite} for chaining */ Suite.prototype.addSuite = function(suite) { suite.parent = this; + suite.root = false; suite.timeout(this.timeout()); suite.retries(this.retries()); suite.enableTimeouts(this.enableTimeouts()); suite.slow(this.slow()); suite.bail(this.bail()); this.suites.push(suite); - this.emit('suite', suite); + this.emit(constants.EVENT_SUITE_ADD_SUITE, suite); return this; }; /** * Add a `test` to this suite. * - * @api private + * @private * @param {Test} test * @return {Suite} for chaining */ @@ -5745,7 +6954,7 @@ test.slow(this.slow()); test.ctx = this.ctx; this.tests.push(test); - this.emit('test', test); + this.emit(constants.EVENT_SUITE_ADD_TEST, test); return this; }; @@ -5753,42 +6962,59 @@ * Return the full title generated by recursively concatenating the parent's * full title. * - * @api public + * @memberof Suite + * @public * @return {string} */ Suite.prototype.fullTitle = function() { + return this.titlePath().join(' '); +}; + +/** + * Return the title path generated by recursively concatenating the parent's + * title path. + * + * @memberof Suite + * @public + * @return {string} + */ +Suite.prototype.titlePath = function() { + var result = []; if (this.parent) { - var full = this.parent.fullTitle(); - if (full) { - return full + ' ' + this.title; - } + result = result.concat(this.parent.titlePath()); } - return this.title; + if (!this.root) { + result.push(this.title); + } + return result; }; /** * Return the total number of tests. * - * @api public + * @memberof Suite + * @public * @return {number} */ Suite.prototype.total = function() { - return utils.reduce(this.suites, function(sum, suite) { - return sum + suite.total(); - }, 0) + this.tests.length; + return ( + this.suites.reduce(function(sum, suite) { + return sum + suite.total(); + }, 0) + this.tests.length + ); }; /** * Iterates through each suite recursively to find all tests. Applies a * function in the format `fn(test)`. * - * @api private + * @private * @param {Function} fn * @return {Suite} */ Suite.prototype.eachTest = function(fn) { - utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite) { + this.tests.forEach(fn); + this.suites.forEach(function(suite) { suite.eachTest(fn); }); return this; @@ -5796,35 +7022,248 @@ /** * This will run the root suite if we happen to be running in delayed mode. + * @private */ Suite.prototype.run = function run() { if (this.root) { - this.emit('run'); + this.emit(constants.EVENT_ROOT_SUITE_RUN); } }; -},{"./hook":7,"./ms":15,"./utils":39,"debug":2,"events":3}],38:[function(require,module,exports){ /** - * Module dependencies. + * Determines whether a suite has an `only` test or suite as a descendant. + * + * @private + * @returns {Boolean} */ +Suite.prototype.hasOnly = function hasOnly() { + return ( + this._onlyTests.length > 0 || + this._onlySuites.length > 0 || + this.suites.some(function(suite) { + return suite.hasOnly(); + }) + ); +}; +/** + * Filter suites based on `isOnly` logic. + * + * @private + * @returns {Boolean} + */ +Suite.prototype.filterOnly = function filterOnly() { + if (this._onlyTests.length) { + // If the suite contains `only` tests, run those and ignore any nested suites. + this.tests = this._onlyTests; + this.suites = []; + } else { + // Otherwise, do not run any of the tests in this suite. + this.tests = []; + this._onlySuites.forEach(function(onlySuite) { + // If there are other `only` tests/suites nested in the current `only` suite, then filter that `only` suite. + // Otherwise, all of the tests on this `only` suite should be run, so don't filter it. + if (onlySuite.hasOnly()) { + onlySuite.filterOnly(); + } + }); + // Run the `only` suites, as well as any other suites that have `only` tests/suites as descendants. + var onlySuites = this._onlySuites; + this.suites = this.suites.filter(function(childSuite) { + return onlySuites.indexOf(childSuite) !== -1 || childSuite.filterOnly(); + }); + } + // Keep the suite only if there is something to run + return this.tests.length > 0 || this.suites.length > 0; +}; + +/** + * Adds a suite to the list of subsuites marked `only`. + * + * @private + * @param {Suite} suite + */ +Suite.prototype.appendOnlySuite = function(suite) { + this._onlySuites.push(suite); +}; + +/** + * Adds a test to the list of tests marked `only`. + * + * @private + * @param {Test} test + */ +Suite.prototype.appendOnlyTest = function(test) { + this._onlyTests.push(test); +}; + +/** + * Returns the array of hooks by hook name; see `HOOK_TYPE_*` constants. + * @private + */ +Suite.prototype.getHooks = function getHooks(name) { + return this['_' + name]; +}; + +/** + * Cleans up the references to all the deferred functions + * (before/after/beforeEach/afterEach) and tests of a Suite. + * These must be deleted otherwise a memory leak can happen, + * as those functions may reference variables from closures, + * thus those variables can never be garbage collected as long + * as the deferred functions exist. + * + * @private + */ +Suite.prototype.cleanReferences = function cleanReferences() { + function cleanArrReferences(arr) { + for (var i = 0; i < arr.length; i++) { + delete arr[i].fn; + } + } + + if (Array.isArray(this._beforeAll)) { + cleanArrReferences(this._beforeAll); + } + + if (Array.isArray(this._beforeEach)) { + cleanArrReferences(this._beforeEach); + } + + if (Array.isArray(this._afterAll)) { + cleanArrReferences(this._afterAll); + } + + if (Array.isArray(this._afterEach)) { + cleanArrReferences(this._afterEach); + } + + for (var i = 0; i < this.tests.length; i++) { + delete this.tests[i].fn; + } +}; + +var constants = utils.defineConstants( + /** + * {@link Suite}-related constants. + * @public + * @memberof Suite + * @alias constants + * @readonly + * @static + * @enum {string} + */ + { + /** + * Event emitted after a test file has been loaded Not emitted in browser. + */ + EVENT_FILE_POST_REQUIRE: 'post-require', + /** + * Event emitted before a test file has been loaded. In browser, this is emitted once an interface has been selected. + */ + EVENT_FILE_PRE_REQUIRE: 'pre-require', + /** + * Event emitted immediately after a test file has been loaded. Not emitted in browser. + */ + EVENT_FILE_REQUIRE: 'require', + /** + * Event emitted when `global.run()` is called (use with `delay` option) + */ + EVENT_ROOT_SUITE_RUN: 'run', + + /** + * Namespace for collection of a `Suite`'s "after all" hooks + */ + HOOK_TYPE_AFTER_ALL: 'afterAll', + /** + * Namespace for collection of a `Suite`'s "after each" hooks + */ + HOOK_TYPE_AFTER_EACH: 'afterEach', + /** + * Namespace for collection of a `Suite`'s "before all" hooks + */ + HOOK_TYPE_BEFORE_ALL: 'beforeAll', + /** + * Namespace for collection of a `Suite`'s "before all" hooks + */ + HOOK_TYPE_BEFORE_EACH: 'beforeEach', + + // the following events are all deprecated + + /** + * Emitted after an "after all" `Hook` has been added to a `Suite`. Deprecated + */ + EVENT_SUITE_ADD_HOOK_AFTER_ALL: 'afterAll', + /** + * Emitted after an "after each" `Hook` has been added to a `Suite` Deprecated + */ + EVENT_SUITE_ADD_HOOK_AFTER_EACH: 'afterEach', + /** + * Emitted after an "before all" `Hook` has been added to a `Suite` Deprecated + */ + EVENT_SUITE_ADD_HOOK_BEFORE_ALL: 'beforeAll', + /** + * Emitted after an "before each" `Hook` has been added to a `Suite` Deprecated + */ + EVENT_SUITE_ADD_HOOK_BEFORE_EACH: 'beforeEach', + /** + * Emitted after a child `Suite` has been added to a `Suite`. Deprecated + */ + EVENT_SUITE_ADD_SUITE: 'suite', + /** + * Emitted after a `Test` has been added to a `Suite`. Deprecated + */ + EVENT_SUITE_ADD_TEST: 'test' + } +); + +/** + * @summary There are no known use cases for these events. + * @desc This is a `Set`-like object having all keys being the constant's string value and the value being `true`. + * @todo Remove eventually + * @type {Object<string,boolean>} + * @ignore + */ +var deprecatedEvents = Object.keys(constants) + .filter(function(constant) { + return constant.substring(0, 15) === 'EVENT_SUITE_ADD'; + }) + .reduce(function(acc, constant) { + acc[constants[constant]] = true; + return acc; + }, utils.createMap()); + +Suite.constants = constants; + +},{"./errors":6,"./hook":7,"./utils":38,"debug":45,"events":50,"ms":60}],37:[function(require,module,exports){ +'use strict'; var Runnable = require('./runnable'); -var inherits = require('./utils').inherits; - -/** - * Expose `Test`. - */ +var utils = require('./utils'); +var errors = require('./errors'); +var createInvalidArgumentTypeError = errors.createInvalidArgumentTypeError; +var isString = utils.isString; module.exports = Test; /** * Initialize a new `Test` with the given `title` and callback `fn`. * - * @api private - * @param {String} title - * @param {Function} fn + * @public + * @class + * @extends Runnable + * @param {String} title - Test title (required) + * @param {Function} [fn] - Test callback. If omitted, the Test is considered "pending" */ function Test(title, fn) { + if (!isString(title)) { + throw createInvalidArgumentTypeError( + 'Test argument "title" should be a string. Received type "' + + typeof title + + '"', + 'title', + 'string' + ); + } Runnable.call(this, title, fn); this.pending = !fn; this.type = 'test'; @@ -5833,7 +7272,7 @@ /** * Inherit from `Runnable.prototype`. */ -inherits(Test, Runnable); +utils.inherits(Test, Runnable); Test.prototype.clone = function() { var test = new Test(this.title, this.fn); @@ -5849,65 +7288,56 @@ return test; }; -},{"./runnable":35,"./utils":39}],39:[function(require,module,exports){ +},{"./errors":6,"./runnable":33,"./utils":38}],38:[function(require,module,exports){ (function (process,Buffer){ -/* eslint-env browser */ +'use strict'; + +/** + * Various utility functions used throughout Mocha's codebase. + * @module utils + */ /** * Module dependencies. */ -var basename = require('path').basename; -var debug = require('debug')('mocha:watch'); -var exists = require('fs').existsSync || require('path').existsSync; +var fs = require('fs'); +var path = require('path'); +var util = require('util'); var glob = require('glob'); -var join = require('path').join; -var readdirSync = require('fs').readdirSync; -var statSync = require('fs').statSync; -var watchFile = require('fs').watchFile; -var toISOString = require('to-iso-string'); +var he = require('he'); +var errors = require('./errors'); +var createNoFilesMatchPatternError = errors.createNoFilesMatchPatternError; +var createMissingArgumentError = errors.createMissingArgumentError; + +var assign = (exports.assign = require('object.assign').getPolyfill()); /** - * Ignored directories. + * Inherit the prototype methods from one constructor into another. + * + * @param {function} ctor - Constructor function which needs to inherit the + * prototype. + * @param {function} superCtor - Constructor function to inherit prototype from. + * @throws {TypeError} if either constructor is null, or if super constructor + * lacks a prototype. */ - -var ignore = ['node_modules', '.git']; - -exports.inherits = require('util').inherits; +exports.inherits = util.inherits; /** * Escape special characters in the given string of html. * - * @api private + * @private * @param {string} html * @return {string} */ exports.escape = function(html) { - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(/</g, '<') - .replace(/>/g, '>'); -}; - -/** - * Array#forEach (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} scope - */ -exports.forEach = function(arr, fn, scope) { - for (var i = 0, l = arr.length; i < l; i++) { - fn.call(scope, arr[i], i); - } + return he.encode(String(html), {useNamedReferences: false}); }; /** * Test if the given obj is type of string. * - * @api private + * @private * @param {Object} obj * @return {boolean} */ @@ -5916,113 +7346,19 @@ }; /** - * Array#map (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} scope - * @return {Array} - */ -exports.map = function(arr, fn, scope) { - var result = []; - for (var i = 0, l = arr.length; i < l; i++) { - result.push(fn.call(scope, arr[i], i, arr)); - } - return result; -}; - -/** - * Array#indexOf (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Object} obj to find index of - * @param {number} start - * @return {number} - */ -exports.indexOf = function(arr, obj, start) { - for (var i = start || 0, l = arr.length; i < l; i++) { - if (arr[i] === obj) { - return i; - } - } - return -1; -}; - -/** - * Array#reduce (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @param {Object} val Initial value. - * @return {*} - */ -exports.reduce = function(arr, fn, val) { - var rval = val; - - for (var i = 0, l = arr.length; i < l; i++) { - rval = fn(rval, arr[i], i, arr); - } - - return rval; -}; - -/** - * Array#filter (<=IE8) - * - * @api private - * @param {Array} arr - * @param {Function} fn - * @return {Array} - */ -exports.filter = function(arr, fn) { - var ret = []; - - for (var i = 0, l = arr.length; i < l; i++) { - var val = arr[i]; - if (fn(val, i, arr)) { - ret.push(val); - } - } - - return ret; -}; - -/** - * Object.keys (<=IE8) - * - * @api private - * @param {Object} obj - * @return {Array} keys - */ -exports.keys = typeof Object.keys === 'function' ? Object.keys : function(obj) { - var keys = []; - var has = Object.prototype.hasOwnProperty; // for `window` on <=IE8 - - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - - return keys; -}; - -/** * Watch the given `files` for changes * and invoke `fn(file)` on modification. * - * @api private + * @private * @param {Array} files * @param {Function} fn */ exports.watch = function(files, fn) { - var options = { interval: 100 }; + var options = {interval: 100}; + var debug = require('debug')('mocha:watch'); files.forEach(function(file) { debug('file %s', file); - watchFile(file, options, function(curr, prev) { + fs.watchFile(file, options, function(curr, prev) { if (prev.mtime < curr.mtime) { fn(file); } @@ -6031,63 +7367,52 @@ }; /** - * Array.isArray (<=IE8) + * Predicate to screen `pathname` for further consideration. * - * @api private - * @param {Object} obj - * @return {Boolean} - */ -var isArray = typeof Array.isArray === 'function' ? Array.isArray : function(obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; -}; - -exports.isArray = isArray; - -/** - * Buffer.prototype.toJSON polyfill. + * @description + * Returns <code>false</code> for pathname referencing: + * <ul> + * <li>'npm' package installation directory + * <li>'git' version control directory + * </ul> * - * @type {Function} + * @private + * @param {string} pathname - File or directory name to screen + * @return {boolean} whether pathname should be further considered + * @example + * ['node_modules', 'test.js'].filter(considerFurther); // => ['test.js'] */ -if (typeof Buffer !== 'undefined' && Buffer.prototype) { - Buffer.prototype.toJSON = Buffer.prototype.toJSON || function() { - return Array.prototype.slice.call(this, 0); - }; -} +function considerFurther(pathname) { + var ignore = ['node_modules', '.git']; -/** - * Ignored files. - * - * @api private - * @param {string} path - * @return {boolean} - */ -function ignored(path) { - return !~ignore.indexOf(path); + return !~ignore.indexOf(pathname); } /** * Lookup files in the given `dir`. * - * @api private + * @description + * Filenames are returned in _traversal_ order by the OS/filesystem. + * **Make no assumption that the names will be sorted in any fashion.** + * + * @private * @param {string} dir - * @param {string[]} [ext=['.js']] + * @param {string[]} [exts=['js']] * @param {Array} [ret=[]] * @return {Array} */ -exports.files = function(dir, ext, ret) { +exports.files = function(dir, exts, ret) { ret = ret || []; - ext = ext || ['js']; + exts = exts || ['js']; - var re = new RegExp('\\.(' + ext.join('|') + ')$'); - - readdirSync(dir) - .filter(ignored) - .forEach(function(path) { - path = join(dir, path); - if (statSync(path).isDirectory()) { - exports.files(path, ext, ret); - } else if (path.match(re)) { - ret.push(path); + fs.readdirSync(dir) + .filter(considerFurther) + .forEach(function(dirent) { + var pathname = path.join(dir, dirent); + if (fs.lstatSync(pathname).isDirectory()) { + exports.files(pathname, exts, ret); + } else if (hasMatchingExtname(pathname, exts)) { + ret.push(pathname); } }); @@ -6097,7 +7422,7 @@ /** * Compute a slug from the given `str`. * - * @api private + * @private * @param {string} str * @return {string} */ @@ -6116,52 +7441,53 @@ */ exports.clean = function(str) { str = str - .replace(/\r\n?|[\n\u2028\u2029]/g, '\n').replace(/^\uFEFF/, '') - .replace(/^function *\(.*\)\s*\{|\(.*\) *=> *\{?/, '') - .replace(/\s+\}$/, ''); + .replace(/\r\n?|[\n\u2028\u2029]/g, '\n') + .replace(/^\uFEFF/, '') + // (traditional)-> space/name parameters body (lambda)-> parameters body multi-statement/single keep body content + .replace( + /^function(?:\s*|\s+[^(]*)\([^)]*\)\s*\{((?:.|\n)*?)\s*\}$|^\([^)]*\)\s*=>\s*(?:\{((?:.|\n)*?)\s*\}|((?:.|\n)*))$/, + '$1$2$3' + ); var spaces = str.match(/^\n?( *)/)[1].length; var tabs = str.match(/^\n?(\t*)/)[1].length; - var re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); + var re = new RegExp( + '^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs || spaces) + '}', + 'gm' + ); str = str.replace(re, ''); - return exports.trim(str); -}; - -/** - * Trim the given `str`. - * - * @api private - * @param {string} str - * @return {string} - */ -exports.trim = function(str) { - return str.replace(/^\s+|\s+$/g, ''); + return str.trim(); }; /** * Parse the given `qs`. * - * @api private + * @private * @param {string} qs * @return {Object} */ exports.parseQuery = function(qs) { - return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair) { - var i = pair.indexOf('='); - var key = pair.slice(0, i); - var val = pair.slice(++i); + return qs + .replace('?', '') + .split('&') + .reduce(function(obj, pair) { + var i = pair.indexOf('='); + var key = pair.slice(0, i); + var val = pair.slice(++i); - obj[key] = decodeURIComponent(val); - return obj; - }, {}); + // Due to how the URLSearchParams API treats spaces + obj[key] = decodeURIComponent(val.replace(/\+/g, '%20')); + + return obj; + }, {}); }; /** * Highlight the given string of `js`. * - * @api private + * @private * @param {string} js * @return {string} */ @@ -6173,14 +7499,20 @@ .replace(/('.*?')/gm, '<span class="string">$1</span>') .replace(/(\d+\.\d+)/gm, '<span class="number">$1</span>') .replace(/(\d+)/gm, '<span class="number">$1</span>') - .replace(/\bnew[ \t]+(\w+)/gm, '<span class="keyword">new</span> <span class="init">$1</span>') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '<span class="keyword">$1</span>'); + .replace( + /\bnew[ \t]+(\w+)/gm, + '<span class="keyword">new</span> <span class="init">$1</span>' + ) + .replace( + /\b(function|new|throw|return|var|if|else)\b/gm, + '<span class="keyword">$1</span>' + ); } /** * Highlight the contents of tag `name`. * - * @api private + * @private * @param {string} name */ exports.highlightTags = function(name) { @@ -6199,15 +7531,13 @@ * Objects w/ no properties return `'{}'` * All else: return result of `value.toString()` * - * @api private + * @private * @param {*} value The value to inspect. - * @param {string} [type] The type of the value, if known. + * @param {string} typeHint The type of the value * @returns {string} */ -function emptyRepresentation(value, type) { - type = type || exports.type(value); - - switch (type) { +function emptyRepresentation(value, typeHint) { + switch (typeHint) { case 'function': return '[Function]'; case 'object': @@ -6223,10 +7553,10 @@ * Takes some variable and asks `Object.prototype.toString()` what it thinks it * is. * - * @api private + * @private * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString * @param {*} value The value to test. - * @returns {string} + * @returns {string} Computed type * @example * type({}) // 'object' * type([]) // 'array' @@ -6238,19 +7568,21 @@ * type(/foo/) // 'regexp' * type('type') // 'string' * type(global) // 'global' + * type(new String('foo') // 'object' */ -exports.type = function type(value) { +var type = (exports.type = function type(value) { if (value === undefined) { return 'undefined'; } else if (value === null) { return 'null'; - } else if (typeof Buffer !== 'undefined' && Buffer.isBuffer(value)) { + } else if (Buffer.isBuffer(value)) { return 'buffer'; } - return Object.prototype.toString.call(value) - .replace(/^\[.+\s(.+?)\]$/, '$1') + return Object.prototype.toString + .call(value) + .replace(/^\[.+\s(.+?)]$/, '$1') .toLowerCase(); -}; +}); /** * Stringify `value`. Different behavior depending on type of value: @@ -6262,37 +7594,53 @@ * - If `value` has properties, call {@link exports.canonicalize} on it, then return result of * JSON.stringify(). * - * @api private + * @private * @see exports.type * @param {*} value * @return {string} */ exports.stringify = function(value) { - var type = exports.type(value); + var typeHint = type(value); - if (!~exports.indexOf(['object', 'array', 'function'], type)) { - if (type !== 'buffer') { + if (!~['object', 'array', 'function'].indexOf(typeHint)) { + if (typeHint === 'buffer') { + var json = Buffer.prototype.toJSON.call(value); + // Based on the toJSON result + return jsonStringify( + json.data && json.type ? json.data : json, + 2 + ).replace(/,(\n|$)/g, '$1'); + } + + // IE7/IE8 has a bizarre String constructor; needs to be coerced + // into an array and back to obj. + if (typeHint === 'string' && typeof value === 'object') { + value = value.split('').reduce(function(acc, char, idx) { + acc[idx] = char; + return acc; + }, {}); + typeHint = 'object'; + } else { return jsonStringify(value); } - var json = value.toJSON(); - // Based on the toJSON result - return jsonStringify(json.data && json.type ? json.data : json, 2) - .replace(/,(\n|$)/g, '$1'); } for (var prop in value) { if (Object.prototype.hasOwnProperty.call(value, prop)) { - return jsonStringify(exports.canonicalize(value), 2).replace(/,(\n|$)/g, '$1'); + return jsonStringify( + exports.canonicalize(value, null, typeHint), + 2 + ).replace(/,(\n|$)/g, '$1'); } } - return emptyRepresentation(value, type); + return emptyRepresentation(value, typeHint); }; /** * like JSON.stringify but more sense. * - * @api private + * @private * @param {Object} object * @param {number=} spaces * @param {number=} depth @@ -6306,16 +7654,19 @@ depth = depth || 1; var space = spaces * depth; - var str = isArray(object) ? '[' : '{'; - var end = isArray(object) ? ']' : '}'; - var length = typeof object.length === 'number' ? object.length : exports.keys(object).length; + var str = Array.isArray(object) ? '[' : '{'; + var end = Array.isArray(object) ? ']' : '}'; + var length = + typeof object.length === 'number' + ? object.length + : Object.keys(object).length; // `.repeat()` polyfill function repeat(s, n) { return new Array(n).join(s); } function _stringify(val) { - switch (exports.type(val)) { + switch (type(val)) { case 'null': case 'undefined': val = '[' + val + ']'; @@ -6328,17 +7679,13 @@ case 'regexp': case 'symbol': case 'number': - val = val === 0 && (1 / val) === -Infinity // `-0` - ? '-0' - : val.toString(); + val = + val === 0 && 1 / val === -Infinity // `-0` + ? '-0' + : val.toString(); break; case 'date': - var sDate; - if (isNaN(val.getTime())) { // Invalid date - sDate = val.toString(); - } else { - sDate = val.toISOString ? val.toISOString() : toISOString(val); - } + var sDate = isNaN(val.getTime()) ? val.toString() : val.toISOString(); val = '[Date: ' + sDate + ']'; break; case 'buffer': @@ -6348,9 +7695,10 @@ val = '[Buffer: ' + jsonStringify(json, 2, depth + 1) + ']'; break; default: - val = (val === '[Function]' || val === '[Circular]') - ? val - : JSON.stringify(val); // string + val = + val === '[Function]' || val === '[Circular]' + ? val + : JSON.stringify(val); // string } return val; } @@ -6360,29 +7708,22 @@ continue; // not my business } --length; - str += '\n ' + repeat(' ', space) - + (isArray(object) ? '' : '"' + i + '": ') // key - + _stringify(object[i]) // value - + (length ? ',' : ''); // comma + str += + '\n ' + + repeat(' ', space) + + (Array.isArray(object) ? '' : '"' + i + '": ') + // key + _stringify(object[i]) + // value + (length ? ',' : ''); // comma } - return str + return ( + str + // [], {} - + (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end); + (str.length !== 1 ? '\n' + repeat(' ', --space) + end : end) + ); } /** - * Test if a value is a buffer. - * - * @api private - * @param {*} value The value to test. - * @return {boolean} True if `value` is a buffer, otherwise false - */ -exports.isBuffer = function(value) { - return typeof Buffer !== 'undefined' && Buffer.isBuffer(value); -}; - -/** * Return a new Thing that has the keys in sorted order. Recursive. * * If the Thing... @@ -6394,18 +7735,19 @@ * - is a non-empty `Array`, `Object`, or `Function`, return the result of calling this function again. * - is an empty `Array`, `Object`, or `Function`, return the result of calling `emptyRepresentation()` * - * @api private + * @private * @see {@link exports.stringify} * @param {*} value Thing to inspect. May or may not have properties. * @param {Array} [stack=[]] Stack of seen values + * @param {string} [typeHint] Type hint * @return {(Object|Array|Function|string|undefined)} */ -exports.canonicalize = function(value, stack) { +exports.canonicalize = function canonicalize(value, stack, typeHint) { var canonicalizedObj; /* eslint-disable no-unused-vars */ var prop; /* eslint-enable no-unused-vars */ - var type = exports.type(value); + typeHint = typeHint || type(value); function withStack(value, fn) { stack.push(value); fn(); @@ -6414,11 +7756,11 @@ stack = stack || []; - if (exports.indexOf(stack, value) !== -1) { + if (stack.indexOf(value) !== -1) { return '[Circular]'; } - switch (type) { + switch (typeHint) { case 'undefined': case 'buffer': case 'null': @@ -6426,7 +7768,7 @@ break; case 'array': withStack(value, function() { - canonicalizedObj = exports.map(value, function(item) { + canonicalizedObj = value.map(function(item) { return exports.canonicalize(item, stack); }); }); @@ -6439,16 +7781,18 @@ } /* eslint-enable guard-for-in */ if (!canonicalizedObj) { - canonicalizedObj = emptyRepresentation(value, type); + canonicalizedObj = emptyRepresentation(value, typeHint); break; } /* falls through */ case 'object': canonicalizedObj = canonicalizedObj || {}; withStack(value, function() { - exports.forEach(exports.keys(value).sort(), function(key) { - canonicalizedObj[key] = exports.canonicalize(value[key], stack); - }); + Object.keys(value) + .sort() + .forEach(function(key) { + canonicalizedObj[key] = exports.canonicalize(value[key], stack); + }); }); break; case 'date': @@ -6466,47 +7810,99 @@ }; /** + * Determines if pathname has a matching file extension. + * + * @private + * @param {string} pathname - Pathname to check for match. + * @param {string[]} exts - List of file extensions (sans period). + * @return {boolean} whether file extension matches. + * @example + * hasMatchingExtname('foo.html', ['js', 'css']); // => false + */ +function hasMatchingExtname(pathname, exts) { + var suffix = path.extname(pathname).slice(1); + return exts.some(function(element) { + return suffix === element; + }); +} + +/** + * Determines if pathname would be a "hidden" file (or directory) on UN*X. + * + * @description + * On UN*X, pathnames beginning with a full stop (aka dot) are hidden during + * typical usage. Dotfiles, plain-text configuration files, are prime examples. + * + * @see {@link http://xahlee.info/UnixResource_dir/writ/unix_origin_of_dot_filename.html|Origin of Dot File Names} + * + * @private + * @param {string} pathname - Pathname to check for match. + * @return {boolean} whether pathname would be considered a hidden file. + * @example + * isHiddenOnUnix('.profile'); // => true + */ +function isHiddenOnUnix(pathname) { + return path.basename(pathname)[0] === '.'; +} + +/** * Lookup file names at the given `path`. * - * @api public - * @param {string} path Base path to start searching from. - * @param {string[]} extensions File extensions to look for. - * @param {boolean} recursive Whether or not to recurse into subdirectories. + * @description + * Filenames are returned in _traversal_ order by the OS/filesystem. + * **Make no assumption that the names will be sorted in any fashion.** + * + * @public + * @memberof Mocha.utils + * @todo Fix extension handling + * @param {string} filepath - Base path to start searching from. + * @param {string[]} extensions - File extensions to look for. + * @param {boolean} recursive - Whether to recurse into subdirectories. * @return {string[]} An array of paths. + * @throws {Error} if no files match pattern. + * @throws {TypeError} if `filepath` is directory and `extensions` not provided. */ -exports.lookupFiles = function lookupFiles(path, extensions, recursive) { +exports.lookupFiles = function lookupFiles(filepath, extensions, recursive) { var files = []; - var re = new RegExp('\\.(' + extensions.join('|') + ')$'); + var stat; - if (!exists(path)) { - if (exists(path + '.js')) { - path += '.js'; + if (!fs.existsSync(filepath)) { + if (fs.existsSync(filepath + '.js')) { + filepath += '.js'; } else { - files = glob.sync(path); + // Handle glob + files = glob.sync(filepath); if (!files.length) { - throw new Error("cannot resolve path (or pattern) '" + path + "'"); + throw createNoFilesMatchPatternError( + 'Cannot find any files matching pattern ' + exports.dQuote(filepath), + filepath + ); } return files; } } + // Handle file try { - var stat = statSync(path); + stat = fs.statSync(filepath); if (stat.isFile()) { - return path; + return filepath; } } catch (err) { // ignore error return; } - readdirSync(path).forEach(function(file) { - file = join(path, file); + // Handle directory + fs.readdirSync(filepath).forEach(function(dirent) { + var pathname = path.join(filepath, dirent); + var stat; + try { - var stat = statSync(file); + stat = fs.statSync(pathname); if (stat.isDirectory()) { if (recursive) { - files = files.concat(lookupFiles(file, extensions, recursive)); + files = files.concat(lookupFiles(pathname, extensions, recursive)); } return; } @@ -6514,34 +7910,73 @@ // ignore error return; } - if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') { + if (!extensions) { + throw createMissingArgumentError( + util.format( + 'Argument %s required when argument %s is a directory', + exports.sQuote('extensions'), + exports.sQuote('filepath') + ), + 'extensions', + 'array' + ); + } + + if ( + !stat.isFile() || + !hasMatchingExtname(pathname, extensions) || + isHiddenOnUnix(pathname) + ) { return; } - files.push(file); + files.push(pathname); }); return files; }; /** - * Generate an undefined error with a message warning the user. - * - * @return {Error} + * process.emitWarning or a polyfill + * @see https://nodejs.org/api/process.html#process_process_emitwarning_warning_options + * @ignore */ - -exports.undefinedError = function() { - return new Error('Caught undefined error, did you throw without specifying what?'); -}; +function emitWarning(msg, type) { + if (process.emitWarning) { + process.emitWarning(msg, type); + } else { + process.nextTick(function() { + console.warn(type + ': ' + msg); + }); + } +} /** - * Generate an undefined error if `err` is not defined. + * Show a deprecation warning. Each distinct message is only displayed once. + * Ignores empty messages. * - * @param {Error} err - * @return {Error} + * @param {string} [msg] - Warning to print + * @private */ +exports.deprecate = function deprecate(msg) { + msg = String(msg); + if (msg && !deprecate.cache[msg]) { + deprecate.cache[msg] = true; + emitWarning(msg, 'DeprecationWarning'); + } +}; +exports.deprecate.cache = {}; -exports.getError = function(err) { - return err || exports.undefinedError(); +/** + * Show a generic warning. + * Ignores empty messages. + * + * @param {string} [msg] - Warning to print + * @private + */ +exports.warn = function warn(msg) { + if (msg) { + emitWarning(msg); + } }; /** @@ -6555,32 +7990,41 @@ */ exports.stackTraceFilter = function() { // TODO: Replace with `process.browser` - var slash = '/'; - var is = typeof document === 'undefined' ? { node: true } : { browser: true }; - var cwd = is.node - ? process.cwd() + slash - : (typeof location === 'undefined' ? window.location : location).href.replace(/\/[^\/]*$/, '/'); + var is = typeof document === 'undefined' ? {node: true} : {browser: true}; + var slash = path.sep; + var cwd; + if (is.node) { + cwd = process.cwd() + slash; + } else { + cwd = (typeof location === 'undefined' + ? window.location + : location + ).href.replace(/\/[^/]*$/, '/'); + slash = '/'; + } function isMochaInternal(line) { - return (~line.indexOf('node_modules' + slash + 'mocha' + slash)) - || (~line.indexOf('components' + slash + 'mochajs' + slash)) - || (~line.indexOf('components' + slash + 'mocha' + slash)) - || (~line.indexOf(slash + 'mocha.js')); + return ( + ~line.indexOf('node_modules' + slash + 'mocha' + slash) || + ~line.indexOf(slash + 'mocha.js') + ); } function isNodeInternal(line) { - return (~line.indexOf('(timers.js:')) - || (~line.indexOf('(events.js:')) - || (~line.indexOf('(node.js:')) - || (~line.indexOf('(module.js:')) - || (~line.indexOf('GeneratorFunctionPrototype.next (native)')) - || false; + return ( + ~line.indexOf('(timers.js:') || + ~line.indexOf('(events.js:') || + ~line.indexOf('(node.js:') || + ~line.indexOf('(module.js:') || + ~line.indexOf('GeneratorFunctionPrototype.next (native)') || + false + ); } return function(stack) { stack = stack.split('\n'); - stack = exports.reduce(stack, function(list, line) { + stack = stack.reduce(function(list, line) { if (isMochaInternal(line)) { return list; } @@ -6590,8 +8034,8 @@ } // Clean up cwd(absolute) - if (/\(?.+:\d+:\d+\)?$/.test(line)) { - line = line.replace(cwd, ''); + if (/:\d+:\d+\)?$/.test(line)) { + line = line.replace('(' + cwd, '('); } list.push(line); @@ -6602,10 +8046,153 @@ }; }; +/** + * Crude, but effective. + * @public + * @param {*} value + * @returns {boolean} Whether or not `value` is a Promise + */ +exports.isPromise = function isPromise(value) { + return ( + typeof value === 'object' && + value !== null && + typeof value.then === 'function' + ); +}; + +/** + * Clamps a numeric value to an inclusive range. + * + * @param {number} value - Value to be clamped. + * @param {numer[]} range - Two element array specifying [min, max] range. + * @returns {number} clamped value + */ +exports.clamp = function clamp(value, range) { + return Math.min(Math.max(value, range[0]), range[1]); +}; + +/** + * Single quote text by combining with undirectional ASCII quotation marks. + * + * @description + * Provides a simple means of markup for quoting text to be used in output. + * Use this to quote names of variables, methods, and packages. + * + * <samp>package 'foo' cannot be found</samp> + * + * @private + * @param {string} str - Value to be quoted. + * @returns {string} quoted value + * @example + * sQuote('n') // => 'n' + */ +exports.sQuote = function(str) { + return "'" + str + "'"; +}; + +/** + * Double quote text by combining with undirectional ASCII quotation marks. + * + * @description + * Provides a simple means of markup for quoting text to be used in output. + * Use this to quote names of datatypes, classes, pathnames, and strings. + * + * <samp>argument 'value' must be "string" or "number"</samp> + * + * @private + * @param {string} str - Value to be quoted. + * @returns {string} quoted value + * @example + * dQuote('number') // => "number" + */ +exports.dQuote = function(str) { + return '"' + str + '"'; +}; + +/** + * Provides simplistic message translation for dealing with plurality. + * + * @description + * Use this to create messages which need to be singular or plural. + * Some languages have several plural forms, so _complete_ message clauses + * are preferable to generating the message on the fly. + * + * @private + * @param {number} n - Non-negative integer + * @param {string} msg1 - Message to be used in English for `n = 1` + * @param {string} msg2 - Message to be used in English for `n = 0, 2, 3, ...` + * @returns {string} message corresponding to value of `n` + * @example + * var sprintf = require('util').format; + * var pkgs = ['one', 'two']; + * var msg = sprintf( + * ngettext( + * pkgs.length, + * 'cannot load package: %s', + * 'cannot load packages: %s' + * ), + * pkgs.map(sQuote).join(', ') + * ); + * console.log(msg); // => cannot load packages: 'one', 'two' + */ +exports.ngettext = function(n, msg1, msg2) { + if (typeof n === 'number' && n >= 0) { + return n === 1 ? msg1 : msg2; + } +}; + +/** + * It's a noop. + * @public + */ +exports.noop = function() {}; + +/** + * Creates a map-like object. + * + * @description + * A "map" is an object with no prototype, for our purposes. In some cases + * this would be more appropriate than a `Map`, especially if your environment + * doesn't support it. Recommended for use in Mocha's public APIs. + * + * @public + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Map|MDN:Map} + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Custom_and_Null_objects|MDN:Object.create - Custom objects} + * @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign|MDN:Object.assign} + * @param {...*} [obj] - Arguments to `Object.assign()`. + * @returns {Object} An object with no prototype, having `...obj` properties + */ +exports.createMap = function(obj) { + return assign.apply( + null, + [Object.create(null)].concat(Array.prototype.slice.call(arguments)) + ); +}; + +/** + * Creates a read-only map-like object. + * + * @description + * This differs from {@link module:utils.createMap createMap} only in that + * the argument must be non-empty, because the result is frozen. + * + * @see {@link module:utils.createMap createMap} + * @param {...*} [obj] - Arguments to `Object.assign()`. + * @returns {Object} A frozen object with no prototype, having `...obj` properties + * @throws {TypeError} if argument is not a non-empty object. + */ +exports.defineConstants = function(obj) { + if (type(obj) !== 'object' || !Object.keys(obj).length) { + throw new TypeError('Invalid argument; expected a non-empty object'); + } + return Object.freeze(exports.createMap(obj)); +}; + }).call(this,require('_process'),require("buffer").Buffer) -},{"_process":58,"buffer":45,"debug":2,"fs":43,"glob":43,"path":43,"to-iso-string":72,"util":75}],40:[function(require,module,exports){ +},{"./errors":6,"_process":69,"buffer":43,"debug":45,"fs":42,"glob":42,"he":54,"object.assign":65,"path":42,"util":89}],39:[function(require,module,exports){ 'use strict' +exports.byteLength = byteLength exports.toByteArray = toByteArray exports.fromByteArray = fromByteArray @@ -6613,70 +8200,108 @@ var revLookup = [] var Arr = typeof Uint8Array !== 'undefined' ? Uint8Array : Array -function init () { - var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' - for (var i = 0, len = code.length; i < len; ++i) { - lookup[i] = code[i] - revLookup[code.charCodeAt(i)] = i - } - - revLookup['-'.charCodeAt(0)] = 62 - revLookup['_'.charCodeAt(0)] = 63 +var code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/' +for (var i = 0, len = code.length; i < len; ++i) { + lookup[i] = code[i] + revLookup[code.charCodeAt(i)] = i } -init() +// Support decoding URL-safe base64 strings, as Node.js does. +// See: https://en.wikipedia.org/wiki/Base64#URL_applications +revLookup['-'.charCodeAt(0)] = 62 +revLookup['_'.charCodeAt(0)] = 63 -function toByteArray (b64) { - var i, j, l, tmp, placeHolders, arr +function getLens (b64) { var len = b64.length if (len % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4') } - // the number of equal signs (place holders) - // if there are two placeholders, than the two characters before it - // represent one byte - // if there is only one, then the three characters before it represent 2 bytes - // this is just a cheap hack to not do indexOf twice - placeHolders = b64[len - 2] === '=' ? 2 : b64[len - 1] === '=' ? 1 : 0 + // Trim off extra bytes after placeholder bytes are found + // See: https://github.com/beatgammit/base64-js/issues/42 + var validLen = b64.indexOf('=') + if (validLen === -1) validLen = len - // base64 is 4/3 + up to two characters of the original data - arr = new Arr(len * 3 / 4 - placeHolders) + var placeHoldersLen = validLen === len + ? 0 + : 4 - (validLen % 4) + + return [validLen, placeHoldersLen] +} + +// base64 is 4/3 + up to two characters of the original data +function byteLength (b64) { + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function _byteLength (b64, validLen, placeHoldersLen) { + return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen +} + +function toByteArray (b64) { + var tmp + var lens = getLens(b64) + var validLen = lens[0] + var placeHoldersLen = lens[1] + + var arr = new Arr(_byteLength(b64, validLen, placeHoldersLen)) + + var curByte = 0 // if there are placeholders, only get up to the last complete 4 chars - l = placeHolders > 0 ? len - 4 : len + var len = placeHoldersLen > 0 + ? validLen - 4 + : validLen - var L = 0 - - for (i = 0, j = 0; i < l; i += 4, j += 3) { - tmp = (revLookup[b64.charCodeAt(i)] << 18) | (revLookup[b64.charCodeAt(i + 1)] << 12) | (revLookup[b64.charCodeAt(i + 2)] << 6) | revLookup[b64.charCodeAt(i + 3)] - arr[L++] = (tmp >> 16) & 0xFF - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF + for (var i = 0; i < len; i += 4) { + tmp = + (revLookup[b64.charCodeAt(i)] << 18) | + (revLookup[b64.charCodeAt(i + 1)] << 12) | + (revLookup[b64.charCodeAt(i + 2)] << 6) | + revLookup[b64.charCodeAt(i + 3)] + arr[curByte++] = (tmp >> 16) & 0xFF + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF } - if (placeHolders === 2) { - tmp = (revLookup[b64.charCodeAt(i)] << 2) | (revLookup[b64.charCodeAt(i + 1)] >> 4) - arr[L++] = tmp & 0xFF - } else if (placeHolders === 1) { - tmp = (revLookup[b64.charCodeAt(i)] << 10) | (revLookup[b64.charCodeAt(i + 1)] << 4) | (revLookup[b64.charCodeAt(i + 2)] >> 2) - arr[L++] = (tmp >> 8) & 0xFF - arr[L++] = tmp & 0xFF + if (placeHoldersLen === 2) { + tmp = + (revLookup[b64.charCodeAt(i)] << 2) | + (revLookup[b64.charCodeAt(i + 1)] >> 4) + arr[curByte++] = tmp & 0xFF + } + + if (placeHoldersLen === 1) { + tmp = + (revLookup[b64.charCodeAt(i)] << 10) | + (revLookup[b64.charCodeAt(i + 1)] << 4) | + (revLookup[b64.charCodeAt(i + 2)] >> 2) + arr[curByte++] = (tmp >> 8) & 0xFF + arr[curByte++] = tmp & 0xFF } return arr } function tripletToBase64 (num) { - return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] + return lookup[num >> 18 & 0x3F] + + lookup[num >> 12 & 0x3F] + + lookup[num >> 6 & 0x3F] + + lookup[num & 0x3F] } function encodeChunk (uint8, start, end) { var tmp var output = [] for (var i = start; i < end; i += 3) { - tmp = (uint8[i] << 16) + (uint8[i + 1] << 8) + (uint8[i + 2]) + tmp = + ((uint8[i] << 16) & 0xFF0000) + + ((uint8[i + 1] << 8) & 0xFF00) + + (uint8[i + 2] & 0xFF) output.push(tripletToBase64(tmp)) } return output.join('') @@ -6686,37 +8311,40 @@ var tmp var len = uint8.length var extraBytes = len % 3 // if we have 1 byte left, pad 2 bytes - var output = '' var parts = [] var maxChunkLength = 16383 // must be multiple of 3 // go through the array every three bytes, we'll deal with trailing stuff later for (var i = 0, len2 = len - extraBytes; i < len2; i += maxChunkLength) { - parts.push(encodeChunk(uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength))) + parts.push(encodeChunk( + uint8, i, (i + maxChunkLength) > len2 ? len2 : (i + maxChunkLength) + )) } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { tmp = uint8[len - 1] - output += lookup[tmp >> 2] - output += lookup[(tmp << 4) & 0x3F] - output += '==' + parts.push( + lookup[tmp >> 2] + + lookup[(tmp << 4) & 0x3F] + + '==' + ) } else if (extraBytes === 2) { - tmp = (uint8[len - 2] << 8) + (uint8[len - 1]) - output += lookup[tmp >> 10] - output += lookup[(tmp >> 4) & 0x3F] - output += lookup[(tmp << 2) & 0x3F] - output += '=' + tmp = (uint8[len - 2] << 8) + uint8[len - 1] + parts.push( + lookup[tmp >> 10] + + lookup[(tmp >> 4) & 0x3F] + + lookup[(tmp << 2) & 0x3F] + + '=' + ) } - parts.push(output) - return parts.join('') } -},{}],41:[function(require,module,exports){ +},{}],40:[function(require,module,exports){ -},{}],42:[function(require,module,exports){ +},{}],41:[function(require,module,exports){ (function (process){ var WritableStream = require('stream').Writable var inherits = require('util').inherits @@ -6745,126 +8373,14 @@ } }).call(this,require('_process')) -},{"_process":58,"stream":59,"util":75}],43:[function(require,module,exports){ -arguments[4][41][0].apply(exports,arguments) -},{"dup":41}],44:[function(require,module,exports){ -(function (global){ -'use strict'; - -var buffer = require('buffer'); -var Buffer = buffer.Buffer; -var SlowBuffer = buffer.SlowBuffer; -var MAX_LEN = buffer.kMaxLength || 2147483647; -exports.alloc = function alloc(size, fill, encoding) { - if (typeof Buffer.alloc === 'function') { - return Buffer.alloc(size, fill, encoding); - } - if (typeof encoding === 'number') { - throw new TypeError('encoding must not be number'); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size > MAX_LEN) { - throw new RangeError('size is too large'); - } - var enc = encoding; - var _fill = fill; - if (_fill === undefined) { - enc = undefined; - _fill = 0; - } - var buf = new Buffer(size); - if (typeof _fill === 'string') { - var fillBuf = new Buffer(_fill, enc); - var flen = fillBuf.length; - var i = -1; - while (++i < size) { - buf[i] = fillBuf[i % flen]; - } - } else { - buf.fill(_fill); - } - return buf; -} -exports.allocUnsafe = function allocUnsafe(size) { - if (typeof Buffer.allocUnsafe === 'function') { - return Buffer.allocUnsafe(size); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size > MAX_LEN) { - throw new RangeError('size is too large'); - } - return new Buffer(size); -} -exports.from = function from(value, encodingOrOffset, length) { - if (typeof Buffer.from === 'function' && (!global.Uint8Array || Uint8Array.from !== Buffer.from)) { - return Buffer.from(value, encodingOrOffset, length); - } - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number'); - } - if (typeof value === 'string') { - return new Buffer(value, encodingOrOffset); - } - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - var offset = encodingOrOffset; - if (arguments.length === 1) { - return new Buffer(value); - } - if (typeof offset === 'undefined') { - offset = 0; - } - var len = length; - if (typeof len === 'undefined') { - len = value.byteLength - offset; - } - if (offset >= value.byteLength) { - throw new RangeError('\'offset\' is out of bounds'); - } - if (len > value.byteLength - offset) { - throw new RangeError('\'length\' is out of bounds'); - } - return new Buffer(value.slice(offset, offset + len)); - } - if (Buffer.isBuffer(value)) { - var out = new Buffer(value.length); - value.copy(out, 0, 0, value.length); - return out; - } - if (value) { - if (Array.isArray(value) || (typeof ArrayBuffer !== 'undefined' && value.buffer instanceof ArrayBuffer) || 'length' in value) { - return new Buffer(value); - } - if (value.type === 'Buffer' && Array.isArray(value.data)) { - return new Buffer(value.data); - } - } - - throw new TypeError('First argument must be a string, Buffer, ' + 'ArrayBuffer, Array, or array-like object.'); -} -exports.allocUnsafeSlow = function allocUnsafeSlow(size) { - if (typeof Buffer.allocUnsafeSlow === 'function') { - return Buffer.allocUnsafeSlow(size); - } - if (typeof size !== 'number') { - throw new TypeError('size must be a number'); - } - if (size >= MAX_LEN) { - throw new RangeError('size is too large'); - } - return new SlowBuffer(size); -} - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"buffer":45}],45:[function(require,module,exports){ -(function (global){ +},{"_process":69,"stream":84,"util":89}],42:[function(require,module,exports){ +arguments[4][40][0].apply(exports,arguments) +},{"dup":40}],43:[function(require,module,exports){ +(function (Buffer){ /*! * The buffer module from node.js, for the browser. * - * @author Feross Aboukhadijeh <feross@feross.org> <http://feross.org> + * @author Feross Aboukhadijeh <https://feross.org> * @license MIT */ /* eslint-disable no-proto */ @@ -6873,80 +8389,73 @@ var base64 = require('base64-js') var ieee754 = require('ieee754') -var isArray = require('isarray') exports.Buffer = Buffer exports.SlowBuffer = SlowBuffer exports.INSPECT_MAX_BYTES = 50 +var K_MAX_LENGTH = 0x7fffffff +exports.kMaxLength = K_MAX_LENGTH + /** * If `Buffer.TYPED_ARRAY_SUPPORT`: * === true Use Uint8Array implementation (fastest) - * === false Use Object implementation (most compatible, even IE6) + * === false Print warning and recommend using `buffer` v4.x which has an Object + * implementation (most compatible, even IE6) * * Browsers that support typed arrays are IE 10+, Firefox 4+, Chrome 7+, Safari 5.1+, * Opera 11.6+, iOS 4.2+. * - * Due to various browser bugs, sometimes the Object implementation will be used even - * when the browser supports typed arrays. - * - * Note: - * - * - Firefox 4-29 lacks support for adding new properties to `Uint8Array` instances, - * See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438. - * - * - Chrome 9-10 is missing the `TypedArray.prototype.subarray` function. - * - * - IE10 has a broken `TypedArray.prototype.subarray` function which returns arrays of - * incorrect length in some situations. - - * We detect these buggy browsers and set `Buffer.TYPED_ARRAY_SUPPORT` to `false` so they - * get the Object implementation, which is slower but behaves correctly. + * We report that the browser does not support typed arrays if the are not subclassable + * using __proto__. Firefox 4-29 lacks support for adding new properties to `Uint8Array` + * (See: https://bugzilla.mozilla.org/show_bug.cgi?id=695438). IE 10 lacks support + * for __proto__ and has a buggy typed array implementation. */ -Buffer.TYPED_ARRAY_SUPPORT = global.TYPED_ARRAY_SUPPORT !== undefined - ? global.TYPED_ARRAY_SUPPORT - : typedArraySupport() +Buffer.TYPED_ARRAY_SUPPORT = typedArraySupport() -/* - * Export kMaxLength after typed array support is determined. - */ -exports.kMaxLength = kMaxLength() +if (!Buffer.TYPED_ARRAY_SUPPORT && typeof console !== 'undefined' && + typeof console.error === 'function') { + console.error( + 'This browser lacks typed array (Uint8Array) support which is required by ' + + '`buffer` v5.x. Use `buffer` v4.x if you require old browser support.' + ) +} function typedArraySupport () { + // Can typed array instances can be augmented? try { var arr = new Uint8Array(1) - arr.foo = function () { return 42 } - return arr.foo() === 42 && // typed array instances can be augmented - typeof arr.subarray === 'function' && // chrome 9-10 lack `subarray` - arr.subarray(1, 1).byteLength === 0 // ie10 has broken `subarray` + arr.__proto__ = { __proto__: Uint8Array.prototype, foo: function () { return 42 } } + return arr.foo() === 42 } catch (e) { return false } } -function kMaxLength () { - return Buffer.TYPED_ARRAY_SUPPORT - ? 0x7fffffff - : 0x3fffffff -} - -function createBuffer (that, length) { - if (kMaxLength() < length) { - throw new RangeError('Invalid typed array length') +Object.defineProperty(Buffer.prototype, 'parent', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.buffer } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = new Uint8Array(length) - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - if (that === null) { - that = new Buffer(length) - } - that.length = length - } +}) - return that +Object.defineProperty(Buffer.prototype, 'offset', { + enumerable: true, + get: function () { + if (!Buffer.isBuffer(this)) return undefined + return this.byteOffset + } +}) + +function createBuffer (length) { + if (length > K_MAX_LENGTH) { + throw new RangeError('The value "' + length + '" is invalid for option "size"') + } + // Return an augmented `Uint8Array` instance + var buf = new Uint8Array(length) + buf.__proto__ = Buffer.prototype + return buf } /** @@ -6960,44 +8469,77 @@ */ function Buffer (arg, encodingOrOffset, length) { - if (!Buffer.TYPED_ARRAY_SUPPORT && !(this instanceof Buffer)) { - return new Buffer(arg, encodingOrOffset, length) - } - // Common case. if (typeof arg === 'number') { if (typeof encodingOrOffset === 'string') { - throw new Error( - 'If encoding is specified then the first argument must be a string' + throw new TypeError( + 'The "string" argument must be of type string. Received type number' ) } - return allocUnsafe(this, arg) + return allocUnsafe(arg) } - return from(this, arg, encodingOrOffset, length) + return from(arg, encodingOrOffset, length) +} + +// Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 +if (typeof Symbol !== 'undefined' && Symbol.species != null && + Buffer[Symbol.species] === Buffer) { + Object.defineProperty(Buffer, Symbol.species, { + value: null, + configurable: true, + enumerable: false, + writable: false + }) } Buffer.poolSize = 8192 // not used by this implementation -// TODO: Legacy, not needed anymore. Remove in next major version. -Buffer._augment = function (arr) { - arr.__proto__ = Buffer.prototype - return arr -} - -function from (that, value, encodingOrOffset, length) { - if (typeof value === 'number') { - throw new TypeError('"value" argument must not be a number') - } - - if (typeof ArrayBuffer !== 'undefined' && value instanceof ArrayBuffer) { - return fromArrayBuffer(that, value, encodingOrOffset, length) - } - +function from (value, encodingOrOffset, length) { if (typeof value === 'string') { - return fromString(that, value, encodingOrOffset) + return fromString(value, encodingOrOffset) } - return fromObject(that, value) + if (ArrayBuffer.isView(value)) { + return fromArrayLike(value) + } + + if (value == null) { + throw TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) + } + + if (isInstance(value, ArrayBuffer) || + (value && isInstance(value.buffer, ArrayBuffer))) { + return fromArrayBuffer(value, encodingOrOffset, length) + } + + if (typeof value === 'number') { + throw new TypeError( + 'The "value" argument must not be of type number. Received type number' + ) + } + + var valueOf = value.valueOf && value.valueOf() + if (valueOf != null && valueOf !== value) { + return Buffer.from(valueOf, encodingOrOffset, length) + } + + var b = fromObject(value) + if (b) return b + + if (typeof Symbol !== 'undefined' && Symbol.toPrimitive != null && + typeof value[Symbol.toPrimitive] === 'function') { + return Buffer.from( + value[Symbol.toPrimitive]('string'), encodingOrOffset, length + ) + } + + throw new TypeError( + 'The first argument must be one of type string, Buffer, ArrayBuffer, Array, ' + + 'or Array-like Object. Received type ' + (typeof value) + ) } /** @@ -7009,42 +8551,36 @@ * Buffer.from(arrayBuffer[, byteOffset[, length]]) **/ Buffer.from = function (value, encodingOrOffset, length) { - return from(null, value, encodingOrOffset, length) + return from(value, encodingOrOffset, length) } -if (Buffer.TYPED_ARRAY_SUPPORT) { - Buffer.prototype.__proto__ = Uint8Array.prototype - Buffer.__proto__ = Uint8Array - if (typeof Symbol !== 'undefined' && Symbol.species && - Buffer[Symbol.species] === Buffer) { - // Fix subarray() in ES2016. See: https://github.com/feross/buffer/pull/97 - Object.defineProperty(Buffer, Symbol.species, { - value: null, - configurable: true - }) - } -} +// Note: Change prototype *after* Buffer.from is defined to workaround Chrome bug: +// https://github.com/feross/buffer/pull/148 +Buffer.prototype.__proto__ = Uint8Array.prototype +Buffer.__proto__ = Uint8Array function assertSize (size) { if (typeof size !== 'number') { - throw new TypeError('"size" argument must be a number') + throw new TypeError('"size" argument must be of type number') + } else if (size < 0) { + throw new RangeError('The value "' + size + '" is invalid for option "size"') } } -function alloc (that, size, fill, encoding) { +function alloc (size, fill, encoding) { assertSize(size) if (size <= 0) { - return createBuffer(that, size) + return createBuffer(size) } if (fill !== undefined) { // Only pay attention to encoding if it's a string. This // prevents accidentally sending in a number that would // be interpretted as a start offset. return typeof encoding === 'string' - ? createBuffer(that, size).fill(fill, encoding) - : createBuffer(that, size).fill(fill) + ? createBuffer(size).fill(fill, encoding) + : createBuffer(size).fill(fill) } - return createBuffer(that, size) + return createBuffer(size) } /** @@ -7052,122 +8588,114 @@ * alloc(size[, fill[, encoding]]) **/ Buffer.alloc = function (size, fill, encoding) { - return alloc(null, size, fill, encoding) + return alloc(size, fill, encoding) } -function allocUnsafe (that, size) { +function allocUnsafe (size) { assertSize(size) - that = createBuffer(that, size < 0 ? 0 : checked(size) | 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) { - for (var i = 0; i < size; i++) { - that[i] = 0 - } - } - return that + return createBuffer(size < 0 ? 0 : checked(size) | 0) } /** * Equivalent to Buffer(num), by default creates a non-zero-filled Buffer instance. * */ Buffer.allocUnsafe = function (size) { - return allocUnsafe(null, size) + return allocUnsafe(size) } /** * Equivalent to SlowBuffer(num), by default creates a non-zero-filled Buffer instance. */ Buffer.allocUnsafeSlow = function (size) { - return allocUnsafe(null, size) + return allocUnsafe(size) } -function fromString (that, string, encoding) { +function fromString (string, encoding) { if (typeof encoding !== 'string' || encoding === '') { encoding = 'utf8' } if (!Buffer.isEncoding(encoding)) { - throw new TypeError('"encoding" must be a valid string encoding') + throw new TypeError('Unknown encoding: ' + encoding) } var length = byteLength(string, encoding) | 0 - that = createBuffer(that, length) + var buf = createBuffer(length) - that.write(string, encoding) - return that -} + var actual = buf.write(string, encoding) -function fromArrayLike (that, array) { - var length = checked(array.length) | 0 - that = createBuffer(that, length) - for (var i = 0; i < length; i += 1) { - that[i] = array[i] & 255 + if (actual !== length) { + // Writing a hex string, for example, that contains invalid characters will + // cause everything after the first invalid character to be ignored. (e.g. + // 'abxxcd' will be treated as 'ab') + buf = buf.slice(0, actual) } - return that + + return buf } -function fromArrayBuffer (that, array, byteOffset, length) { - array.byteLength // this throws if `array` is not a valid ArrayBuffer +function fromArrayLike (array) { + var length = array.length < 0 ? 0 : checked(array.length) | 0 + var buf = createBuffer(length) + for (var i = 0; i < length; i += 1) { + buf[i] = array[i] & 255 + } + return buf +} +function fromArrayBuffer (array, byteOffset, length) { if (byteOffset < 0 || array.byteLength < byteOffset) { - throw new RangeError('\'offset\' is out of bounds') + throw new RangeError('"offset" is outside of buffer bounds') } if (array.byteLength < byteOffset + (length || 0)) { - throw new RangeError('\'length\' is out of bounds') + throw new RangeError('"length" is outside of buffer bounds') } - if (length === undefined) { - array = new Uint8Array(array, byteOffset) + var buf + if (byteOffset === undefined && length === undefined) { + buf = new Uint8Array(array) + } else if (length === undefined) { + buf = new Uint8Array(array, byteOffset) } else { - array = new Uint8Array(array, byteOffset, length) + buf = new Uint8Array(array, byteOffset, length) } - if (Buffer.TYPED_ARRAY_SUPPORT) { - // Return an augmented `Uint8Array` instance, for best performance - that = array - that.__proto__ = Buffer.prototype - } else { - // Fallback: Return an object instance of the Buffer class - that = fromArrayLike(that, array) - } - return that + // Return an augmented `Uint8Array` instance + buf.__proto__ = Buffer.prototype + return buf } -function fromObject (that, obj) { +function fromObject (obj) { if (Buffer.isBuffer(obj)) { var len = checked(obj.length) | 0 - that = createBuffer(that, len) + var buf = createBuffer(len) - if (that.length === 0) { - return that + if (buf.length === 0) { + return buf } - obj.copy(that, 0, 0, len) - return that + obj.copy(buf, 0, 0, len) + return buf } - if (obj) { - if ((typeof ArrayBuffer !== 'undefined' && - obj.buffer instanceof ArrayBuffer) || 'length' in obj) { - if (typeof obj.length !== 'number' || isnan(obj.length)) { - return createBuffer(that, 0) - } - return fromArrayLike(that, obj) + if (obj.length !== undefined) { + if (typeof obj.length !== 'number' || numberIsNaN(obj.length)) { + return createBuffer(0) } - - if (obj.type === 'Buffer' && isArray(obj.data)) { - return fromArrayLike(that, obj.data) - } + return fromArrayLike(obj) } - throw new TypeError('First argument must be a string, Buffer, ArrayBuffer, Array, or array-like object.') + if (obj.type === 'Buffer' && Array.isArray(obj.data)) { + return fromArrayLike(obj.data) + } } function checked (length) { - // Note: cannot use `length < kMaxLength` here because that fails when + // Note: cannot use `length < K_MAX_LENGTH` here because that fails when // length is NaN (which is otherwise coerced to zero.) - if (length >= kMaxLength()) { + if (length >= K_MAX_LENGTH) { throw new RangeError('Attempt to allocate Buffer larger than maximum ' + - 'size: 0x' + kMaxLength().toString(16) + ' bytes') + 'size: 0x' + K_MAX_LENGTH.toString(16) + ' bytes') } return length | 0 } @@ -7180,12 +8708,17 @@ } Buffer.isBuffer = function isBuffer (b) { - return !!(b != null && b._isBuffer) + return b != null && b._isBuffer === true && + b !== Buffer.prototype // so Buffer.isBuffer(Buffer.prototype) will be false } Buffer.compare = function compare (a, b) { + if (isInstance(a, Uint8Array)) a = Buffer.from(a, a.offset, a.byteLength) + if (isInstance(b, Uint8Array)) b = Buffer.from(b, b.offset, b.byteLength) if (!Buffer.isBuffer(a) || !Buffer.isBuffer(b)) { - throw new TypeError('Arguments must be Buffers') + throw new TypeError( + 'The "buf1", "buf2" arguments must be one of type Buffer or Uint8Array' + ) } if (a === b) return 0 @@ -7212,9 +8745,9 @@ case 'utf8': case 'utf-8': case 'ascii': + case 'latin1': case 'binary': case 'base64': - case 'raw': case 'ucs2': case 'ucs-2': case 'utf16le': @@ -7226,7 +8759,7 @@ } Buffer.concat = function concat (list, length) { - if (!isArray(list)) { + if (!Array.isArray(list)) { throw new TypeError('"list" argument must be an Array of Buffers') } @@ -7237,15 +8770,18 @@ var i if (length === undefined) { length = 0 - for (i = 0; i < list.length; i++) { + for (i = 0; i < list.length; ++i) { length += list[i].length } } var buffer = Buffer.allocUnsafe(length) var pos = 0 - for (i = 0; i < list.length; i++) { + for (i = 0; i < list.length; ++i) { var buf = list[i] + if (isInstance(buf, Uint8Array)) { + buf = Buffer.from(buf) + } if (!Buffer.isBuffer(buf)) { throw new TypeError('"list" argument must be an Array of Buffers') } @@ -7259,30 +8795,30 @@ if (Buffer.isBuffer(string)) { return string.length } - if (typeof ArrayBuffer !== 'undefined' && typeof ArrayBuffer.isView === 'function' && - (ArrayBuffer.isView(string) || string instanceof ArrayBuffer)) { + if (ArrayBuffer.isView(string) || isInstance(string, ArrayBuffer)) { return string.byteLength } if (typeof string !== 'string') { - string = '' + string + throw new TypeError( + 'The "string" argument must be one of type string, Buffer, or ArrayBuffer. ' + + 'Received type ' + typeof string + ) } var len = string.length - if (len === 0) return 0 + var mustMatch = (arguments.length > 2 && arguments[2] === true) + if (!mustMatch && len === 0) return 0 // Use a for loop to avoid recursion var loweredCase = false for (;;) { switch (encoding) { case 'ascii': + case 'latin1': case 'binary': - // Deprecated - case 'raw': - case 'raws': return len case 'utf8': case 'utf-8': - case undefined: return utf8ToBytes(string).length case 'ucs2': case 'ucs-2': @@ -7294,7 +8830,9 @@ case 'base64': return base64ToBytes(string).length default: - if (loweredCase) return utf8ToBytes(string).length // assume utf8 + if (loweredCase) { + return mustMatch ? -1 : utf8ToBytes(string).length // assume utf8 + } encoding = ('' + encoding).toLowerCase() loweredCase = true } @@ -7351,8 +8889,9 @@ case 'ascii': return asciiSlice(this, start, end) + case 'latin1': case 'binary': - return binarySlice(this, start, end) + return latin1Slice(this, start, end) case 'base64': return base64Slice(this, start, end) @@ -7371,8 +8910,12 @@ } } -// The property is used by `Buffer.isBuffer` and `is-buffer` (in Safari 5-7) to detect -// Buffer instances. +// This property is used by `Buffer.isBuffer` (and the `is-buffer` npm package) +// to detect a Buffer instance. It's not possible to use `instanceof Buffer` +// reliably in a browserify context because there could be multiple different +// copies of the 'buffer' package in use. This method works even for Buffer +// instances that were created from another copy of the `buffer` package. +// See: https://github.com/feross/buffer/issues/154 Buffer.prototype._isBuffer = true function swap (b, n, m) { @@ -7404,13 +8947,29 @@ return this } +Buffer.prototype.swap64 = function swap64 () { + var len = this.length + if (len % 8 !== 0) { + throw new RangeError('Buffer size must be a multiple of 64-bits') + } + for (var i = 0; i < len; i += 8) { + swap(this, i, i + 7) + swap(this, i + 1, i + 6) + swap(this, i + 2, i + 5) + swap(this, i + 3, i + 4) + } + return this +} + Buffer.prototype.toString = function toString () { - var length = this.length | 0 + var length = this.length if (length === 0) return '' if (arguments.length === 0) return utf8Slice(this, 0, length) return slowToString.apply(this, arguments) } +Buffer.prototype.toLocaleString = Buffer.prototype.toString + Buffer.prototype.equals = function equals (b) { if (!Buffer.isBuffer(b)) throw new TypeError('Argument must be a Buffer') if (this === b) return true @@ -7420,16 +8979,20 @@ Buffer.prototype.inspect = function inspect () { var str = '' var max = exports.INSPECT_MAX_BYTES - if (this.length > 0) { - str = this.toString('hex', 0, max).match(/.{2}/g).join(' ') - if (this.length > max) str += ' ... ' - } + str = this.toString('hex', 0, max).replace(/(.{2})/g, '$1 ').trim() + if (this.length > max) str += ' ... ' return '<Buffer ' + str + '>' } Buffer.prototype.compare = function compare (target, start, end, thisStart, thisEnd) { + if (isInstance(target, Uint8Array)) { + target = Buffer.from(target, target.offset, target.byteLength) + } if (!Buffer.isBuffer(target)) { - throw new TypeError('Argument must be a Buffer') + throw new TypeError( + 'The "target" argument must be one of type Buffer or Uint8Array. ' + + 'Received type ' + (typeof target) + ) } if (start === undefined) { @@ -7486,7 +9049,72 @@ return 0 } -function arrayIndexOf (arr, val, byteOffset, encoding) { +// Finds either the first index of `val` in `buffer` at offset >= `byteOffset`, +// OR the last index of `val` in `buffer` at offset <= `byteOffset`. +// +// Arguments: +// - buffer - a Buffer to search +// - val - a string, Buffer, or number +// - byteOffset - an index into `buffer`; will be clamped to an int32 +// - encoding - an optional encoding, relevant is val is a string +// - dir - true for indexOf, false for lastIndexOf +function bidirectionalIndexOf (buffer, val, byteOffset, encoding, dir) { + // Empty buffer means no match + if (buffer.length === 0) return -1 + + // Normalize byteOffset + if (typeof byteOffset === 'string') { + encoding = byteOffset + byteOffset = 0 + } else if (byteOffset > 0x7fffffff) { + byteOffset = 0x7fffffff + } else if (byteOffset < -0x80000000) { + byteOffset = -0x80000000 + } + byteOffset = +byteOffset // Coerce to Number. + if (numberIsNaN(byteOffset)) { + // byteOffset: it it's undefined, null, NaN, "foo", etc, search whole buffer + byteOffset = dir ? 0 : (buffer.length - 1) + } + + // Normalize byteOffset: negative offsets start from the end of the buffer + if (byteOffset < 0) byteOffset = buffer.length + byteOffset + if (byteOffset >= buffer.length) { + if (dir) return -1 + else byteOffset = buffer.length - 1 + } else if (byteOffset < 0) { + if (dir) byteOffset = 0 + else return -1 + } + + // Normalize val + if (typeof val === 'string') { + val = Buffer.from(val, encoding) + } + + // Finally, search either indexOf (if dir is true) or lastIndexOf + if (Buffer.isBuffer(val)) { + // Special case: looking for empty string/buffer always fails + if (val.length === 0) { + return -1 + } + return arrayIndexOf(buffer, val, byteOffset, encoding, dir) + } else if (typeof val === 'number') { + val = val & 0xFF // Search for a byte value [0-255] + if (typeof Uint8Array.prototype.indexOf === 'function') { + if (dir) { + return Uint8Array.prototype.indexOf.call(buffer, val, byteOffset) + } else { + return Uint8Array.prototype.lastIndexOf.call(buffer, val, byteOffset) + } + } + return arrayIndexOf(buffer, [ val ], byteOffset, encoding, dir) + } + + throw new TypeError('val must be string, number or Buffer') +} + +function arrayIndexOf (arr, val, byteOffset, encoding, dir) { var indexSize = 1 var arrLength = arr.length var valLength = val.length @@ -7513,61 +9141,47 @@ } } - var foundIndex = -1 - for (var i = 0; byteOffset + i < arrLength; i++) { - if (read(arr, byteOffset + i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { - if (foundIndex === -1) foundIndex = i - if (i - foundIndex + 1 === valLength) return (byteOffset + foundIndex) * indexSize - } else { - if (foundIndex !== -1) i -= i - foundIndex - foundIndex = -1 + var i + if (dir) { + var foundIndex = -1 + for (i = byteOffset; i < arrLength; i++) { + if (read(arr, i) === read(val, foundIndex === -1 ? 0 : i - foundIndex)) { + if (foundIndex === -1) foundIndex = i + if (i - foundIndex + 1 === valLength) return foundIndex * indexSize + } else { + if (foundIndex !== -1) i -= i - foundIndex + foundIndex = -1 + } + } + } else { + if (byteOffset + valLength > arrLength) byteOffset = arrLength - valLength + for (i = byteOffset; i >= 0; i--) { + var found = true + for (var j = 0; j < valLength; j++) { + if (read(arr, i + j) !== read(val, j)) { + found = false + break + } + } + if (found) return i } } + return -1 } -Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { - if (typeof byteOffset === 'string') { - encoding = byteOffset - byteOffset = 0 - } else if (byteOffset > 0x7fffffff) { - byteOffset = 0x7fffffff - } else if (byteOffset < -0x80000000) { - byteOffset = -0x80000000 - } - byteOffset >>= 0 - - if (this.length === 0) return -1 - if (byteOffset >= this.length) return -1 - - // Negative offsets start from the end of the buffer - if (byteOffset < 0) byteOffset = Math.max(this.length + byteOffset, 0) - - if (typeof val === 'string') { - val = Buffer.from(val, encoding) - } - - if (Buffer.isBuffer(val)) { - // special case: looking for empty string/buffer always fails - if (val.length === 0) { - return -1 - } - return arrayIndexOf(this, val, byteOffset, encoding) - } - if (typeof val === 'number') { - if (Buffer.TYPED_ARRAY_SUPPORT && Uint8Array.prototype.indexOf === 'function') { - return Uint8Array.prototype.indexOf.call(this, val, byteOffset) - } - return arrayIndexOf(this, [ val ], byteOffset, encoding) - } - - throw new TypeError('val must be string, number or Buffer') -} - Buffer.prototype.includes = function includes (val, byteOffset, encoding) { return this.indexOf(val, byteOffset, encoding) !== -1 } +Buffer.prototype.indexOf = function indexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, true) +} + +Buffer.prototype.lastIndexOf = function lastIndexOf (val, byteOffset, encoding) { + return bidirectionalIndexOf(this, val, byteOffset, encoding, false) +} + function hexWrite (buf, string, offset, length) { offset = Number(offset) || 0 var remaining = buf.length - offset @@ -7580,16 +9194,14 @@ } } - // must be an even number of digits var strLen = string.length - if (strLen % 2 !== 0) throw new Error('Invalid hex string') if (length > strLen / 2) { length = strLen / 2 } - for (var i = 0; i < length; i++) { + for (var i = 0; i < length; ++i) { var parsed = parseInt(string.substr(i * 2, 2), 16) - if (isNaN(parsed)) return i + if (numberIsNaN(parsed)) return i buf[offset + i] = parsed } return i @@ -7603,7 +9215,7 @@ return blitBuffer(asciiToBytes(string), buf, offset, length) } -function binaryWrite (buf, string, offset, length) { +function latin1Write (buf, string, offset, length) { return asciiWrite(buf, string, offset, length) } @@ -7628,15 +9240,14 @@ offset = 0 // Buffer#write(string, offset[, length][, encoding]) } else if (isFinite(offset)) { - offset = offset | 0 + offset = offset >>> 0 if (isFinite(length)) { - length = length | 0 + length = length >>> 0 if (encoding === undefined) encoding = 'utf8' } else { encoding = length length = undefined } - // legacy write(string, encoding, offset, length) - remove in v0.13 } else { throw new Error( 'Buffer.write(string, encoding, offset[, length]) is no longer supported' @@ -7665,8 +9276,9 @@ case 'ascii': return asciiWrite(this, string, offset, length) + case 'latin1': case 'binary': - return binaryWrite(this, string, offset, length) + return latin1Write(this, string, offset, length) case 'base64': // Warning: maxLength not taken into account in base64Write @@ -7711,8 +9323,8 @@ var codePoint = null var bytesPerSequence = (firstByte > 0xEF) ? 4 : (firstByte > 0xDF) ? 3 - : (firstByte > 0xBF) ? 2 - : 1 + : (firstByte > 0xBF) ? 2 + : 1 if (i + bytesPerSequence <= end) { var secondByte, thirdByte, fourthByte, tempCodePoint @@ -7801,17 +9413,17 @@ var ret = '' end = Math.min(buf.length, end) - for (var i = start; i < end; i++) { + for (var i = start; i < end; ++i) { ret += String.fromCharCode(buf[i] & 0x7F) } return ret } -function binarySlice (buf, start, end) { +function latin1Slice (buf, start, end) { var ret = '' end = Math.min(buf.length, end) - for (var i = start; i < end; i++) { + for (var i = start; i < end; ++i) { ret += String.fromCharCode(buf[i]) } return ret @@ -7824,7 +9436,7 @@ if (!end || end < 0 || end > len) end = len var out = '' - for (var i = start; i < end; i++) { + for (var i = start; i < end; ++i) { out += toHex(buf[i]) } return out @@ -7834,7 +9446,7 @@ var bytes = buf.slice(start, end) var res = '' for (var i = 0; i < bytes.length; i += 2) { - res += String.fromCharCode(bytes[i] + bytes[i + 1] * 256) + res += String.fromCharCode(bytes[i] + (bytes[i + 1] * 256)) } return res } @@ -7860,18 +9472,9 @@ if (end < start) end = start - var newBuf - if (Buffer.TYPED_ARRAY_SUPPORT) { - newBuf = this.subarray(start, end) - newBuf.__proto__ = Buffer.prototype - } else { - var sliceLen = end - start - newBuf = new Buffer(sliceLen, undefined) - for (var i = 0; i < sliceLen; i++) { - newBuf[i] = this[i + start] - } - } - + var newBuf = this.subarray(start, end) + // Return an augmented `Uint8Array` instance + newBuf.__proto__ = Buffer.prototype return newBuf } @@ -7884,8 +9487,8 @@ } Buffer.prototype.readUIntLE = function readUIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var val = this[offset] @@ -7899,8 +9502,8 @@ } Buffer.prototype.readUIntBE = function readUIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) { checkOffset(offset, byteLength, this.length) } @@ -7915,21 +9518,25 @@ } Buffer.prototype.readUInt8 = function readUInt8 (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 1, this.length) return this[offset] } Buffer.prototype.readUInt16LE = function readUInt16LE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) return this[offset] | (this[offset + 1] << 8) } Buffer.prototype.readUInt16BE = function readUInt16BE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) return (this[offset] << 8) | this[offset + 1] } Buffer.prototype.readUInt32LE = function readUInt32LE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ((this[offset]) | @@ -7939,6 +9546,7 @@ } Buffer.prototype.readUInt32BE = function readUInt32BE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset] * 0x1000000) + @@ -7948,8 +9556,8 @@ } Buffer.prototype.readIntLE = function readIntLE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var val = this[offset] @@ -7966,8 +9574,8 @@ } Buffer.prototype.readIntBE = function readIntBE (offset, byteLength, noAssert) { - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) checkOffset(offset, byteLength, this.length) var i = byteLength @@ -7984,24 +9592,28 @@ } Buffer.prototype.readInt8 = function readInt8 (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 1, this.length) if (!(this[offset] & 0x80)) return (this[offset]) return ((0xff - this[offset] + 1) * -1) } Buffer.prototype.readInt16LE = function readInt16LE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) var val = this[offset] | (this[offset + 1] << 8) return (val & 0x8000) ? val | 0xFFFF0000 : val } Buffer.prototype.readInt16BE = function readInt16BE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 2, this.length) var val = this[offset + 1] | (this[offset] << 8) return (val & 0x8000) ? val | 0xFFFF0000 : val } Buffer.prototype.readInt32LE = function readInt32LE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset]) | @@ -8011,6 +9623,7 @@ } Buffer.prototype.readInt32BE = function readInt32BE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return (this[offset] << 24) | @@ -8020,21 +9633,25 @@ } Buffer.prototype.readFloatLE = function readFloatLE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ieee754.read(this, offset, true, 23, 4) } Buffer.prototype.readFloatBE = function readFloatBE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 4, this.length) return ieee754.read(this, offset, false, 23, 4) } Buffer.prototype.readDoubleLE = function readDoubleLE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 8, this.length) return ieee754.read(this, offset, true, 52, 8) } Buffer.prototype.readDoubleBE = function readDoubleBE (offset, noAssert) { + offset = offset >>> 0 if (!noAssert) checkOffset(offset, 8, this.length) return ieee754.read(this, offset, false, 52, 8) } @@ -8047,8 +9664,8 @@ Buffer.prototype.writeUIntLE = function writeUIntLE (value, offset, byteLength, noAssert) { value = +value - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) { var maxBytes = Math.pow(2, 8 * byteLength) - 1 checkInt(this, value, offset, byteLength, maxBytes, 0) @@ -8066,8 +9683,8 @@ Buffer.prototype.writeUIntBE = function writeUIntBE (value, offset, byteLength, noAssert) { value = +value - offset = offset | 0 - byteLength = byteLength | 0 + offset = offset >>> 0 + byteLength = byteLength >>> 0 if (!noAssert) { var maxBytes = Math.pow(2, 8 * byteLength) - 1 checkInt(this, value, offset, byteLength, maxBytes, 0) @@ -8085,89 +9702,57 @@ Buffer.prototype.writeUInt8 = function writeUInt8 (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 1, 0xff, 0) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) this[offset] = (value & 0xff) return offset + 1 } -function objectWriteUInt16 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 2); i < j; i++) { - buf[offset + i] = (value & (0xff << (8 * (littleEndian ? i : 1 - i)))) >>> - (littleEndian ? i : 1 - i) * 8 - } -} - Buffer.prototype.writeUInt16LE = function writeUInt16LE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) return offset + 2 } Buffer.prototype.writeUInt16BE = function writeUInt16BE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0xffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) return offset + 2 } -function objectWriteUInt32 (buf, value, offset, littleEndian) { - if (value < 0) value = 0xffffffff + value + 1 - for (var i = 0, j = Math.min(buf.length - offset, 4); i < j; i++) { - buf[offset + i] = (value >>> (littleEndian ? i : 3 - i) * 8) & 0xff - } -} - Buffer.prototype.writeUInt32LE = function writeUInt32LE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset + 3] = (value >>> 24) - this[offset + 2] = (value >>> 16) - this[offset + 1] = (value >>> 8) - this[offset] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, true) - } + this[offset + 3] = (value >>> 24) + this[offset + 2] = (value >>> 16) + this[offset + 1] = (value >>> 8) + this[offset] = (value & 0xff) return offset + 4 } Buffer.prototype.writeUInt32BE = function writeUInt32BE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0xffffffff, 0) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) return offset + 4 } Buffer.prototype.writeIntLE = function writeIntLE (value, offset, byteLength, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) + var limit = Math.pow(2, (8 * byteLength) - 1) checkInt(this, value, offset, byteLength, limit - 1, -limit) } @@ -8188,9 +9773,9 @@ Buffer.prototype.writeIntBE = function writeIntBE (value, offset, byteLength, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) { - var limit = Math.pow(2, 8 * byteLength - 1) + var limit = Math.pow(2, (8 * byteLength) - 1) checkInt(this, value, offset, byteLength, limit - 1, -limit) } @@ -8211,9 +9796,8 @@ Buffer.prototype.writeInt8 = function writeInt8 (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 1, 0x7f, -0x80) - if (!Buffer.TYPED_ARRAY_SUPPORT) value = Math.floor(value) if (value < 0) value = 0xff + value + 1 this[offset] = (value & 0xff) return offset + 1 @@ -8221,58 +9805,42 @@ Buffer.prototype.writeInt16LE = function writeInt16LE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - } else { - objectWriteUInt16(this, value, offset, true) - } + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) return offset + 2 } Buffer.prototype.writeInt16BE = function writeInt16BE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 2, 0x7fff, -0x8000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 8) - this[offset + 1] = (value & 0xff) - } else { - objectWriteUInt16(this, value, offset, false) - } + this[offset] = (value >>> 8) + this[offset + 1] = (value & 0xff) return offset + 2 } Buffer.prototype.writeInt32LE = function writeInt32LE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value & 0xff) - this[offset + 1] = (value >>> 8) - this[offset + 2] = (value >>> 16) - this[offset + 3] = (value >>> 24) - } else { - objectWriteUInt32(this, value, offset, true) - } + this[offset] = (value & 0xff) + this[offset + 1] = (value >>> 8) + this[offset + 2] = (value >>> 16) + this[offset + 3] = (value >>> 24) return offset + 4 } Buffer.prototype.writeInt32BE = function writeInt32BE (value, offset, noAssert) { value = +value - offset = offset | 0 + offset = offset >>> 0 if (!noAssert) checkInt(this, value, offset, 4, 0x7fffffff, -0x80000000) if (value < 0) value = 0xffffffff + value + 1 - if (Buffer.TYPED_ARRAY_SUPPORT) { - this[offset] = (value >>> 24) - this[offset + 1] = (value >>> 16) - this[offset + 2] = (value >>> 8) - this[offset + 3] = (value & 0xff) - } else { - objectWriteUInt32(this, value, offset, false) - } + this[offset] = (value >>> 24) + this[offset + 1] = (value >>> 16) + this[offset + 2] = (value >>> 8) + this[offset + 3] = (value & 0xff) return offset + 4 } @@ -8282,6 +9850,8 @@ } function writeFloat (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 if (!noAssert) { checkIEEE754(buf, value, offset, 4, 3.4028234663852886e+38, -3.4028234663852886e+38) } @@ -8298,6 +9868,8 @@ } function writeDouble (buf, value, offset, littleEndian, noAssert) { + value = +value + offset = offset >>> 0 if (!noAssert) { checkIEEE754(buf, value, offset, 8, 1.7976931348623157E+308, -1.7976931348623157E+308) } @@ -8315,6 +9887,7 @@ // copy(targetBuffer, targetStart=0, sourceStart=0, sourceEnd=buffer.length) Buffer.prototype.copy = function copy (target, targetStart, start, end) { + if (!Buffer.isBuffer(target)) throw new TypeError('argument should be a Buffer') if (!start) start = 0 if (!end && end !== 0) end = this.length if (targetStart >= target.length) targetStart = target.length @@ -8329,7 +9902,7 @@ if (targetStart < 0) { throw new RangeError('targetStart out of bounds') } - if (start < 0 || start >= this.length) throw new RangeError('sourceStart out of bounds') + if (start < 0 || start >= this.length) throw new RangeError('Index out of range') if (end < 0) throw new RangeError('sourceEnd out of bounds') // Are we oob? @@ -8339,22 +9912,19 @@ } var len = end - start - var i - if (this === target && start < targetStart && targetStart < end) { + if (this === target && typeof Uint8Array.prototype.copyWithin === 'function') { + // Use built-in when available, missing from IE11 + this.copyWithin(targetStart, start, end) + } else if (this === target && start < targetStart && targetStart < end) { // descending copy from end - for (i = len - 1; i >= 0; i--) { - target[i + targetStart] = this[i + start] - } - } else if (len < 1000 || !Buffer.TYPED_ARRAY_SUPPORT) { - // ascending copy from start - for (i = 0; i < len; i++) { + for (var i = len - 1; i >= 0; --i) { target[i + targetStart] = this[i + start] } } else { Uint8Array.prototype.set.call( target, - this.subarray(start, start + len), + this.subarray(start, end), targetStart ) } @@ -8377,18 +9947,20 @@ encoding = end end = this.length } - if (val.length === 1) { - var code = val.charCodeAt(0) - if (code < 256) { - val = code - } - } if (encoding !== undefined && typeof encoding !== 'string') { throw new TypeError('encoding must be a string') } if (typeof encoding === 'string' && !Buffer.isEncoding(encoding)) { throw new TypeError('Unknown encoding: ' + encoding) } + if (val.length === 1) { + var code = val.charCodeAt(0) + if ((encoding === 'utf8' && code < 128) || + encoding === 'latin1') { + // Fast path: If `val` fits into a single byte, use that numeric value. + val = code + } + } } else if (typeof val === 'number') { val = val & 255 } @@ -8409,15 +9981,19 @@ var i if (typeof val === 'number') { - for (i = start; i < end; i++) { + for (i = start; i < end; ++i) { this[i] = val } } else { var bytes = Buffer.isBuffer(val) ? val - : utf8ToBytes(new Buffer(val, encoding).toString()) + : Buffer.from(val, encoding) var len = bytes.length - for (i = 0; i < end - start; i++) { + if (len === 0) { + throw new TypeError('The value "' + val + + '" is invalid for argument "value"') + } + for (i = 0; i < end - start; ++i) { this[i + start] = bytes[i % len] } } @@ -8428,11 +10004,13 @@ // HELPER FUNCTIONS // ================ -var INVALID_BASE64_RE = /[^+\/0-9A-Za-z-_]/g +var INVALID_BASE64_RE = /[^+/0-9A-Za-z-_]/g function base64clean (str) { + // Node takes equal signs as end of the Base64 encoding + str = str.split('=')[0] // Node strips out invalid characters like \n and \t from the string, base64-js does not - str = stringtrim(str).replace(INVALID_BASE64_RE, '') + str = str.trim().replace(INVALID_BASE64_RE, '') // Node converts strings with length < 2 to '' if (str.length < 2) return '' // Node allows for non-padded base64 strings (missing trailing ===), base64-js does not @@ -8442,11 +10020,6 @@ return str } -function stringtrim (str) { - if (str.trim) return str.trim() - return str.replace(/^\s+|\s+$/g, '') -} - function toHex (n) { if (n < 16) return '0' + n.toString(16) return n.toString(16) @@ -8459,7 +10032,7 @@ var leadSurrogate = null var bytes = [] - for (var i = 0; i < length; i++) { + for (var i = 0; i < length; ++i) { codePoint = string.charCodeAt(i) // is surrogate component @@ -8534,7 +10107,7 @@ function asciiToBytes (str) { var byteArray = [] - for (var i = 0; i < str.length; i++) { + for (var i = 0; i < str.length; ++i) { // Node's code seems to be doing this and not & 0x7F.. byteArray.push(str.charCodeAt(i) & 0xFF) } @@ -8544,7 +10117,7 @@ function utf16leToBytes (str, units) { var c, hi, lo var byteArray = [] - for (var i = 0; i < str.length; i++) { + for (var i = 0; i < str.length; ++i) { if ((units -= 2) < 0) break c = str.charCodeAt(i) @@ -8562,26 +10135,28 @@ } function blitBuffer (src, dst, offset, length) { - for (var i = 0; i < length; i++) { + for (var i = 0; i < length; ++i) { if ((i + offset >= dst.length) || (i >= src.length)) break dst[i + offset] = src[i] } return i } -function isnan (val) { - return val !== val // eslint-disable-line no-self-compare +// ArrayBuffer or Uint8Array objects from other contexts (i.e. iframes) do not pass +// the `instanceof` check but they should be treated as of that type. +// See: https://github.com/feross/buffer/issues/166 +function isInstance (obj, type) { + return obj instanceof type || + (obj != null && obj.constructor != null && obj.constructor.name != null && + obj.constructor.name === type.name) +} +function numberIsNaN (obj) { + // For IE11 support + return obj !== obj // eslint-disable-line no-self-compare } -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"base64-js":40,"ieee754":52,"isarray":46}],46:[function(require,module,exports){ -var toString = {}.toString; - -module.exports = Array.isArray || function (arr) { - return toString.call(arr) == '[object Array]'; -}; - -},{}],47:[function(require,module,exports){ +}).call(this,require("buffer").Buffer) +},{"base64-js":39,"buffer":43,"ieee754":55}],44:[function(require,module,exports){ (function (Buffer){ // Copyright Joyent, Inc. and other Node contributors. // @@ -8692,627 +10267,2345 @@ } }).call(this,{"isBuffer":require("../../is-buffer/index.js")}) -},{"../../is-buffer/index.js":54}],48:[function(require,module,exports){ -/* See LICENSE file for terms of use */ +},{"../../is-buffer/index.js":57}],45:[function(require,module,exports){ +(function (process){ +"use strict"; -/* - * Text diff implementation. - * - * This library supports the following APIS: - * JsDiff.diffChars: Character by character diff - * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace - * JsDiff.diffLines: Line based diff - * - * JsDiff.diffCss: Diff targeted at CSS content - * - * These methods are based on the implementation proposed in - * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 +function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + +/* eslint-env browser */ + +/** + * This is the web browser implementation of `debug()`. */ -(function(global, undefined) { - var objectPrototypeToString = Object.prototype.toString; +exports.log = log; +exports.formatArgs = formatArgs; +exports.save = save; +exports.load = load; +exports.useColors = useColors; +exports.storage = localstorage(); +/** + * Colors. + */ - /*istanbul ignore next*/ - function map(arr, mapper, that) { - if (Array.prototype.map) { - return Array.prototype.map.call(arr, mapper, that); +exports.colors = ['#0000CC', '#0000FF', '#0033CC', '#0033FF', '#0066CC', '#0066FF', '#0099CC', '#0099FF', '#00CC00', '#00CC33', '#00CC66', '#00CC99', '#00CCCC', '#00CCFF', '#3300CC', '#3300FF', '#3333CC', '#3333FF', '#3366CC', '#3366FF', '#3399CC', '#3399FF', '#33CC00', '#33CC33', '#33CC66', '#33CC99', '#33CCCC', '#33CCFF', '#6600CC', '#6600FF', '#6633CC', '#6633FF', '#66CC00', '#66CC33', '#9900CC', '#9900FF', '#9933CC', '#9933FF', '#99CC00', '#99CC33', '#CC0000', '#CC0033', '#CC0066', '#CC0099', '#CC00CC', '#CC00FF', '#CC3300', '#CC3333', '#CC3366', '#CC3399', '#CC33CC', '#CC33FF', '#CC6600', '#CC6633', '#CC9900', '#CC9933', '#CCCC00', '#CCCC33', '#FF0000', '#FF0033', '#FF0066', '#FF0099', '#FF00CC', '#FF00FF', '#FF3300', '#FF3333', '#FF3366', '#FF3399', '#FF33CC', '#FF33FF', '#FF6600', '#FF6633', '#FF9900', '#FF9933', '#FFCC00', '#FFCC33']; +/** + * Currently only WebKit-based Web Inspectors, Firefox >= v31, + * and the Firebug extension (any Firefox version) are known + * to support "%c" CSS customizations. + * + * TODO: add a `localStorage` variable to explicitly enable/disable colors + */ +// eslint-disable-next-line complexity + +function useColors() { + // NB: In an Electron preload script, document will be defined but not fully + // initialized. Since we know we're in Chrome, we'll just detect this case + // explicitly + if (typeof window !== 'undefined' && window.process && (window.process.type === 'renderer' || window.process.__nwjs)) { + return true; + } // Internet Explorer and Edge do not support colors. + + + if (typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/)) { + return false; + } // Is webkit? http://stackoverflow.com/a/16459606/376773 + // document is undefined in react-native: https://github.com/facebook/react-native/pull/1632 + + + return typeof document !== 'undefined' && document.documentElement && document.documentElement.style && document.documentElement.style.WebkitAppearance || // Is firebug? http://stackoverflow.com/a/398120/376773 + typeof window !== 'undefined' && window.console && (window.console.firebug || window.console.exception && window.console.table) || // Is firefox >= v31? + // https://developer.mozilla.org/en-US/docs/Tools/Web_Console#Styling_messages + typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/) && parseInt(RegExp.$1, 10) >= 31 || // Double check webkit in userAgent just in case we are in a worker + typeof navigator !== 'undefined' && navigator.userAgent && navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/); +} +/** + * Colorize log arguments if enabled. + * + * @api public + */ + + +function formatArgs(args) { + args[0] = (this.useColors ? '%c' : '') + this.namespace + (this.useColors ? ' %c' : ' ') + args[0] + (this.useColors ? '%c ' : ' ') + '+' + module.exports.humanize(this.diff); + + if (!this.useColors) { + return; + } + + var c = 'color: ' + this.color; + args.splice(1, 0, c, 'color: inherit'); // The final "%c" is somewhat tricky, because there could be other + // arguments passed either before or after the %c, so we need to + // figure out the correct index to insert the CSS into + + var index = 0; + var lastC = 0; + args[0].replace(/%[a-zA-Z%]/g, function (match) { + if (match === '%%') { + return; } - var other = new Array(arr.length); + index++; - for (var i = 0, n = arr.length; i < n; i++) { - other[i] = mapper.call(that, arr[i], i, arr); + if (match === '%c') { + // We only are interested in the *last* %c + // (the user may have provided their own) + lastC = index; } - return other; + }); + args.splice(lastC, 0, c); +} +/** + * Invokes `console.log()` when available. + * No-op when `console.log` is not a "function". + * + * @api public + */ + + +function log() { + var _console; + + // This hackery is required for IE8/9, where + // the `console.log` function doesn't have 'apply' + return (typeof console === "undefined" ? "undefined" : _typeof(console)) === 'object' && console.log && (_console = console).log.apply(_console, arguments); +} +/** + * Save `namespaces`. + * + * @param {String} namespaces + * @api private + */ + + +function save(namespaces) { + try { + if (namespaces) { + exports.storage.setItem('debug', namespaces); + } else { + exports.storage.removeItem('debug'); + } + } catch (error) {// Swallow + // XXX (@Qix-) should we be logging these? } - function clonePath(path) { - return { newPos: path.newPos, components: path.components.slice(0) }; +} +/** + * Load `namespaces`. + * + * @return {String} returns the previously persisted debug modes + * @api private + */ + + +function load() { + var r; + + try { + r = exports.storage.getItem('debug'); + } catch (error) {} // Swallow + // XXX (@Qix-) should we be logging these? + // If debug isn't set in LS, and we're in Electron, try to load $DEBUG + + + if (!r && typeof process !== 'undefined' && 'env' in process) { + r = process.env.DEBUG; } - function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); + + return r; +} +/** + * Localstorage attempts to return the localstorage. + * + * This is necessary because safari throws + * when a user disables cookies/localstorage + * and you attempt to access it. + * + * @return {LocalStorage} + * @api private + */ + + +function localstorage() { + try { + // TVMLKit (Apple TV JS Runtime) does not have a window object, just localStorage in the global context + // The Browser also has localStorage in the global context. + return localStorage; + } catch (error) {// Swallow + // XXX (@Qix-) should we be logging these? + } +} + +module.exports = require('./common')(exports); +var formatters = module.exports.formatters; +/** + * Map %j to `JSON.stringify()`, since no Web Inspectors do that by default. + */ + +formatters.j = function (v) { + try { + return JSON.stringify(v); + } catch (error) { + return '[UnexpectedJSONParseError]: ' + error.message; + } +}; + + +}).call(this,require('_process')) +},{"./common":46,"_process":69}],46:[function(require,module,exports){ +"use strict"; + +/** + * This is the common logic for both the Node.js and web browser + * implementations of `debug()`. + */ +function setup(env) { + createDebug.debug = createDebug; + createDebug.default = createDebug; + createDebug.coerce = coerce; + createDebug.disable = disable; + createDebug.enable = enable; + createDebug.enabled = enabled; + createDebug.humanize = require('ms'); + Object.keys(env).forEach(function (key) { + createDebug[key] = env[key]; + }); + /** + * Active `debug` instances. + */ + + createDebug.instances = []; + /** + * The currently active debug mode names, and names to skip. + */ + + createDebug.names = []; + createDebug.skips = []; + /** + * Map of special "%n" handling functions, for the debug "format" argument. + * + * Valid key names are a single, lower or upper-case letter, i.e. "n" and "N". + */ + + createDebug.formatters = {}; + /** + * Selects a color for a debug namespace + * @param {String} namespace The namespace string for the for the debug instance to be colored + * @return {Number|String} An ANSI color code for the given namespace + * @api private + */ + + function selectColor(namespace) { + var hash = 0; + + for (var i = 0; i < namespace.length; i++) { + hash = (hash << 5) - hash + namespace.charCodeAt(i); + hash |= 0; // Convert to 32bit integer + } + + return createDebug.colors[Math.abs(hash) % createDebug.colors.length]; + } + + createDebug.selectColor = selectColor; + /** + * Create a debugger with the given `namespace`. + * + * @param {String} namespace + * @return {Function} + * @api public + */ + + function createDebug(namespace) { + var prevTime; + + function debug() { + // Disabled? + if (!debug.enabled) { + return; + } + + for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { + args[_key] = arguments[_key]; + } + + var self = debug; // Set `diff` timestamp + + var curr = Number(new Date()); + var ms = curr - (prevTime || curr); + self.diff = ms; + self.prev = prevTime; + self.curr = curr; + prevTime = curr; + args[0] = createDebug.coerce(args[0]); + + if (typeof args[0] !== 'string') { + // Anything else let's inspect with %O + args.unshift('%O'); + } // Apply any `formatters` transformations + + + var index = 0; + args[0] = args[0].replace(/%([a-zA-Z%])/g, function (match, format) { + // If we encounter an escaped % then don't increase the array index + if (match === '%%') { + return match; + } + + index++; + var formatter = createDebug.formatters[format]; + + if (typeof formatter === 'function') { + var val = args[index]; + match = formatter.call(self, val); // Now we need to remove `args[index]` since it's inlined in the `format` + + args.splice(index, 1); + index--; + } + + return match; + }); // Apply env-specific formatting (colors, etc.) + + createDebug.formatArgs.call(self, args); + var logFn = self.log || createDebug.log; + logFn.apply(self, args); + } + + debug.namespace = namespace; + debug.enabled = createDebug.enabled(namespace); + debug.useColors = createDebug.useColors(); + debug.color = selectColor(namespace); + debug.destroy = destroy; + debug.extend = extend; // Debug.formatArgs = formatArgs; + // debug.rawLog = rawLog; + // env-specific initialization logic for debug instances + + if (typeof createDebug.init === 'function') { + createDebug.init(debug); + } + + createDebug.instances.push(debug); + return debug; + } + + function destroy() { + var index = createDebug.instances.indexOf(this); + + if (index !== -1) { + createDebug.instances.splice(index, 1); + return true; + } + + return false; + } + + function extend(namespace, delimiter) { + return createDebug(this.namespace + (typeof delimiter === 'undefined' ? ':' : delimiter) + namespace); + } + /** + * Enables a debug mode by namespaces. This can include modes + * separated by a colon and wildcards. + * + * @param {String} namespaces + * @api public + */ + + + function enable(namespaces) { + createDebug.save(namespaces); + createDebug.names = []; + createDebug.skips = []; + var i; + var split = (typeof namespaces === 'string' ? namespaces : '').split(/[\s,]+/); + var len = split.length; + + for (i = 0; i < len; i++) { + if (!split[i]) { + // ignore empty strings + continue; + } + + namespaces = split[i].replace(/\*/g, '.*?'); + + if (namespaces[0] === '-') { + createDebug.skips.push(new RegExp('^' + namespaces.substr(1) + '$')); + } else { + createDebug.names.push(new RegExp('^' + namespaces + '$')); } } - return ret; - } - function escapeHTML(s) { - var n = s; - n = n.replace(/&/g, '&'); - n = n.replace(/</g, '<'); - n = n.replace(/>/g, '>'); - n = n.replace(/"/g, '"'); - return n; + for (i = 0; i < createDebug.instances.length; i++) { + var instance = createDebug.instances[i]; + instance.enabled = createDebug.enabled(instance.namespace); + } } + /** + * Disable debug output. + * + * @api public + */ - // This function handles the presence of circular references by bailing out when encountering an - // object that is already on the "stack" of items being processed. - function canonicalize(obj, stack, replacementStack) { - stack = stack || []; - replacementStack = replacementStack || []; + + function disable() { + createDebug.enable(''); + } + /** + * Returns true if the given mode name is enabled, false otherwise. + * + * @param {String} name + * @return {Boolean} + * @api public + */ + + + function enabled(name) { + if (name[name.length - 1] === '*') { + return true; + } var i; + var len; - for (i = 0; i < stack.length; i += 1) { - if (stack[i] === obj) { - return replacementStack[i]; + for (i = 0, len = createDebug.skips.length; i < len; i++) { + if (createDebug.skips[i].test(name)) { + return false; } } - var canonicalizedObj; - - if ('[object Array]' === objectPrototypeToString.call(obj)) { - stack.push(obj); - canonicalizedObj = new Array(obj.length); - replacementStack.push(canonicalizedObj); - for (i = 0; i < obj.length; i += 1) { - canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack); + for (i = 0, len = createDebug.names.length; i < len; i++) { + if (createDebug.names[i].test(name)) { + return true; } - stack.pop(); - replacementStack.pop(); - } else if (typeof obj === 'object' && obj !== null) { - stack.push(obj); - canonicalizedObj = {}; - replacementStack.push(canonicalizedObj); - var sortedKeys = [], - key; - for (key in obj) { - sortedKeys.push(key); - } - sortedKeys.sort(); - for (i = 0; i < sortedKeys.length; i += 1) { - key = sortedKeys[i]; - canonicalizedObj[key] = canonicalize(obj[key], stack, replacementStack); - } - stack.pop(); - replacementStack.pop(); - } else { - canonicalizedObj = obj; } - return canonicalizedObj; + + return false; + } + /** + * Coerce `val`. + * + * @param {Mixed} val + * @return {Mixed} + * @api private + */ + + + function coerce(val) { + if (val instanceof Error) { + return val.stack || val.message; + } + + return val; } - function buildValues(components, newString, oldString, useLongestToken) { - var componentPos = 0, - componentLen = components.length, - newPos = 0, - oldPos = 0; + createDebug.enable(createDebug.load()); + return createDebug; +} + +module.exports = setup; + + +},{"ms":60}],47:[function(require,module,exports){ +'use strict'; + +var keys = require('object-keys'); +var hasSymbols = typeof Symbol === 'function' && typeof Symbol('foo') === 'symbol'; + +var toStr = Object.prototype.toString; +var concat = Array.prototype.concat; +var origDefineProperty = Object.defineProperty; + +var isFunction = function (fn) { + return typeof fn === 'function' && toStr.call(fn) === '[object Function]'; +}; + +var arePropertyDescriptorsSupported = function () { + var obj = {}; + try { + origDefineProperty(obj, 'x', { enumerable: false, value: obj }); + // eslint-disable-next-line no-unused-vars, no-restricted-syntax + for (var _ in obj) { // jscs:ignore disallowUnusedVariables + return false; + } + return obj.x === obj; + } catch (e) { /* this is IE 8. */ + return false; + } +}; +var supportsDescriptors = origDefineProperty && arePropertyDescriptorsSupported(); + +var defineProperty = function (object, name, value, predicate) { + if (name in object && (!isFunction(predicate) || !predicate())) { + return; + } + if (supportsDescriptors) { + origDefineProperty(object, name, { + configurable: true, + enumerable: false, + value: value, + writable: true + }); + } else { + object[name] = value; + } +}; + +var defineProperties = function (object, map) { + var predicates = arguments.length > 2 ? arguments[2] : {}; + var props = keys(map); + if (hasSymbols) { + props = concat.call(props, Object.getOwnPropertySymbols(map)); + } + for (var i = 0; i < props.length; i += 1) { + defineProperty(object, props[i], map[props[i]], predicates[props[i]]); + } +}; + +defineProperties.supportsDescriptors = !!supportsDescriptors; + +module.exports = defineProperties; + +},{"object-keys":62}],48:[function(require,module,exports){ +/*! + + diff v3.5.0 + +Software License Agreement (BSD License) + +Copyright (c) 2009-2015, Kevin Decker <kpdecker@gmail.com> + +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Kevin Decker nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +@license +*/ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(false) + define([], factory); + else if(typeof exports === 'object') + exports["JsDiff"] = factory(); + else + root["JsDiff"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.canonicalize = exports.convertChangesToXML = exports.convertChangesToDMP = exports.merge = exports.parsePatch = exports.applyPatches = exports.applyPatch = exports.createPatch = exports.createTwoFilesPatch = exports.structuredPatch = exports.diffArrays = exports.diffJson = exports.diffCss = exports.diffSentences = exports.diffTrimmedLines = exports.diffLines = exports.diffWordsWithSpace = exports.diffWords = exports.diffChars = exports.Diff = undefined; + + /*istanbul ignore end*/var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + /*istanbul ignore end*/var /*istanbul ignore start*/_character = __webpack_require__(2) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_word = __webpack_require__(3) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_sentence = __webpack_require__(6) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_css = __webpack_require__(7) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_json = __webpack_require__(8) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_array = __webpack_require__(9) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_apply = __webpack_require__(10) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_merge = __webpack_require__(13) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_create = __webpack_require__(14) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_dmp = __webpack_require__(16) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_xml = __webpack_require__(17) /*istanbul ignore end*/; + + /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /* See LICENSE file for terms of use */ + + /* + * Text diff implementation. + * + * This library supports the following APIS: + * JsDiff.diffChars: Character by character diff + * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace + * JsDiff.diffLines: Line based diff + * + * JsDiff.diffCss: Diff targeted at CSS content + * + * These methods are based on the implementation proposed in + * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + */ + exports. /*istanbul ignore end*/Diff = _base2['default']; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffChars = _character.diffChars; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWords = _word.diffWords; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWordsWithSpace = _word.diffWordsWithSpace; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffLines = _line.diffLines; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffTrimmedLines = _line.diffTrimmedLines; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffSentences = _sentence.diffSentences; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffCss = _css.diffCss; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffJson = _json.diffJson; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffArrays = _array.diffArrays; + /*istanbul ignore start*/exports. /*istanbul ignore end*/structuredPatch = _create.structuredPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/createTwoFilesPatch = _create.createTwoFilesPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/createPatch = _create.createPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatch = _apply.applyPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatches = _apply.applyPatches; + /*istanbul ignore start*/exports. /*istanbul ignore end*/parsePatch = _parse.parsePatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/merge = _merge.merge; + /*istanbul ignore start*/exports. /*istanbul ignore end*/convertChangesToDMP = _dmp.convertChangesToDMP; + /*istanbul ignore start*/exports. /*istanbul ignore end*/convertChangesToXML = _xml.convertChangesToXML; + /*istanbul ignore start*/exports. /*istanbul ignore end*/canonicalize = _json.canonicalize; + + + +/***/ }), +/* 1 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports['default'] = /*istanbul ignore end*/Diff; + function Diff() {} + + Diff.prototype = { + /*istanbul ignore start*/ /*istanbul ignore end*/diff: function diff(oldString, newString) { + /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + var callback = options.callback; + if (typeof options === 'function') { + callback = options; + options = {}; + } + this.options = options; + + var self = this; + + function done(value) { + if (callback) { + setTimeout(function () { + callback(undefined, value); + }, 0); + return true; + } else { + return value; + } + } + + // Allow subclasses to massage the input prior to running + oldString = this.castInput(oldString); + newString = this.castInput(newString); + + oldString = this.removeEmpty(this.tokenize(oldString)); + newString = this.removeEmpty(this.tokenize(newString)); + + var newLen = newString.length, + oldLen = oldString.length; + var editLength = 1; + var maxEditLength = newLen + oldLen; + var bestPath = [{ newPos: -1, components: [] }]; + + // Seed editLength = 0, i.e. the content starts with the same values + var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); + if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { + // Identity per the equality and tokenizer + return done([{ value: this.join(newString), count: newString.length }]); + } + + // Main worker method. checks all permutations of a given edit length for acceptance. + function execEditLength() { + for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { + var basePath = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + var addPath = bestPath[diagonalPath - 1], + removePath = bestPath[diagonalPath + 1], + _oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; + if (addPath) { + // No one else is going to attempt to use this value, clear it + bestPath[diagonalPath - 1] = undefined; + } + + var canAdd = addPath && addPath.newPos + 1 < newLen, + canRemove = removePath && 0 <= _oldPos && _oldPos < oldLen; + if (!canAdd && !canRemove) { + // If this path is a terminal then prune + bestPath[diagonalPath] = undefined; + continue; + } + + // Select the diagonal that we want to branch from. We select the prior + // path whose position in the new string is the farthest from the origin + // and does not pass the bounds of the diff graph + if (!canAdd || canRemove && addPath.newPos < removePath.newPos) { + basePath = clonePath(removePath); + self.pushComponent(basePath.components, undefined, true); + } else { + basePath = addPath; // No need to clone, we've pulled it from the list + basePath.newPos++; + self.pushComponent(basePath.components, true, undefined); + } + + _oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); + + // If we have hit the end of both strings, then we are done + if (basePath.newPos + 1 >= newLen && _oldPos + 1 >= oldLen) { + return done(buildValues(self, basePath.components, newString, oldString, self.useLongestToken)); + } else { + // Otherwise track this path as a potential candidate and continue. + bestPath[diagonalPath] = basePath; + } + } + + editLength++; + } + + // Performs the length of edit iteration. Is a bit fugly as this has to support the + // sync and async mode which is never fun. Loops over execEditLength until a value + // is produced. + if (callback) { + (function exec() { + setTimeout(function () { + // This should not happen, but we want to be safe. + /* istanbul ignore next */ + if (editLength > maxEditLength) { + return callback(); + } + + if (!execEditLength()) { + exec(); + } + }, 0); + })(); + } else { + while (editLength <= maxEditLength) { + var ret = execEditLength(); + if (ret) { + return ret; + } + } + } + }, + /*istanbul ignore start*/ /*istanbul ignore end*/pushComponent: function pushComponent(components, added, removed) { + var last = components[components.length - 1]; + if (last && last.added === added && last.removed === removed) { + // We need to clone here as the component clone operation is just + // as shallow array clone + components[components.length - 1] = { count: last.count + 1, added: added, removed: removed }; + } else { + components.push({ count: 1, added: added, removed: removed }); + } + }, + /*istanbul ignore start*/ /*istanbul ignore end*/extractCommon: function extractCommon(basePath, newString, oldString, diagonalPath) { + var newLen = newString.length, + oldLen = oldString.length, + newPos = basePath.newPos, + oldPos = newPos - diagonalPath, + commonCount = 0; + while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) { + newPos++; + oldPos++; + commonCount++; + } + + if (commonCount) { + basePath.components.push({ count: commonCount }); + } + + basePath.newPos = newPos; + return oldPos; + }, + /*istanbul ignore start*/ /*istanbul ignore end*/equals: function equals(left, right) { + if (this.options.comparator) { + return this.options.comparator(left, right); + } else { + return left === right || this.options.ignoreCase && left.toLowerCase() === right.toLowerCase(); + } + }, + /*istanbul ignore start*/ /*istanbul ignore end*/removeEmpty: function removeEmpty(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + }, + /*istanbul ignore start*/ /*istanbul ignore end*/castInput: function castInput(value) { + return value; + }, + /*istanbul ignore start*/ /*istanbul ignore end*/tokenize: function tokenize(value) { + return value.split(''); + }, + /*istanbul ignore start*/ /*istanbul ignore end*/join: function join(chars) { + return chars.join(''); + } + }; + + function buildValues(diff, components, newString, oldString, useLongestToken) { + var componentPos = 0, + componentLen = components.length, + newPos = 0, + oldPos = 0; + + for (; componentPos < componentLen; componentPos++) { + var component = components[componentPos]; + if (!component.removed) { + if (!component.added && useLongestToken) { + var value = newString.slice(newPos, newPos + component.count); + value = value.map(function (value, i) { + var oldValue = oldString[oldPos + i]; + return oldValue.length > value.length ? oldValue : value; + }); + + component.value = diff.join(value); + } else { + component.value = diff.join(newString.slice(newPos, newPos + component.count)); + } + newPos += component.count; + + // Common case + if (!component.added) { + oldPos += component.count; + } + } else { + component.value = diff.join(oldString.slice(oldPos, oldPos + component.count)); + oldPos += component.count; + + // Reverse add and remove so removes are output first to match common convention + // The diffing algorithm is tied to add then remove output and this is the simplest + // route to get the desired output with minimal overhead. + if (componentPos && components[componentPos - 1].added) { + var tmp = components[componentPos - 1]; + components[componentPos - 1] = components[componentPos]; + components[componentPos] = tmp; + } + } + } + + // Special case handle for when one terminal is ignored (i.e. whitespace). + // For this case we merge the terminal into the prior string and drop the change. + // This is only available for string mode. + var lastComponent = components[componentLen - 1]; + if (componentLen > 1 && typeof lastComponent.value === 'string' && (lastComponent.added || lastComponent.removed) && diff.equals('', lastComponent.value)) { + components[componentLen - 2].value += lastComponent.value; + components.pop(); + } + + return components; + } + + function clonePath(path) { + return { newPos: path.newPos, components: path.components.slice(0) }; + } + + + +/***/ }), +/* 2 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.characterDiff = undefined; + exports. /*istanbul ignore end*/diffChars = diffChars; + + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/var characterDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/characterDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + function diffChars(oldStr, newStr, options) { + return characterDiff.diff(oldStr, newStr, options); + } + + + +/***/ }), +/* 3 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.wordDiff = undefined; + exports. /*istanbul ignore end*/diffWords = diffWords; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffWordsWithSpace = diffWordsWithSpace; + + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + /*istanbul ignore end*/var /*istanbul ignore start*/_params = __webpack_require__(4) /*istanbul ignore end*/; + + /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/ // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode + // + // Ranges and exceptions: + // Latin-1 Supplement, 0080–00FF + // - U+00D7 × Multiplication sign + // - U+00F7 ÷ Division sign + // Latin Extended-A, 0100–017F + // Latin Extended-B, 0180–024F + // IPA Extensions, 0250–02AF + // Spacing Modifier Letters, 02B0–02FF + // - U+02C7 ˇ ˇ Caron + // - U+02D8 ˘ ˘ Breve + // - U+02D9 ˙ ˙ Dot Above + // - U+02DA ˚ ˚ Ring Above + // - U+02DB ˛ ˛ Ogonek + // - U+02DC ˜ ˜ Small Tilde + // - U+02DD ˝ ˝ Double Acute Accent + // Latin Extended Additional, 1E00–1EFF + var extendedWordChars = /^[A-Za-z\xC0-\u02C6\u02C8-\u02D7\u02DE-\u02FF\u1E00-\u1EFF]+$/; + + var reWhitespace = /\S/; + + var wordDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/wordDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + wordDiff.equals = function (left, right) { + if (this.options.ignoreCase) { + left = left.toLowerCase(); + right = right.toLowerCase(); + } + return left === right || this.options.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right); + }; + wordDiff.tokenize = function (value) { + var tokens = value.split(/(\s+|\b)/); + + // Join the boundary splits that we do not consider to be boundaries. This is primarily the extended Latin character set. + for (var i = 0; i < tokens.length - 1; i++) { + // If we have an empty string in the next field and we have only word chars before and after, merge + if (!tokens[i + 1] && tokens[i + 2] && extendedWordChars.test(tokens[i]) && extendedWordChars.test(tokens[i + 2])) { + tokens[i] += tokens[i + 2]; + tokens.splice(i + 1, 2); + i--; + } + } + + return tokens; + }; + + function diffWords(oldStr, newStr, options) { + options = /*istanbul ignore start*/(0, _params.generateOptions) /*istanbul ignore end*/(options, { ignoreWhitespace: true }); + return wordDiff.diff(oldStr, newStr, options); + } + + function diffWordsWithSpace(oldStr, newStr, options) { + return wordDiff.diff(oldStr, newStr, options); + } + + + +/***/ }), +/* 4 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports. /*istanbul ignore end*/generateOptions = generateOptions; + function generateOptions(options, defaults) { + if (typeof options === 'function') { + defaults.callback = options; + } else if (options) { + for (var name in options) { + /* istanbul ignore else */ + if (options.hasOwnProperty(name)) { + defaults[name] = options[name]; + } + } + } + return defaults; + } + + + +/***/ }), +/* 5 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.lineDiff = undefined; + exports. /*istanbul ignore end*/diffLines = diffLines; + /*istanbul ignore start*/exports. /*istanbul ignore end*/diffTrimmedLines = diffTrimmedLines; + + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + /*istanbul ignore end*/var /*istanbul ignore start*/_params = __webpack_require__(4) /*istanbul ignore end*/; + + /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/var lineDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/lineDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + lineDiff.tokenize = function (value) { + var retLines = [], + linesAndNewlines = value.split(/(\n|\r\n)/); + + // Ignore the final empty token that occurs if the string ends with a new line + if (!linesAndNewlines[linesAndNewlines.length - 1]) { + linesAndNewlines.pop(); + } + + // Merge the content and line separators into single tokens + for (var i = 0; i < linesAndNewlines.length; i++) { + var line = linesAndNewlines[i]; + + if (i % 2 && !this.options.newlineIsToken) { + retLines[retLines.length - 1] += line; + } else { + if (this.options.ignoreWhitespace) { + line = line.trim(); + } + retLines.push(line); + } + } + + return retLines; + }; + + function diffLines(oldStr, newStr, callback) { + return lineDiff.diff(oldStr, newStr, callback); + } + function diffTrimmedLines(oldStr, newStr, callback) { + var options = /*istanbul ignore start*/(0, _params.generateOptions) /*istanbul ignore end*/(callback, { ignoreWhitespace: true }); + return lineDiff.diff(oldStr, newStr, options); + } + + + +/***/ }), +/* 6 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.sentenceDiff = undefined; + exports. /*istanbul ignore end*/diffSentences = diffSentences; + + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/var sentenceDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/sentenceDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + sentenceDiff.tokenize = function (value) { + return value.split(/(\S.+?[.!?])(?=\s+|$)/); + }; + + function diffSentences(oldStr, newStr, callback) { + return sentenceDiff.diff(oldStr, newStr, callback); + } + + + +/***/ }), +/* 7 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.cssDiff = undefined; + exports. /*istanbul ignore end*/diffCss = diffCss; + + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/var cssDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/cssDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + cssDiff.tokenize = function (value) { + return value.split(/([{}:;,]|\s+)/); + }; + + function diffCss(oldStr, newStr, callback) { + return cssDiff.diff(oldStr, newStr, callback); + } + + + +/***/ }), +/* 8 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.jsonDiff = undefined; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + + exports. /*istanbul ignore end*/diffJson = diffJson; + /*istanbul ignore start*/exports. /*istanbul ignore end*/canonicalize = canonicalize; + + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + /*istanbul ignore end*/var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; + + /*istanbul ignore start*/function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/var objectPrototypeToString = Object.prototype.toString; + + var jsonDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/jsonDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a + // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output: + jsonDiff.useLongestToken = true; + + jsonDiff.tokenize = /*istanbul ignore start*/_line.lineDiff /*istanbul ignore end*/.tokenize; + jsonDiff.castInput = function (value) { + /*istanbul ignore start*/var _options = /*istanbul ignore end*/this.options, + undefinedReplacement = _options.undefinedReplacement, + _options$stringifyRep = _options.stringifyReplacer, + stringifyReplacer = _options$stringifyRep === undefined ? function (k, v) /*istanbul ignore start*/{ + return (/*istanbul ignore end*/typeof v === 'undefined' ? undefinedReplacement : v + ); + } : _options$stringifyRep; + + + return typeof value === 'string' ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), stringifyReplacer, ' '); + }; + jsonDiff.equals = function (left, right) { + return (/*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/.prototype.equals.call(jsonDiff, left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1')) + ); + }; + + function diffJson(oldObj, newObj, options) { + return jsonDiff.diff(oldObj, newObj, options); + } + + // This function handles the presence of circular references by bailing out when encountering an + // object that is already on the "stack" of items being processed. Accepts an optional replacer + function canonicalize(obj, stack, replacementStack, replacer, key) { + stack = stack || []; + replacementStack = replacementStack || []; + + if (replacer) { + obj = replacer(key, obj); + } + + var i = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + + for (i = 0; i < stack.length; i += 1) { + if (stack[i] === obj) { + return replacementStack[i]; + } + } + + var canonicalizedObj = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + + if ('[object Array]' === objectPrototypeToString.call(obj)) { + stack.push(obj); + canonicalizedObj = new Array(obj.length); + replacementStack.push(canonicalizedObj); + for (i = 0; i < obj.length; i += 1) { + canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, key); + } + stack.pop(); + replacementStack.pop(); + return canonicalizedObj; + } + + if (obj && obj.toJSON) { + obj = obj.toJSON(); + } + + if ( /*istanbul ignore start*/(typeof /*istanbul ignore end*/obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' && obj !== null) { + stack.push(obj); + canonicalizedObj = {}; + replacementStack.push(canonicalizedObj); + var sortedKeys = [], + _key = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + for (_key in obj) { + /* istanbul ignore else */ + if (obj.hasOwnProperty(_key)) { + sortedKeys.push(_key); + } + } + sortedKeys.sort(); + for (i = 0; i < sortedKeys.length; i += 1) { + _key = sortedKeys[i]; + canonicalizedObj[_key] = canonicalize(obj[_key], stack, replacementStack, replacer, _key); + } + stack.pop(); + replacementStack.pop(); + } else { + canonicalizedObj = obj; + } + return canonicalizedObj; + } + + + +/***/ }), +/* 9 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports.arrayDiff = undefined; + exports. /*istanbul ignore end*/diffArrays = diffArrays; + + var /*istanbul ignore start*/_base = __webpack_require__(1) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _base2 = _interopRequireDefault(_base); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/var arrayDiff = /*istanbul ignore start*/exports. /*istanbul ignore end*/arrayDiff = new /*istanbul ignore start*/_base2['default'] /*istanbul ignore end*/(); + arrayDiff.tokenize = function (value) { + return value.slice(); + }; + arrayDiff.join = arrayDiff.removeEmpty = function (value) { + return value; + }; + + function diffArrays(oldArr, newArr, callback) { + return arrayDiff.diff(oldArr, newArr, callback); + } + + + +/***/ }), +/* 10 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports. /*istanbul ignore end*/applyPatch = applyPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/applyPatches = applyPatches; + + var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_distanceIterator = __webpack_require__(12) /*istanbul ignore end*/; + + /*istanbul ignore start*/var _distanceIterator2 = _interopRequireDefault(_distanceIterator); + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + /*istanbul ignore end*/function applyPatch(source, uniDiff) { + /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + + if (typeof uniDiff === 'string') { + uniDiff = /*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(uniDiff); + } + + if (Array.isArray(uniDiff)) { + if (uniDiff.length > 1) { + throw new Error('applyPatch only works with a single input.'); + } + + uniDiff = uniDiff[0]; + } + + // Apply the diff to the input + var lines = source.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = source.match(/\r\n|[\n\v\f\r\x85]/g) || [], + hunks = uniDiff.hunks, + compareLine = options.compareLine || function (lineNumber, line, operation, patchContent) /*istanbul ignore start*/{ + return (/*istanbul ignore end*/line === patchContent + ); + }, + errorCount = 0, + fuzzFactor = options.fuzzFactor || 0, + minLine = 0, + offset = 0, + removeEOFNL = /*istanbul ignore start*/void 0 /*istanbul ignore end*/, + addEOFNL = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + + /** + * Checks if the hunk exactly fits on the provided location + */ + function hunkFits(hunk, toPos) { + for (var j = 0; j < hunk.lines.length; j++) { + var line = hunk.lines[j], + operation = line.length > 0 ? line[0] : ' ', + content = line.length > 0 ? line.substr(1) : line; + + if (operation === ' ' || operation === '-') { + // Context sanity check + if (!compareLine(toPos + 1, lines[toPos], operation, content)) { + errorCount++; + + if (errorCount > fuzzFactor) { + return false; + } + } + toPos++; + } + } + + return true; + } + + // Search best fit offsets for each hunk based on the previous ones + for (var i = 0; i < hunks.length; i++) { + var hunk = hunks[i], + maxLine = lines.length - hunk.oldLines, + localOffset = 0, + toPos = offset + hunk.oldStart - 1; + + var iterator = /*istanbul ignore start*/(0, _distanceIterator2['default']) /*istanbul ignore end*/(toPos, minLine, maxLine); + + for (; localOffset !== undefined; localOffset = iterator()) { + if (hunkFits(hunk, toPos + localOffset)) { + hunk.offset = offset += localOffset; + break; + } + } + + if (localOffset === undefined) { + return false; + } + + // Set lower text limit to end of the current hunk, so next ones don't try + // to fit over already patched text + minLine = hunk.offset + hunk.oldStart + hunk.oldLines; + } + + // Apply patch hunks + var diffOffset = 0; + for (var _i = 0; _i < hunks.length; _i++) { + var _hunk = hunks[_i], + _toPos = _hunk.oldStart + _hunk.offset + diffOffset - 1; + diffOffset += _hunk.newLines - _hunk.oldLines; + + if (_toPos < 0) { + // Creating a new file + _toPos = 0; + } + + for (var j = 0; j < _hunk.lines.length; j++) { + var line = _hunk.lines[j], + operation = line.length > 0 ? line[0] : ' ', + content = line.length > 0 ? line.substr(1) : line, + delimiter = _hunk.linedelimiters[j]; + + if (operation === ' ') { + _toPos++; + } else if (operation === '-') { + lines.splice(_toPos, 1); + delimiters.splice(_toPos, 1); + /* istanbul ignore else */ + } else if (operation === '+') { + lines.splice(_toPos, 0, content); + delimiters.splice(_toPos, 0, delimiter); + _toPos++; + } else if (operation === '\\') { + var previousOperation = _hunk.lines[j - 1] ? _hunk.lines[j - 1][0] : null; + if (previousOperation === '+') { + removeEOFNL = true; + } else if (previousOperation === '-') { + addEOFNL = true; + } + } + } + } + + // Handle EOFNL insertion/removal + if (removeEOFNL) { + while (!lines[lines.length - 1]) { + lines.pop(); + delimiters.pop(); + } + } else if (addEOFNL) { + lines.push(''); + delimiters.push('\n'); + } + for (var _k = 0; _k < lines.length - 1; _k++) { + lines[_k] = lines[_k] + delimiters[_k]; + } + return lines.join(''); + } + + // Wrapper that supports multiple file patches via callbacks. + function applyPatches(uniDiff, options) { + if (typeof uniDiff === 'string') { + uniDiff = /*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(uniDiff); + } + + var currentIndex = 0; + function processIndex() { + var index = uniDiff[currentIndex++]; + if (!index) { + return options.complete(); + } + + options.loadFile(index, function (err, data) { + if (err) { + return options.complete(err); + } + + var updatedContent = applyPatch(data, index, options); + options.patched(index, updatedContent, function (err) { + if (err) { + return options.complete(err); + } + + processIndex(); + }); + }); + } + processIndex(); + } + + + +/***/ }), +/* 11 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports. /*istanbul ignore end*/parsePatch = parsePatch; + function parsePatch(uniDiff) { + /*istanbul ignore start*/var /*istanbul ignore end*/options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; + + var diffstr = uniDiff.split(/\r\n|[\n\v\f\r\x85]/), + delimiters = uniDiff.match(/\r\n|[\n\v\f\r\x85]/g) || [], + list = [], + i = 0; + + function parseIndex() { + var index = {}; + list.push(index); + + // Parse diff metadata + while (i < diffstr.length) { + var line = diffstr[i]; + + // File header found, end parsing diff metadata + if (/^(\-\-\-|\+\+\+|@@)\s/.test(line)) { + break; + } + + // Diff index + var header = /^(?:Index:|diff(?: -r \w+)+)\s+(.+?)\s*$/.exec(line); + if (header) { + index.index = header[1]; + } + + i++; + } + + // Parse file headers if they are defined. Unified diff requires them, but + // there's no technical issues to have an isolated hunk without file header + parseFileHeader(index); + parseFileHeader(index); + + // Parse hunks + index.hunks = []; + + while (i < diffstr.length) { + var _line = diffstr[i]; + + if (/^(Index:|diff|\-\-\-|\+\+\+)\s/.test(_line)) { + break; + } else if (/^@@/.test(_line)) { + index.hunks.push(parseHunk()); + } else if (_line && options.strict) { + // Ignore unexpected content unless in strict mode + throw new Error('Unknown line ' + (i + 1) + ' ' + JSON.stringify(_line)); + } else { + i++; + } + } + } + + // Parses the --- and +++ headers, if none are found, no lines + // are consumed. + function parseFileHeader(index) { + var fileHeader = /^(---|\+\+\+)\s+(.*)$/.exec(diffstr[i]); + if (fileHeader) { + var keyPrefix = fileHeader[1] === '---' ? 'old' : 'new'; + var data = fileHeader[2].split('\t', 2); + var fileName = data[0].replace(/\\\\/g, '\\'); + if (/^".*"$/.test(fileName)) { + fileName = fileName.substr(1, fileName.length - 2); + } + index[keyPrefix + 'FileName'] = fileName; + index[keyPrefix + 'Header'] = (data[1] || '').trim(); + + i++; + } + } + + // Parses a hunk + // This assumes that we are at the start of a hunk. + function parseHunk() { + var chunkHeaderIndex = i, + chunkHeaderLine = diffstr[i++], + chunkHeader = chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/); + + var hunk = { + oldStart: +chunkHeader[1], + oldLines: +chunkHeader[2] || 1, + newStart: +chunkHeader[3], + newLines: +chunkHeader[4] || 1, + lines: [], + linedelimiters: [] + }; + + var addCount = 0, + removeCount = 0; + for (; i < diffstr.length; i++) { + // Lines starting with '---' could be mistaken for the "remove line" operation + // But they could be the header for the next file. Therefore prune such cases out. + if (diffstr[i].indexOf('--- ') === 0 && i + 2 < diffstr.length && diffstr[i + 1].indexOf('+++ ') === 0 && diffstr[i + 2].indexOf('@@') === 0) { + break; + } + var operation = diffstr[i].length == 0 && i != diffstr.length - 1 ? ' ' : diffstr[i][0]; + + if (operation === '+' || operation === '-' || operation === ' ' || operation === '\\') { + hunk.lines.push(diffstr[i]); + hunk.linedelimiters.push(delimiters[i] || '\n'); + + if (operation === '+') { + addCount++; + } else if (operation === '-') { + removeCount++; + } else if (operation === ' ') { + addCount++; + removeCount++; + } + } else { + break; + } + } + + // Handle the empty block count case + if (!addCount && hunk.newLines === 1) { + hunk.newLines = 0; + } + if (!removeCount && hunk.oldLines === 1) { + hunk.oldLines = 0; + } + + // Perform optional sanity checking + if (options.strict) { + if (addCount !== hunk.newLines) { + throw new Error('Added line count did not match for hunk at line ' + (chunkHeaderIndex + 1)); + } + if (removeCount !== hunk.oldLines) { + throw new Error('Removed line count did not match for hunk at line ' + (chunkHeaderIndex + 1)); + } + } + + return hunk; + } + + while (i < diffstr.length) { + parseIndex(); + } + + return list; + } + + + +/***/ }), +/* 12 */ +/***/ (function(module, exports) { + + /*istanbul ignore start*/"use strict"; + + exports.__esModule = true; + + exports["default"] = /*istanbul ignore end*/function (start, minLine, maxLine) { + var wantForward = true, + backwardExhausted = false, + forwardExhausted = false, + localOffset = 1; + + return function iterator() { + if (wantForward && !forwardExhausted) { + if (backwardExhausted) { + localOffset++; + } else { + wantForward = false; + } + + // Check if trying to fit beyond text length, and if not, check it fits + // after offset location (or desired location on first iteration) + if (start + localOffset <= maxLine) { + return localOffset; + } + + forwardExhausted = true; + } + + if (!backwardExhausted) { + if (!forwardExhausted) { + wantForward = true; + } + + // Check if trying to fit before text beginning, and if not, check it fits + // before offset location + if (minLine <= start - localOffset) { + return -localOffset++; + } + + backwardExhausted = true; + return iterator(); + } + + // We tried to fit hunk before text beginning and beyond text length, then + // hunk can't fit on the text. Return undefined + }; + }; + + + +/***/ }), +/* 13 */ +/***/ (function(module, exports, __webpack_require__) { + + /*istanbul ignore start*/'use strict'; + + exports.__esModule = true; + exports. /*istanbul ignore end*/calcLineCount = calcLineCount; + /*istanbul ignore start*/exports. /*istanbul ignore end*/merge = merge; + + var /*istanbul ignore start*/_create = __webpack_require__(14) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_parse = __webpack_require__(11) /*istanbul ignore end*/; + + var /*istanbul ignore start*/_array = __webpack_require__(15) /*istanbul ignore end*/; + + /*istanbul ignore start*/function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } + + /*istanbul ignore end*/function calcLineCount(hunk) { + /*istanbul ignore start*/var _calcOldNewLineCount = /*istanbul ignore end*/calcOldNewLineCount(hunk.lines), + oldLines = _calcOldNewLineCount.oldLines, + newLines = _calcOldNewLineCount.newLines; + + if (oldLines !== undefined) { + hunk.oldLines = oldLines; + } else { + delete hunk.oldLines; + } + + if (newLines !== undefined) { + hunk.newLines = newLines; + } else { + delete hunk.newLines; + } + } + + function merge(mine, theirs, base) { + mine = loadPatch(mine, base); + theirs = loadPatch(theirs, base); + + var ret = {}; + + // For index we just let it pass through as it doesn't have any necessary meaning. + // Leaving sanity checks on this to the API consumer that may know more about the + // meaning in their own context. + if (mine.index || theirs.index) { + ret.index = mine.index || theirs.index; + } + + if (mine.newFileName || theirs.newFileName) { + if (!fileNameChanged(mine)) { + // No header or no change in ours, use theirs (and ours if theirs does not exist) + ret.oldFileName = theirs.oldFileName || mine.oldFileName; + ret.newFileName = theirs.newFileName || mine.newFileName; + ret.oldHeader = theirs.oldHeader || mine.oldHeader; + ret.newHeader = theirs.newHeader || mine.newHeader; + } else if (!fileNameChanged(theirs)) { + // No header or no change in theirs, use ours + ret.oldFileName = mine.oldFileName; + ret.newFileName = mine.newFileName; + ret.oldHeader = mine.oldHeader; + ret.newHeader = mine.newHeader; + } else { + // Both changed... figure it out + ret.oldFileName = selectField(ret, mine.oldFileName, theirs.oldFileName); + ret.newFileName = selectField(ret, mine.newFileName, theirs.newFileName); + ret.oldHeader = selectField(ret, mine.oldHeader, theirs.oldHeader); + ret.newHeader = selectField(ret, mine.newHeader, theirs.newHeader); + } + } + + ret.hunks = []; + + var mineIndex = 0, + theirsIndex = 0, + mineOffset = 0, + theirsOffset = 0; + + while (mineIndex < mine.hunks.length || theirsIndex < theirs.hunks.length) { + var mineCurrent = mine.hunks[mineIndex] || { oldStart: Infinity }, + theirsCurrent = theirs.hunks[theirsIndex] || { oldStart: Infinity }; + + if (hunkBefore(mineCurrent, theirsCurrent)) { + // This patch does not overlap with any of the others, yay. + ret.hunks.push(cloneHunk(mineCurrent, mineOffset)); + mineIndex++; + theirsOffset += mineCurrent.newLines - mineCurrent.oldLines; + } else if (hunkBefore(theirsCurrent, mineCurrent)) { + // This patch does not overlap with any of the others, yay. + ret.hunks.push(cloneHunk(theirsCurrent, theirsOffset)); + theirsIndex++; + mineOffset += theirsCurrent.newLines - theirsCurrent.oldLines; + } else { + // Overlap, merge as best we can + var mergedHunk = { + oldStart: Math.min(mineCurrent.oldStart, theirsCurrent.oldStart), + oldLines: 0, + newStart: Math.min(mineCurrent.newStart + mineOffset, theirsCurrent.oldStart + theirsOffset), + newLines: 0, + lines: [] + }; + mergeLines(mergedHunk, mineCurrent.oldStart, mineCurrent.lines, theirsCurrent.oldStart, theirsCurrent.lines); + theirsIndex++; + mineIndex++; + + ret.hunks.push(mergedHunk); + } + } + + return ret; + } + + function loadPatch(param, base) { + if (typeof param === 'string') { + if (/^@@/m.test(param) || /^Index:/m.test(param)) { + return (/*istanbul ignore start*/(0, _parse.parsePatch) /*istanbul ignore end*/(param)[0] + ); + } + + if (!base) { + throw new Error('Must provide a base reference or pass in a patch'); + } + return (/*istanbul ignore start*/(0, _create.structuredPatch) /*istanbul ignore end*/(undefined, undefined, base, param) + ); + } + + return param; + } + + function fileNameChanged(patch) { + return patch.newFileName && patch.newFileName !== patch.oldFileName; + } + + function selectField(index, mine, theirs) { + if (mine === theirs) { + return mine; + } else { + index.conflict = true; + return { mine: mine, theirs: theirs }; + } + } + + function hunkBefore(test, check) { + return test.oldStart < check.oldStart && test.oldStart + test.oldLines < check.oldStart; + } + + function cloneHunk(hunk, offset) { + return { + oldStart: hunk.oldStart, oldLines: hunk.oldLines, + newStart: hunk.newStart + offset, newLines: hunk.newLines, + lines: hunk.lines + }; + } + + function mergeLines(hunk, mineOffset, mineLines, theirOffset, theirLines) { + // This will generally result in a conflicted hunk, but there are cases where the context + // is the only overlap where we can successfully merge the content here. + var mine = { offset: mineOffset, lines: mineLines, index: 0 }, + their = { offset: theirOffset, lines: theirLines, index: 0 }; + + // Handle any leading content + insertLeading(hunk, mine, their); + insertLeading(hunk, their, mine); + + // Now in the overlap content. Scan through and select the best changes from each. + while (mine.index < mine.lines.length && their.index < their.lines.length) { + var mineCurrent = mine.lines[mine.index], + theirCurrent = their.lines[their.index]; + + if ((mineCurrent[0] === '-' || mineCurrent[0] === '+') && (theirCurrent[0] === '-' || theirCurrent[0] === '+')) { + // Both modified ... + mutualChange(hunk, mine, their); + } else if (mineCurrent[0] === '+' && theirCurrent[0] === ' ') { + /*istanbul ignore start*/var _hunk$lines; + + /*istanbul ignore end*/ // Mine inserted + /*istanbul ignore start*/(_hunk$lines = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/collectChange(mine))); + } else if (theirCurrent[0] === '+' && mineCurrent[0] === ' ') { + /*istanbul ignore start*/var _hunk$lines2; + + /*istanbul ignore end*/ // Theirs inserted + /*istanbul ignore start*/(_hunk$lines2 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines2 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/collectChange(their))); + } else if (mineCurrent[0] === '-' && theirCurrent[0] === ' ') { + // Mine removed or edited + removal(hunk, mine, their); + } else if (theirCurrent[0] === '-' && mineCurrent[0] === ' ') { + // Their removed or edited + removal(hunk, their, mine, true); + } else if (mineCurrent === theirCurrent) { + // Context identity + hunk.lines.push(mineCurrent); + mine.index++; + their.index++; + } else { + // Context mismatch + conflict(hunk, collectChange(mine), collectChange(their)); + } + } + + // Now push anything that may be remaining + insertTrailing(hunk, mine); + insertTrailing(hunk, their); + + calcLineCount(hunk); + } + + function mutualChange(hunk, mine, their) { + var myChanges = collectChange(mine), + theirChanges = collectChange(their); + + if (allRemoves(myChanges) && allRemoves(theirChanges)) { + // Special case for remove changes that are supersets of one another + if ( /*istanbul ignore start*/(0, _array.arrayStartsWith) /*istanbul ignore end*/(myChanges, theirChanges) && skipRemoveSuperset(their, myChanges, myChanges.length - theirChanges.length)) { + /*istanbul ignore start*/var _hunk$lines3; + + /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines3 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines3 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/myChanges)); + return; + } else if ( /*istanbul ignore start*/(0, _array.arrayStartsWith) /*istanbul ignore end*/(theirChanges, myChanges) && skipRemoveSuperset(mine, theirChanges, theirChanges.length - myChanges.length)) { + /*istanbul ignore start*/var _hunk$lines4; + + /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines4 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines4 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/theirChanges)); + return; + } + } else if ( /*istanbul ignore start*/(0, _array.arrayEqual) /*istanbul ignore end*/(myChanges, theirChanges)) { + /*istanbul ignore start*/var _hunk$lines5; + + /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines5 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines5 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/myChanges)); + return; + } + + conflict(hunk, myChanges, theirChanges); + } + + function removal(hunk, mine, their, swap) { + var myChanges = collectChange(mine), + theirChanges = collectContext(their, myChanges); + if (theirChanges.merged) { + /*istanbul ignore start*/var _hunk$lines6; + + /*istanbul ignore end*/ /*istanbul ignore start*/(_hunk$lines6 = /*istanbul ignore end*/hunk.lines).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_hunk$lines6 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/theirChanges.merged)); + } else { + conflict(hunk, swap ? theirChanges : myChanges, swap ? myChanges : theirChanges); + } + } + + function conflict(hunk, mine, their) { + hunk.conflict = true; + hunk.lines.push({ + conflict: true, + mine: mine, + theirs: their + }); + } + + function insertLeading(hunk, insert, their) { + while (insert.offset < their.offset && insert.index < insert.lines.length) { + var line = insert.lines[insert.index++]; + hunk.lines.push(line); + insert.offset++; + } + } + function insertTrailing(hunk, insert) { + while (insert.index < insert.lines.length) { + var line = insert.lines[insert.index++]; + hunk.lines.push(line); + } + } + + function collectChange(state) { + var ret = [], + operation = state.lines[state.index][0]; + while (state.index < state.lines.length) { + var line = state.lines[state.index]; + + // Group additions that are immediately after subtractions and treat them as one "atomic" modify change. + if (operation === '-' && line[0] === '+') { + operation = '+'; + } + + if (operation === line[0]) { + ret.push(line); + state.index++; + } else { + break; + } + } + + return ret; + } + function collectContext(state, matchChanges) { + var changes = [], + merged = [], + matchIndex = 0, + contextChanges = false, + conflicted = false; + while (matchIndex < matchChanges.length && state.index < state.lines.length) { + var change = state.lines[state.index], + match = matchChanges[matchIndex]; + + // Once we've hit our add, then we are done + if (match[0] === '+') { + break; + } + + contextChanges = contextChanges || change[0] !== ' '; + + merged.push(match); + matchIndex++; - for (; componentPos < componentLen; componentPos++) { - var component = components[componentPos]; - if (!component.removed) { - if (!component.added && useLongestToken) { - var value = newString.slice(newPos, newPos + component.count); - value = map(value, function(value, i) { - var oldValue = oldString[oldPos + i]; - return oldValue.length > value.length ? oldValue : value; - }); + // Consume any additions in the other block as a conflict to attempt + // to pull in the remaining context after this + if (change[0] === '+') { + conflicted = true; - component.value = value.join(''); - } else { - component.value = newString.slice(newPos, newPos + component.count).join(''); - } - newPos += component.count; + while (change[0] === '+') { + changes.push(change); + change = state.lines[++state.index]; + } + } - // Common case - if (!component.added) { - oldPos += component.count; - } - } else { - component.value = oldString.slice(oldPos, oldPos + component.count).join(''); - oldPos += component.count; + if (match.substr(1) === change.substr(1)) { + changes.push(change); + state.index++; + } else { + conflicted = true; + } + } - // Reverse add and remove so removes are output first to match common convention - // The diffing algorithm is tied to add then remove output and this is the simplest - // route to get the desired output with minimal overhead. - if (componentPos && components[componentPos - 1].added) { - var tmp = components[componentPos - 1]; - components[componentPos - 1] = components[componentPos]; - components[componentPos] = tmp; - } - } - } + if ((matchChanges[matchIndex] || '')[0] === '+' && contextChanges) { + conflicted = true; + } - return components; - } + if (conflicted) { + return changes; + } - function Diff(ignoreWhitespace) { - this.ignoreWhitespace = ignoreWhitespace; - } - Diff.prototype = { - diff: function(oldString, newString, callback) { - var self = this; + while (matchIndex < matchChanges.length) { + merged.push(matchChanges[matchIndex++]); + } - function done(value) { - if (callback) { - setTimeout(function() { callback(undefined, value); }, 0); - return true; - } else { - return value; - } - } + return { + merged: merged, + changes: changes + }; + } - // Handle the identity case (this is due to unrolling editLength == 0 - if (newString === oldString) { - return done([{ value: newString }]); - } - if (!newString) { - return done([{ value: oldString, removed: true }]); - } - if (!oldString) { - return done([{ value: newString, added: true }]); - } + function allRemoves(changes) { + return changes.reduce(function (prev, change) { + return prev && change[0] === '-'; + }, true); + } + function skipRemoveSuperset(state, removeChanges, delta) { + for (var i = 0; i < delta; i++) { + var changeContent = removeChanges[removeChanges.length - delta + i].substr(1); + if (state.lines[state.index + i] !== ' ' + changeContent) { + return false; + } + } - newString = this.tokenize(newString); - oldString = this.tokenize(oldString); + state.index += delta; + return true; + } - var newLen = newString.length, oldLen = oldString.length; - var editLength = 1; - var maxEditLength = newLen + oldLen; - var bestPath = [{ newPos: -1, components: [] }]; + function calcOldNewLineCount(lines) { + var oldLines = 0; + var newLines = 0; - // Seed editLength = 0, i.e. the content starts with the same values - var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); - if (bestPath[0].newPos + 1 >= newLen && oldPos + 1 >= oldLen) { - // Identity per the equality and tokenizer - return done([{value: newString.join('')}]); - } + lines.forEach(function (line) { + if (typeof line !== 'string') { + var myCount = calcOldNewLineCount(line.mine); + var theirCount = calcOldNewLineCount(line.theirs); - // Main worker method. checks all permutations of a given edit length for acceptance. - function execEditLength() { - for (var diagonalPath = -1 * editLength; diagonalPath <= editLength; diagonalPath += 2) { - var basePath; - var addPath = bestPath[diagonalPath - 1], - removePath = bestPath[diagonalPath + 1], - oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; - if (addPath) { - // No one else is going to attempt to use this value, clear it - bestPath[diagonalPath - 1] = undefined; - } + if (oldLines !== undefined) { + if (myCount.oldLines === theirCount.oldLines) { + oldLines += myCount.oldLines; + } else { + oldLines = undefined; + } + } - var canAdd = addPath && addPath.newPos + 1 < newLen, - canRemove = removePath && 0 <= oldPos && oldPos < oldLen; - if (!canAdd && !canRemove) { - // If this path is a terminal then prune - bestPath[diagonalPath] = undefined; - continue; - } + if (newLines !== undefined) { + if (myCount.newLines === theirCount.newLines) { + newLines += myCount.newLines; + } else { + newLines = undefined; + } + } + } else { + if (newLines !== undefined && (line[0] === '+' || line[0] === ' ')) { + newLines++; + } + if (oldLines !== undefined && (line[0] === '-' || line[0] === ' ')) { + oldLines++; + } + } + }); - // Select the diagonal that we want to branch from. We select the prior - // path whose position in the new string is the farthest from the origin - // and does not pass the bounds of the diff graph - if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { - basePath = clonePath(removePath); - self.pushComponent(basePath.components, undefined, true); - } else { - basePath = addPath; // No need to clone, we've pulled it from the list - basePath.newPos++; - self.pushComponent(basePath.components, true, undefined); - } + return { oldLines: oldLines, newLines: newLines }; + } - oldPos = self.extractCommon(basePath, newString, oldString, diagonalPath); - // If we have hit the end of both strings, then we are done - if (basePath.newPos + 1 >= newLen && oldPos + 1 >= oldLen) { - return done(buildValues(basePath.components, newString, oldString, self.useLongestToken)); - } else { - // Otherwise track this path as a potential candidate and continue. - bestPath[diagonalPath] = basePath; - } - } - editLength++; - } +/***/ }), +/* 14 */ +/***/ (function(module, exports, __webpack_require__) { - // Performs the length of edit iteration. Is a bit fugly as this has to support the - // sync and async mode which is never fun. Loops over execEditLength until a value - // is produced. - if (callback) { - (function exec() { - setTimeout(function() { - // This should not happen, but we want to be safe. - /*istanbul ignore next */ - if (editLength > maxEditLength) { - return callback(); - } + /*istanbul ignore start*/'use strict'; - if (!execEditLength()) { - exec(); - } - }, 0); - }()); - } else { - while (editLength <= maxEditLength) { - var ret = execEditLength(); - if (ret) { - return ret; - } - } - } - }, + exports.__esModule = true; + exports. /*istanbul ignore end*/structuredPatch = structuredPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/createTwoFilesPatch = createTwoFilesPatch; + /*istanbul ignore start*/exports. /*istanbul ignore end*/createPatch = createPatch; - pushComponent: function(components, added, removed) { - var last = components[components.length - 1]; - if (last && last.added === added && last.removed === removed) { - // We need to clone here as the component clone operation is just - // as shallow array clone - components[components.length - 1] = {count: last.count + 1, added: added, removed: removed }; - } else { - components.push({count: 1, added: added, removed: removed }); - } - }, - extractCommon: function(basePath, newString, oldString, diagonalPath) { - var newLen = newString.length, - oldLen = oldString.length, - newPos = basePath.newPos, - oldPos = newPos - diagonalPath, + var /*istanbul ignore start*/_line = __webpack_require__(5) /*istanbul ignore end*/; - commonCount = 0; - while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(newString[newPos + 1], oldString[oldPos + 1])) { - newPos++; - oldPos++; - commonCount++; - } + /*istanbul ignore start*/function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } - if (commonCount) { - basePath.components.push({count: commonCount}); - } + /*istanbul ignore end*/function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { + if (!options) { + options = {}; + } + if (typeof options.context === 'undefined') { + options.context = 4; + } - basePath.newPos = newPos; - return oldPos; - }, + var diff = /*istanbul ignore start*/(0, _line.diffLines) /*istanbul ignore end*/(oldStr, newStr, options); + diff.push({ value: '', lines: [] }); // Append an empty value to make cleanup easier - equals: function(left, right) { - var reWhitespace = /\S/; - return left === right || (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)); - }, - tokenize: function(value) { - return value.split(''); - } - }; + function contextLines(lines) { + return lines.map(function (entry) { + return ' ' + entry; + }); + } - var CharDiff = new Diff(); + var hunks = []; + var oldRangeStart = 0, + newRangeStart = 0, + curRange = [], + oldLine = 1, + newLine = 1; - var WordDiff = new Diff(true); - var WordWithSpaceDiff = new Diff(); - WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\s+|\b)/)); - }; + /*istanbul ignore start*/var _loop = function _loop( /*istanbul ignore end*/i) { + var current = diff[i], + lines = current.lines || current.value.replace(/\n$/, '').split('\n'); + current.lines = lines; - var CssDiff = new Diff(true); - CssDiff.tokenize = function(value) { - return removeEmpty(value.split(/([{}:;,]|\s+)/)); - }; + if (current.added || current.removed) { + /*istanbul ignore start*/var _curRange; - var LineDiff = new Diff(); + /*istanbul ignore end*/ // If we have previous context, start with that + if (!oldRangeStart) { + var prev = diff[i - 1]; + oldRangeStart = oldLine; + newRangeStart = newLine; - var TrimmedLineDiff = new Diff(); - TrimmedLineDiff.ignoreTrim = true; + if (prev) { + curRange = options.context > 0 ? contextLines(prev.lines.slice(-options.context)) : []; + oldRangeStart -= curRange.length; + newRangeStart -= curRange.length; + } + } - LineDiff.tokenize = TrimmedLineDiff.tokenize = function(value) { - var retLines = [], - lines = value.split(/^/m); - for (var i = 0; i < lines.length; i++) { - var line = lines[i], - lastLine = lines[i - 1], - lastLineLastChar = lastLine && lastLine[lastLine.length - 1]; + // Output our changes + /*istanbul ignore start*/(_curRange = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/lines.map(function (entry) { + return (current.added ? '+' : '-') + entry; + }))); - // Merge lines that may contain windows new lines - if (line === '\n' && lastLineLastChar === '\r') { - retLines[retLines.length - 1] = retLines[retLines.length - 1].slice(0, -1) + '\r\n'; - } else { - if (this.ignoreTrim) { - line = line.trim(); - // add a newline unless this is the last line. - if (i < lines.length - 1) { - line += '\n'; - } - } - retLines.push(line); - } - } + // Track the updated file position + if (current.added) { + newLine += lines.length; + } else { + oldLine += lines.length; + } + } else { + // Identical context lines. Track line changes + if (oldRangeStart) { + // Close out any changes that have been output (or join overlapping) + if (lines.length <= options.context * 2 && i < diff.length - 2) { + /*istanbul ignore start*/var _curRange2; - return retLines; - }; + /*istanbul ignore end*/ // Overlapping + /*istanbul ignore start*/(_curRange2 = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange2 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/contextLines(lines))); + } else { + /*istanbul ignore start*/var _curRange3; - var PatchDiff = new Diff(); - PatchDiff.tokenize = function(value) { - var ret = [], - linesAndNewlines = value.split(/(\n|\r\n)/); + /*istanbul ignore end*/ // end the range and output + var contextSize = Math.min(lines.length, options.context); + /*istanbul ignore start*/(_curRange3 = /*istanbul ignore end*/curRange).push. /*istanbul ignore start*/apply /*istanbul ignore end*/( /*istanbul ignore start*/_curRange3 /*istanbul ignore end*/, /*istanbul ignore start*/_toConsumableArray( /*istanbul ignore end*/contextLines(lines.slice(0, contextSize)))); - // Ignore the final empty token that occurs if the string ends with a new line - if (!linesAndNewlines[linesAndNewlines.length - 1]) { - linesAndNewlines.pop(); - } + var hunk = { + oldStart: oldRangeStart, + oldLines: oldLine - oldRangeStart + contextSize, + newStart: newRangeStart, + newLines: newLine - newRangeStart + contextSize, + lines: curRange + }; + if (i >= diff.length - 2 && lines.length <= options.context) { + // EOF is inside this hunk + var oldEOFNewline = /\n$/.test(oldStr); + var newEOFNewline = /\n$/.test(newStr); + if (lines.length == 0 && !oldEOFNewline) { + // special case: old has no eol and no trailing context; no-nl can end up before adds + curRange.splice(hunk.oldLines, 0, '\\ No newline at end of file'); + } else if (!oldEOFNewline || !newEOFNewline) { + curRange.push('\\ No newline at end of file'); + } + } + hunks.push(hunk); - // Merge the content and line separators into single tokens - for (var i = 0; i < linesAndNewlines.length; i++) { - var line = linesAndNewlines[i]; + oldRangeStart = 0; + newRangeStart = 0; + curRange = []; + } + } + oldLine += lines.length; + newLine += lines.length; + } + }; - if (i % 2) { - ret[ret.length - 1] += line; - } else { - ret.push(line); - } - } - return ret; - }; + for (var i = 0; i < diff.length; i++) { + /*istanbul ignore start*/_loop( /*istanbul ignore end*/i); + } - var SentenceDiff = new Diff(); - SentenceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\S.+?[.!?])(?=\s+|$)/)); - }; + return { + oldFileName: oldFileName, newFileName: newFileName, + oldHeader: oldHeader, newHeader: newHeader, + hunks: hunks + }; + } - var JsonDiff = new Diff(); - // Discriminate between two lines of pretty-printed, serialized JSON where one of them has a - // dangling comma and the other doesn't. Turns out including the dangling comma yields the nicest output: - JsonDiff.useLongestToken = true; - JsonDiff.tokenize = LineDiff.tokenize; - JsonDiff.equals = function(left, right) { - return LineDiff.equals(left.replace(/,([\r\n])/g, '$1'), right.replace(/,([\r\n])/g, '$1')); - }; + function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) { + var diff = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options); - var JsDiff = { - Diff: Diff, + var ret = []; + if (oldFileName == newFileName) { + ret.push('Index: ' + oldFileName); + } + ret.push('==================================================================='); + ret.push('--- ' + diff.oldFileName + (typeof diff.oldHeader === 'undefined' ? '' : '\t' + diff.oldHeader)); + ret.push('+++ ' + diff.newFileName + (typeof diff.newHeader === 'undefined' ? '' : '\t' + diff.newHeader)); - diffChars: function(oldStr, newStr, callback) { return CharDiff.diff(oldStr, newStr, callback); }, - diffWords: function(oldStr, newStr, callback) { return WordDiff.diff(oldStr, newStr, callback); }, - diffWordsWithSpace: function(oldStr, newStr, callback) { return WordWithSpaceDiff.diff(oldStr, newStr, callback); }, - diffLines: function(oldStr, newStr, callback) { return LineDiff.diff(oldStr, newStr, callback); }, - diffTrimmedLines: function(oldStr, newStr, callback) { return TrimmedLineDiff.diff(oldStr, newStr, callback); }, + for (var i = 0; i < diff.hunks.length; i++) { + var hunk = diff.hunks[i]; + ret.push('@@ -' + hunk.oldStart + ',' + hunk.oldLines + ' +' + hunk.newStart + ',' + hunk.newLines + ' @@'); + ret.push.apply(ret, hunk.lines); + } - diffSentences: function(oldStr, newStr, callback) { return SentenceDiff.diff(oldStr, newStr, callback); }, + return ret.join('\n') + '\n'; + } - diffCss: function(oldStr, newStr, callback) { return CssDiff.diff(oldStr, newStr, callback); }, - diffJson: function(oldObj, newObj, callback) { - return JsonDiff.diff( - typeof oldObj === 'string' ? oldObj : JSON.stringify(canonicalize(oldObj), undefined, ' '), - typeof newObj === 'string' ? newObj : JSON.stringify(canonicalize(newObj), undefined, ' '), - callback - ); - }, + function createPatch(fileName, oldStr, newStr, oldHeader, newHeader, options) { + return createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader, options); + } - createTwoFilesPatch: function(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader) { - var ret = []; - if (oldFileName == newFileName) { - ret.push('Index: ' + oldFileName); - } - ret.push('==================================================================='); - ret.push('--- ' + oldFileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); - ret.push('+++ ' + newFileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); - var diff = PatchDiff.diff(oldStr, newStr); - diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier +/***/ }), +/* 15 */ +/***/ (function(module, exports) { - // Formats a given set of lines for printing as context lines in a patch - function contextLines(lines) { - return map(lines, function(entry) { return ' ' + entry; }); - } + /*istanbul ignore start*/"use strict"; - // Outputs the no newline at end of file warning if needed - function eofNL(curRange, i, current) { - var last = diff[diff.length - 2], - isLast = i === diff.length - 2, - isLastOfType = i === diff.length - 3 && current.added !== last.added; + exports.__esModule = true; + exports. /*istanbul ignore end*/arrayEqual = arrayEqual; + /*istanbul ignore start*/exports. /*istanbul ignore end*/arrayStartsWith = arrayStartsWith; + function arrayEqual(a, b) { + if (a.length !== b.length) { + return false; + } - // Figure out if this is the last line for the given file and missing NL - if (!(/\n$/.test(current.value)) && (isLast || isLastOfType)) { - curRange.push('\\ No newline at end of file'); - } - } + return arrayStartsWith(a, b); + } - var oldRangeStart = 0, newRangeStart = 0, curRange = [], - oldLine = 1, newLine = 1; - for (var i = 0; i < diff.length; i++) { - var current = diff[i], - lines = current.lines || current.value.replace(/\n$/, '').split('\n'); - current.lines = lines; + function arrayStartsWith(array, start) { + if (start.length > array.length) { + return false; + } - if (current.added || current.removed) { - // If we have previous context, start with that - if (!oldRangeStart) { - var prev = diff[i - 1]; - oldRangeStart = oldLine; - newRangeStart = newLine; + for (var i = 0; i < start.length; i++) { + if (start[i] !== array[i]) { + return false; + } + } - if (prev) { - curRange = contextLines(prev.lines.slice(-4)); - oldRangeStart -= curRange.length; - newRangeStart -= curRange.length; - } - } + return true; + } - // Output our changes - curRange.push.apply(curRange, map(lines, function(entry) { - return (current.added ? '+' : '-') + entry; - })); - eofNL(curRange, i, current); - // Track the updated file position - if (current.added) { - newLine += lines.length; - } else { - oldLine += lines.length; - } - } else { - // Identical context lines. Track line changes - if (oldRangeStart) { - // Close out any changes that have been output (or join overlapping) - if (lines.length <= 8 && i < diff.length - 2) { - // Overlapping - curRange.push.apply(curRange, contextLines(lines)); - } else { - // end the range and output - var contextSize = Math.min(lines.length, 4); - ret.push( - '@@ -' + oldRangeStart + ',' + (oldLine - oldRangeStart + contextSize) - + ' +' + newRangeStart + ',' + (newLine - newRangeStart + contextSize) - + ' @@'); - ret.push.apply(ret, curRange); - ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); - if (lines.length <= 4) { - eofNL(ret, i, current); - } - oldRangeStart = 0; - newRangeStart = 0; - curRange = []; - } - } - oldLine += lines.length; - newLine += lines.length; - } - } +/***/ }), +/* 16 */ +/***/ (function(module, exports) { - return ret.join('\n') + '\n'; - }, + /*istanbul ignore start*/"use strict"; - createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { - return JsDiff.createTwoFilesPatch(fileName, fileName, oldStr, newStr, oldHeader, newHeader); - }, + exports.__esModule = true; + exports. /*istanbul ignore end*/convertChangesToDMP = convertChangesToDMP; + // See: http://code.google.com/p/google-diff-match-patch/wiki/API + function convertChangesToDMP(changes) { + var ret = [], + change = /*istanbul ignore start*/void 0 /*istanbul ignore end*/, + operation = /*istanbul ignore start*/void 0 /*istanbul ignore end*/; + for (var i = 0; i < changes.length; i++) { + change = changes[i]; + if (change.added) { + operation = 1; + } else if (change.removed) { + operation = -1; + } else { + operation = 0; + } - applyPatch: function(oldStr, uniDiff) { - var diffstr = uniDiff.split('\n'), - hunks = [], - i = 0, - remEOFNL = false, - addEOFNL = false; + ret.push([operation, change.value]); + } + return ret; + } - // Skip to the first change hunk - while (i < diffstr.length && !(/^@@/.test(diffstr[i]))) { - i++; - } - // Parse the unified diff - for (; i < diffstr.length; i++) { - if (diffstr[i][0] === '@') { - var chnukHeader = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); - hunks.unshift({ - start: chnukHeader[3], - oldlength: +chnukHeader[2], - removed: [], - newlength: chnukHeader[4], - added: [] - }); - } else if (diffstr[i][0] === '+') { - hunks[0].added.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === '-') { - hunks[0].removed.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === ' ') { - hunks[0].added.push(diffstr[i].substr(1)); - hunks[0].removed.push(diffstr[i].substr(1)); - } else if (diffstr[i][0] === '\\') { - if (diffstr[i - 1][0] === '+') { - remEOFNL = true; - } else if (diffstr[i - 1][0] === '-') { - addEOFNL = true; - } - } - } - // Apply the diff to the input - var lines = oldStr.split('\n'); - for (i = hunks.length - 1; i >= 0; i--) { - var hunk = hunks[i]; - // Sanity check the input string. Bail if we don't match. - for (var j = 0; j < hunk.oldlength; j++) { - if (lines[hunk.start - 1 + j] !== hunk.removed[j]) { - return false; - } - } - Array.prototype.splice.apply(lines, [hunk.start - 1, hunk.oldlength].concat(hunk.added)); - } +/***/ }), +/* 17 */ +/***/ (function(module, exports) { - // Handle EOFNL insertion/removal - if (remEOFNL) { - while (!lines[lines.length - 1]) { - lines.pop(); - } - } else if (addEOFNL) { - lines.push(''); - } - return lines.join('\n'); - }, + /*istanbul ignore start*/'use strict'; - convertChangesToXML: function(changes) { - var ret = []; - for (var i = 0; i < changes.length; i++) { - var change = changes[i]; - if (change.added) { - ret.push('<ins>'); - } else if (change.removed) { - ret.push('<del>'); - } + exports.__esModule = true; + exports. /*istanbul ignore end*/convertChangesToXML = convertChangesToXML; + function convertChangesToXML(changes) { + var ret = []; + for (var i = 0; i < changes.length; i++) { + var change = changes[i]; + if (change.added) { + ret.push('<ins>'); + } else if (change.removed) { + ret.push('<del>'); + } - ret.push(escapeHTML(change.value)); + ret.push(escapeHTML(change.value)); - if (change.added) { - ret.push('</ins>'); - } else if (change.removed) { - ret.push('</del>'); - } - } - return ret.join(''); - }, + if (change.added) { + ret.push('</ins>'); + } else if (change.removed) { + ret.push('</del>'); + } + } + return ret.join(''); + } - // See: http://code.google.com/p/google-diff-match-patch/wiki/API - convertChangesToDMP: function(changes) { - var ret = [], - change, - operation; - for (var i = 0; i < changes.length; i++) { - change = changes[i]; - if (change.added) { - operation = 1; - } else if (change.removed) { - operation = -1; - } else { - operation = 0; - } + function escapeHTML(s) { + var n = s; + n = n.replace(/&/g, '&'); + n = n.replace(/</g, '<'); + n = n.replace(/>/g, '>'); + n = n.replace(/"/g, '"'); - ret.push([operation, change.value]); - } - return ret; - }, + return n; + } - canonicalize: canonicalize - }; - /*istanbul ignore next */ - /*global module */ - if (typeof module !== 'undefined' && module.exports) { - module.exports = JsDiff; - } else if (typeof define === 'function' && define.amd) { - /*global define */ - define([], function() { return JsDiff; }); - } else if (typeof global.JsDiff === 'undefined') { - global.JsDiff = JsDiff; - } -}(this)); +/***/ }) +/******/ ]) +}); +; },{}],49:[function(require,module,exports){ 'use strict'; @@ -9323,7 +12616,7 @@ throw new TypeError('Expected a string'); } - return str.replace(matchOperatorsRe, '\\$&'); + return str.replace(matchOperatorsRe, '\\$&'); }; },{}],50:[function(require,module,exports){ @@ -9348,8 +12641,16 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +var objectCreate = Object.create || objectCreatePolyfill +var objectKeys = Object.keys || objectKeysPolyfill +var bind = Function.prototype.bind || functionBindPolyfill + function EventEmitter() { - this._events = this._events || {}; + if (!this._events || !Object.prototype.hasOwnProperty.call(this, '_events')) { + this._events = objectCreate(null); + this._eventsCount = 0; + } + this._maxListeners = this._maxListeners || undefined; } module.exports = EventEmitter; @@ -9362,568 +12663,943 @@ // By default EventEmitters will print a warning if more than 10 listeners are // added to it. This is a useful default which helps finding memory leaks. -EventEmitter.defaultMaxListeners = 10; +var defaultMaxListeners = 10; + +var hasDefineProperty; +try { + var o = {}; + if (Object.defineProperty) Object.defineProperty(o, 'x', { value: 0 }); + hasDefineProperty = o.x === 0; +} catch (err) { hasDefineProperty = false } +if (hasDefineProperty) { + Object.defineProperty(EventEmitter, 'defaultMaxListeners', { + enumerable: true, + get: function() { + return defaultMaxListeners; + }, + set: function(arg) { + // check whether the input is a positive number (whose value is zero or + // greater and not a NaN). + if (typeof arg !== 'number' || arg < 0 || arg !== arg) + throw new TypeError('"defaultMaxListeners" must be a positive number'); + defaultMaxListeners = arg; + } + }); +} else { + EventEmitter.defaultMaxListeners = defaultMaxListeners; +} // Obviously not all Emitters should be limited to 10. This function allows // that to be increased. Set to zero for unlimited. -EventEmitter.prototype.setMaxListeners = function(n) { - if (!isNumber(n) || n < 0 || isNaN(n)) - throw TypeError('n must be a positive number'); +EventEmitter.prototype.setMaxListeners = function setMaxListeners(n) { + if (typeof n !== 'number' || n < 0 || isNaN(n)) + throw new TypeError('"n" argument must be a positive number'); this._maxListeners = n; return this; }; -EventEmitter.prototype.emit = function(type) { - var er, handler, len, args, i, listeners; +function $getMaxListeners(that) { + if (that._maxListeners === undefined) + return EventEmitter.defaultMaxListeners; + return that._maxListeners; +} - if (!this._events) - this._events = {}; +EventEmitter.prototype.getMaxListeners = function getMaxListeners() { + return $getMaxListeners(this); +}; - // If there is no 'error' event listener then throw. - if (type === 'error') { - if (!this._events.error || - (isObject(this._events.error) && !this._events.error.length)) { - er = arguments[1]; - if (er instanceof Error) { - throw er; // Unhandled 'error' event - } - throw TypeError('Uncaught, unspecified "error" event.'); - } +// These standalone emit* functions are used to optimize calling of event +// handlers for fast cases because emit() itself often has a variable number of +// arguments and can be deoptimized because of that. These functions always have +// the same number of arguments and thus do not get deoptimized, so the code +// inside them can execute faster. +function emitNone(handler, isFn, self) { + if (isFn) + handler.call(self); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self); } +} +function emitOne(handler, isFn, self, arg1) { + if (isFn) + handler.call(self, arg1); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1); + } +} +function emitTwo(handler, isFn, self, arg1, arg2) { + if (isFn) + handler.call(self, arg1, arg2); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2); + } +} +function emitThree(handler, isFn, self, arg1, arg2, arg3) { + if (isFn) + handler.call(self, arg1, arg2, arg3); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].call(self, arg1, arg2, arg3); + } +} - handler = this._events[type]; +function emitMany(handler, isFn, self, args) { + if (isFn) + handler.apply(self, args); + else { + var len = handler.length; + var listeners = arrayClone(handler, len); + for (var i = 0; i < len; ++i) + listeners[i].apply(self, args); + } +} - if (isUndefined(handler)) +EventEmitter.prototype.emit = function emit(type) { + var er, handler, len, args, i, events; + var doError = (type === 'error'); + + events = this._events; + if (events) + doError = (doError && events.error == null); + else if (!doError) return false; - if (isFunction(handler)) { - switch (arguments.length) { - // fast cases - case 1: - handler.call(this); - break; - case 2: - handler.call(this, arguments[1]); - break; - case 3: - handler.call(this, arguments[1], arguments[2]); - break; - // slower - default: - args = Array.prototype.slice.call(arguments, 1); - handler.apply(this, args); + // If there is no 'error' event listener then throw. + if (doError) { + if (arguments.length > 1) + er = arguments[1]; + if (er instanceof Error) { + throw er; // Unhandled 'error' event + } else { + // At least give some kind of context to the user + var err = new Error('Unhandled "error" event. (' + er + ')'); + err.context = er; + throw err; } - } else if (isObject(handler)) { - args = Array.prototype.slice.call(arguments, 1); - listeners = handler.slice(); - len = listeners.length; - for (i = 0; i < len; i++) - listeners[i].apply(this, args); + return false; + } + + handler = events[type]; + + if (!handler) + return false; + + var isFn = typeof handler === 'function'; + len = arguments.length; + switch (len) { + // fast cases + case 1: + emitNone(handler, isFn, this); + break; + case 2: + emitOne(handler, isFn, this, arguments[1]); + break; + case 3: + emitTwo(handler, isFn, this, arguments[1], arguments[2]); + break; + case 4: + emitThree(handler, isFn, this, arguments[1], arguments[2], arguments[3]); + break; + // slower + default: + args = new Array(len - 1); + for (i = 1; i < len; i++) + args[i - 1] = arguments[i]; + emitMany(handler, isFn, this, args); } return true; }; -EventEmitter.prototype.addListener = function(type, listener) { +function _addListener(target, type, listener, prepend) { var m; + var events; + var existing; - if (!isFunction(listener)) - throw TypeError('listener must be a function'); + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); - if (!this._events) - this._events = {}; + events = target._events; + if (!events) { + events = target._events = objectCreate(null); + target._eventsCount = 0; + } else { + // To avoid recursion in the case that type === "newListener"! Before + // adding it to the listeners, first emit "newListener". + if (events.newListener) { + target.emit('newListener', type, + listener.listener ? listener.listener : listener); - // To avoid recursion in the case that type === "newListener"! Before - // adding it to the listeners, first emit "newListener". - if (this._events.newListener) - this.emit('newListener', type, - isFunction(listener.listener) ? - listener.listener : listener); + // Re-assign `events` because a newListener handler could have caused the + // this._events to be assigned to a new object + events = target._events; + } + existing = events[type]; + } - if (!this._events[type]) + if (!existing) { // Optimize the case of one listener. Don't need the extra array object. - this._events[type] = listener; - else if (isObject(this._events[type])) - // If we've already got an array, just append. - this._events[type].push(listener); - else - // Adding the second element, need to change to array. - this._events[type] = [this._events[type], listener]; - - // Check for listener leak - if (isObject(this._events[type]) && !this._events[type].warned) { - if (!isUndefined(this._maxListeners)) { - m = this._maxListeners; + existing = events[type] = listener; + ++target._eventsCount; + } else { + if (typeof existing === 'function') { + // Adding the second element, need to change to array. + existing = events[type] = + prepend ? [listener, existing] : [existing, listener]; } else { - m = EventEmitter.defaultMaxListeners; + // If we've already got an array, just append. + if (prepend) { + existing.unshift(listener); + } else { + existing.push(listener); + } } - if (m && m > 0 && this._events[type].length > m) { - this._events[type].warned = true; - console.error('(node) warning: possible EventEmitter memory ' + - 'leak detected. %d listeners added. ' + - 'Use emitter.setMaxListeners() to increase limit.', - this._events[type].length); - if (typeof console.trace === 'function') { - // not supported in IE 10 - console.trace(); + // Check for listener leak + if (!existing.warned) { + m = $getMaxListeners(target); + if (m && m > 0 && existing.length > m) { + existing.warned = true; + var w = new Error('Possible EventEmitter memory leak detected. ' + + existing.length + ' "' + String(type) + '" listeners ' + + 'added. Use emitter.setMaxListeners() to ' + + 'increase limit.'); + w.name = 'MaxListenersExceededWarning'; + w.emitter = target; + w.type = type; + w.count = existing.length; + if (typeof console === 'object' && console.warn) { + console.warn('%s: %s', w.name, w.message); + } } } } - return this; + return target; +} + +EventEmitter.prototype.addListener = function addListener(type, listener) { + return _addListener(this, type, listener, false); }; EventEmitter.prototype.on = EventEmitter.prototype.addListener; -EventEmitter.prototype.once = function(type, listener) { - if (!isFunction(listener)) - throw TypeError('listener must be a function'); +EventEmitter.prototype.prependListener = + function prependListener(type, listener) { + return _addListener(this, type, listener, true); + }; - var fired = false; - - function g() { - this.removeListener(type, g); - - if (!fired) { - fired = true; - listener.apply(this, arguments); +function onceWrapper() { + if (!this.fired) { + this.target.removeListener(this.type, this.wrapFn); + this.fired = true; + switch (arguments.length) { + case 0: + return this.listener.call(this.target); + case 1: + return this.listener.call(this.target, arguments[0]); + case 2: + return this.listener.call(this.target, arguments[0], arguments[1]); + case 3: + return this.listener.call(this.target, arguments[0], arguments[1], + arguments[2]); + default: + var args = new Array(arguments.length); + for (var i = 0; i < args.length; ++i) + args[i] = arguments[i]; + this.listener.apply(this.target, args); } } +} - g.listener = listener; - this.on(type, g); +function _onceWrap(target, type, listener) { + var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener }; + var wrapped = bind.call(onceWrapper, state); + wrapped.listener = listener; + state.wrapFn = wrapped; + return wrapped; +} +EventEmitter.prototype.once = function once(type, listener) { + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + this.on(type, _onceWrap(this, type, listener)); return this; }; -// emits a 'removeListener' event iff the listener was removed -EventEmitter.prototype.removeListener = function(type, listener) { - var list, position, length, i; - - if (!isFunction(listener)) - throw TypeError('listener must be a function'); - - if (!this._events || !this._events[type]) - return this; - - list = this._events[type]; - length = list.length; - position = -1; - - if (list === listener || - (isFunction(list.listener) && list.listener === listener)) { - delete this._events[type]; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - - } else if (isObject(list)) { - for (i = length; i-- > 0;) { - if (list[i] === listener || - (list[i].listener && list[i].listener === listener)) { - position = i; - break; - } - } - - if (position < 0) +EventEmitter.prototype.prependOnceListener = + function prependOnceListener(type, listener) { + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); + this.prependListener(type, _onceWrap(this, type, listener)); return this; + }; - if (list.length === 1) { - list.length = 0; - delete this._events[type]; - } else { - list.splice(position, 1); - } +// Emits a 'removeListener' event if and only if the listener was removed. +EventEmitter.prototype.removeListener = + function removeListener(type, listener) { + var list, events, position, i, originalListener; - if (this._events.removeListener) - this.emit('removeListener', type, listener); - } + if (typeof listener !== 'function') + throw new TypeError('"listener" argument must be a function'); - return this; + events = this._events; + if (!events) + return this; + + list = events[type]; + if (!list) + return this; + + if (list === listener || list.listener === listener) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else { + delete events[type]; + if (events.removeListener) + this.emit('removeListener', type, list.listener || listener); + } + } else if (typeof list !== 'function') { + position = -1; + + for (i = list.length - 1; i >= 0; i--) { + if (list[i] === listener || list[i].listener === listener) { + originalListener = list[i].listener; + position = i; + break; + } + } + + if (position < 0) + return this; + + if (position === 0) + list.shift(); + else + spliceOne(list, position); + + if (list.length === 1) + events[type] = list[0]; + + if (events.removeListener) + this.emit('removeListener', type, originalListener || listener); + } + + return this; + }; + +EventEmitter.prototype.removeAllListeners = + function removeAllListeners(type) { + var listeners, events, i; + + events = this._events; + if (!events) + return this; + + // not listening for removeListener, no need to emit + if (!events.removeListener) { + if (arguments.length === 0) { + this._events = objectCreate(null); + this._eventsCount = 0; + } else if (events[type]) { + if (--this._eventsCount === 0) + this._events = objectCreate(null); + else + delete events[type]; + } + return this; + } + + // emit removeListener for all listeners on all events + if (arguments.length === 0) { + var keys = objectKeys(events); + var key; + for (i = 0; i < keys.length; ++i) { + key = keys[i]; + if (key === 'removeListener') continue; + this.removeAllListeners(key); + } + this.removeAllListeners('removeListener'); + this._events = objectCreate(null); + this._eventsCount = 0; + return this; + } + + listeners = events[type]; + + if (typeof listeners === 'function') { + this.removeListener(type, listeners); + } else if (listeners) { + // LIFO order + for (i = listeners.length - 1; i >= 0; i--) { + this.removeListener(type, listeners[i]); + } + } + + return this; + }; + +function _listeners(target, type, unwrap) { + var events = target._events; + + if (!events) + return []; + + var evlistener = events[type]; + if (!evlistener) + return []; + + if (typeof evlistener === 'function') + return unwrap ? [evlistener.listener || evlistener] : [evlistener]; + + return unwrap ? unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length); +} + +EventEmitter.prototype.listeners = function listeners(type) { + return _listeners(this, type, true); }; -EventEmitter.prototype.removeAllListeners = function(type) { - var key, listeners; - - if (!this._events) - return this; - - // not listening for removeListener, no need to emit - if (!this._events.removeListener) { - if (arguments.length === 0) - this._events = {}; - else if (this._events[type]) - delete this._events[type]; - return this; - } - - // emit removeListener for all listeners on all events - if (arguments.length === 0) { - for (key in this._events) { - if (key === 'removeListener') continue; - this.removeAllListeners(key); - } - this.removeAllListeners('removeListener'); - this._events = {}; - return this; - } - - listeners = this._events[type]; - - if (isFunction(listeners)) { - this.removeListener(type, listeners); - } else if (listeners) { - // LIFO order - while (listeners.length) - this.removeListener(type, listeners[listeners.length - 1]); - } - delete this._events[type]; - - return this; -}; - -EventEmitter.prototype.listeners = function(type) { - var ret; - if (!this._events || !this._events[type]) - ret = []; - else if (isFunction(this._events[type])) - ret = [this._events[type]]; - else - ret = this._events[type].slice(); - return ret; -}; - -EventEmitter.prototype.listenerCount = function(type) { - if (this._events) { - var evlistener = this._events[type]; - - if (isFunction(evlistener)) - return 1; - else if (evlistener) - return evlistener.length; - } - return 0; +EventEmitter.prototype.rawListeners = function rawListeners(type) { + return _listeners(this, type, false); }; EventEmitter.listenerCount = function(emitter, type) { - return emitter.listenerCount(type); + if (typeof emitter.listenerCount === 'function') { + return emitter.listenerCount(type); + } else { + return listenerCount.call(emitter, type); + } }; -function isFunction(arg) { - return typeof arg === 'function'; +EventEmitter.prototype.listenerCount = listenerCount; +function listenerCount(type) { + var events = this._events; + + if (events) { + var evlistener = events[type]; + + if (typeof evlistener === 'function') { + return 1; + } else if (evlistener) { + return evlistener.length; + } + } + + return 0; } -function isNumber(arg) { - return typeof arg === 'number'; +EventEmitter.prototype.eventNames = function eventNames() { + return this._eventsCount > 0 ? Reflect.ownKeys(this._events) : []; +}; + +// About 1.5x faster than the two-arg version of Array#splice(). +function spliceOne(list, index) { + for (var i = index, k = i + 1, n = list.length; k < n; i += 1, k += 1) + list[i] = list[k]; + list.pop(); } -function isObject(arg) { - return typeof arg === 'object' && arg !== null; +function arrayClone(arr, n) { + var copy = new Array(n); + for (var i = 0; i < n; ++i) + copy[i] = arr[i]; + return copy; } -function isUndefined(arg) { - return arg === void 0; +function unwrapListeners(arr) { + var ret = new Array(arr.length); + for (var i = 0; i < ret.length; ++i) { + ret[i] = arr[i].listener || arr[i]; + } + return ret; +} + +function objectCreatePolyfill(proto) { + var F = function() {}; + F.prototype = proto; + return new F; +} +function objectKeysPolyfill(obj) { + var keys = []; + for (var k in obj) if (Object.prototype.hasOwnProperty.call(obj, k)) { + keys.push(k); + } + return k; +} +function functionBindPolyfill(context) { + var fn = this; + return function () { + return fn.apply(context, arguments); + }; } },{}],51:[function(require,module,exports){ -(function (process){ -// Growl - Copyright TJ Holowaychuk <tj@vision-media.ca> (MIT Licensed) +'use strict'; -/** - * Module dependencies. - */ +/* eslint no-invalid-this: 1 */ -var exec = require('child_process').exec - , fs = require('fs') - , path = require('path') - , exists = fs.existsSync || path.existsSync - , os = require('os') - , quote = JSON.stringify - , cmd; +var ERROR_MESSAGE = 'Function.prototype.bind called on incompatible '; +var slice = Array.prototype.slice; +var toStr = Object.prototype.toString; +var funcType = '[object Function]'; -function which(name) { - var paths = process.env.PATH.split(':'); - var loc; - - for (var i = 0, len = paths.length; i < len; ++i) { - loc = path.join(paths[i], name); - if (exists(loc)) return loc; - } -} - -switch(os.type()) { - case 'Darwin': - if (which('terminal-notifier')) { - cmd = { - type: "Darwin-NotificationCenter" - , pkg: "terminal-notifier" - , msg: '-message' - , title: '-title' - , subtitle: '-subtitle' - , icon: '-appIcon' - , sound: '-sound' - , url: '-open' - , priority: { - cmd: '-execute' - , range: [] - } - }; - } else { - cmd = { - type: "Darwin-Growl" - , pkg: "growlnotify" - , msg: '-m' - , sticky: '--sticky' - , priority: { - cmd: '--priority' - , range: [ - -2 - , -1 - , 0 - , 1 - , 2 - , "Very Low" - , "Moderate" - , "Normal" - , "High" - , "Emergency" - ] - } - }; +module.exports = function bind(that) { + var target = this; + if (typeof target !== 'function' || toStr.call(target) !== funcType) { + throw new TypeError(ERROR_MESSAGE + target); } - break; - case 'Linux': - if (which('growl')) { - cmd = { - type: "Linux-Growl" - , pkg: "growl" - , msg: '-m' - , title: '-title' - , subtitle: '-subtitle' - , host: { - cmd: '-H' - , hostname: '192.168.33.1' - } - }; - } else { - cmd = { - type: "Linux" - , pkg: "notify-send" - , msg: '' - , sticky: '-t 0' - , icon: '-i' - , priority: { - cmd: '-u' - , range: [ - "low" - , "normal" - , "critical" - ] - } - }; - } - break; - case 'Windows_NT': - cmd = { - type: "Windows" - , pkg: "growlnotify" - , msg: '' - , sticky: '/s:true' - , title: '/t:' - , icon: '/i:' - , url: '/cu:' - , priority: { - cmd: '/p:' - , range: [ - -2 - , -1 - , 0 - , 1 - , 2 - ] + var args = slice.call(arguments, 1); + + var bound; + var binder = function () { + if (this instanceof bound) { + var result = target.apply( + this, + args.concat(slice.call(arguments)) + ); + if (Object(result) === result) { + return result; + } + return this; + } else { + return target.apply( + that, + args.concat(slice.call(arguments)) + ); } }; - break; -} -/** - * Expose `growl`. - */ - -exports = module.exports = growl; - -/** - * Node-growl version. - */ - -exports.version = '1.4.1' - -/** - * Send growl notification _msg_ with _options_. - * - * Options: - * - * - title Notification title - * - sticky Make the notification stick (defaults to false) - * - priority Specify an int or named key (default is 0) - * - name Application name (defaults to growlnotify) - * - sound Sound efect ( in OSx defined in preferences -> sound -> effects) * works only in OSX > 10.8x - * - image - * - path to an icon sets --iconpath - * - path to an image sets --image - * - capitalized word sets --appIcon - * - filename uses extname as --icon - * - otherwise treated as --icon - * - * Examples: - * - * growl('New email') - * growl('5 new emails', { title: 'Thunderbird' }) - * growl('5 new emails', { title: 'Thunderbird', sound: 'Purr' }) - * growl('Email sent', function(){ - * // ... notification sent - * }) - * - * @param {string} msg - * @param {object} options - * @param {function} fn - * @api public - */ - -function growl(msg, options, fn) { - var image - , args - , options = options || {} - , fn = fn || function(){}; - - if (options.exec) { - cmd = { - type: "Custom" - , pkg: options.exec - , range: [] - }; - } - - // noop - if (!cmd) return fn(new Error('growl not supported on this platform')); - args = [cmd.pkg]; - - // image - if (image = options.image) { - switch(cmd.type) { - case 'Darwin-Growl': - var flag, ext = path.extname(image).substr(1) - flag = flag || ext == 'icns' && 'iconpath' - flag = flag || /^[A-Z]/.test(image) && 'appIcon' - flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image' - flag = flag || ext && (image = ext) && 'icon' - flag = flag || 'icon' - args.push('--' + flag, quote(image)) - break; - case 'Darwin-NotificationCenter': - args.push(cmd.icon, quote(image)); - break; - case 'Linux': - args.push(cmd.icon, quote(image)); - // libnotify defaults to sticky, set a hint for transient notifications - if (!options.sticky) args.push('--hint=int:transient:1'); - break; - case 'Windows': - args.push(cmd.icon + quote(image)); - break; + var boundLength = Math.max(0, target.length - args.length); + var boundArgs = []; + for (var i = 0; i < boundLength; i++) { + boundArgs.push('$' + i); } - } - // sticky - if (options.sticky) args.push(cmd.sticky); + bound = Function('binder', 'return function (' + boundArgs.join(',') + '){ return binder.apply(this,arguments); }')(binder); - // priority - if (options.priority) { - var priority = options.priority + ''; - var checkindexOf = cmd.priority.range.indexOf(priority); - if (~cmd.priority.range.indexOf(priority)) { - args.push(cmd.priority, options.priority); + if (target.prototype) { + var Empty = function Empty() {}; + Empty.prototype = target.prototype; + bound.prototype = new Empty(); + Empty.prototype = null; } - } - //sound - if(options.sound && cmd.type === 'Darwin-NotificationCenter'){ - args.push(cmd.sound, options.sound) - } - - // name - if (options.name && cmd.type === "Darwin-Growl") { - args.push('--name', options.name); - } - - switch(cmd.type) { - case 'Darwin-Growl': - args.push(cmd.msg); - args.push(quote(msg).replace(/\\n/g, '\n')); - if (options.title) args.push(quote(options.title)); - break; - case 'Darwin-NotificationCenter': - args.push(cmd.msg); - var stringifiedMsg = quote(msg); - var escapedMsg = stringifiedMsg.replace(/\\n/g, '\n'); - args.push(escapedMsg); - if (options.title) { - args.push(cmd.title); - args.push(quote(options.title)); - } - if (options.subtitle) { - args.push(cmd.subtitle); - args.push(quote(options.subtitle)); - } - if (options.url) { - args.push(cmd.url); - args.push(quote(options.url)); - } - break; - case 'Linux-Growl': - args.push(cmd.msg); - args.push(quote(msg).replace(/\\n/g, '\n')); - if (options.title) args.push(quote(options.title)); - if (cmd.host) { - args.push(cmd.host.cmd, cmd.host.hostname) - } - break; - case 'Linux': - if (options.title) { - args.push(quote(options.title)); - args.push(cmd.msg); - args.push(quote(msg).replace(/\\n/g, '\n')); - } else { - args.push(quote(msg).replace(/\\n/g, '\n')); - } - break; - case 'Windows': - args.push(quote(msg).replace(/\\n/g, '\n')); - if (options.title) args.push(cmd.title + quote(options.title)); - if (options.url) args.push(cmd.url + quote(options.url)); - break; - case 'Custom': - args[0] = (function(origCommand) { - var message = options.title - ? options.title + ': ' + msg - : msg; - var command = origCommand.replace(/(^|[^%])%s/g, '$1' + quote(message)); - if (command === origCommand) args.push(quote(message)); - return command; - })(args[0]); - break; - } - - // execute - exec(args.join(' '), fn); + return bound; }; -}).call(this,require('_process')) -},{"_process":58,"child_process":43,"fs":43,"os":56,"path":43}],52:[function(require,module,exports){ +},{}],52:[function(require,module,exports){ +'use strict'; + +var implementation = require('./implementation'); + +module.exports = Function.prototype.bind || implementation; + +},{"./implementation":51}],53:[function(require,module,exports){ +'use strict'; + +/* eslint complexity: [2, 17], max-statements: [2, 33] */ +module.exports = function hasSymbols() { + if (typeof Symbol !== 'function' || typeof Object.getOwnPropertySymbols !== 'function') { return false; } + if (typeof Symbol.iterator === 'symbol') { return true; } + + var obj = {}; + var sym = Symbol('test'); + var symObj = Object(sym); + if (typeof sym === 'string') { return false; } + + if (Object.prototype.toString.call(sym) !== '[object Symbol]') { return false; } + if (Object.prototype.toString.call(symObj) !== '[object Symbol]') { return false; } + + // temp disabled per https://github.com/ljharb/object.assign/issues/17 + // if (sym instanceof Symbol) { return false; } + // temp disabled per https://github.com/WebReflection/get-own-property-symbols/issues/4 + // if (!(symObj instanceof Symbol)) { return false; } + + // if (typeof Symbol.prototype.toString !== 'function') { return false; } + // if (String(sym) !== Symbol.prototype.toString.call(sym)) { return false; } + + var symVal = 42; + obj[sym] = symVal; + for (sym in obj) { return false; } // eslint-disable-line no-restricted-syntax + if (typeof Object.keys === 'function' && Object.keys(obj).length !== 0) { return false; } + + if (typeof Object.getOwnPropertyNames === 'function' && Object.getOwnPropertyNames(obj).length !== 0) { return false; } + + var syms = Object.getOwnPropertySymbols(obj); + if (syms.length !== 1 || syms[0] !== sym) { return false; } + + if (!Object.prototype.propertyIsEnumerable.call(obj, sym)) { return false; } + + if (typeof Object.getOwnPropertyDescriptor === 'function') { + var descriptor = Object.getOwnPropertyDescriptor(obj, sym); + if (descriptor.value !== symVal || descriptor.enumerable !== true) { return false; } + } + + return true; +}; + +},{}],54:[function(require,module,exports){ +(function (global){ +/*! https://mths.be/he v1.2.0 by @mathias | MIT license */ +;(function(root) { + + // Detect free variables `exports`. + var freeExports = typeof exports == 'object' && exports; + + // Detect free variable `module`. + var freeModule = typeof module == 'object' && module && + module.exports == freeExports && module; + + // Detect free variable `global`, from Node.js or Browserified code, + // and use it as `root`. + var freeGlobal = typeof global == 'object' && global; + if (freeGlobal.global === freeGlobal || freeGlobal.window === freeGlobal) { + root = freeGlobal; + } + + /*--------------------------------------------------------------------------*/ + + // All astral symbols. + var regexAstralSymbols = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g; + // All ASCII symbols (not just printable ASCII) except those listed in the + // first column of the overrides table. + // https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides + var regexAsciiWhitelist = /[\x01-\x7F]/g; + // All BMP symbols that are not ASCII newlines, printable ASCII symbols, or + // code points listed in the first column of the overrides table on + // https://html.spec.whatwg.org/multipage/syntax.html#table-charref-overrides. + var regexBmpWhitelist = /[\x01-\t\x0B\f\x0E-\x1F\x7F\x81\x8D\x8F\x90\x9D\xA0-\uFFFF]/g; + + var regexEncodeNonAscii = /<\u20D2|=\u20E5|>\u20D2|\u205F\u200A|\u219D\u0338|\u2202\u0338|\u2220\u20D2|\u2229\uFE00|\u222A\uFE00|\u223C\u20D2|\u223D\u0331|\u223E\u0333|\u2242\u0338|\u224B\u0338|\u224D\u20D2|\u224E\u0338|\u224F\u0338|\u2250\u0338|\u2261\u20E5|\u2264\u20D2|\u2265\u20D2|\u2266\u0338|\u2267\u0338|\u2268\uFE00|\u2269\uFE00|\u226A\u0338|\u226A\u20D2|\u226B\u0338|\u226B\u20D2|\u227F\u0338|\u2282\u20D2|\u2283\u20D2|\u228A\uFE00|\u228B\uFE00|\u228F\u0338|\u2290\u0338|\u2293\uFE00|\u2294\uFE00|\u22B4\u20D2|\u22B5\u20D2|\u22D8\u0338|\u22D9\u0338|\u22DA\uFE00|\u22DB\uFE00|\u22F5\u0338|\u22F9\u0338|\u2933\u0338|\u29CF\u0338|\u29D0\u0338|\u2A6D\u0338|\u2A70\u0338|\u2A7D\u0338|\u2A7E\u0338|\u2AA1\u0338|\u2AA2\u0338|\u2AAC\uFE00|\u2AAD\uFE00|\u2AAF\u0338|\u2AB0\u0338|\u2AC5\u0338|\u2AC6\u0338|\u2ACB\uFE00|\u2ACC\uFE00|\u2AFD\u20E5|[\xA0-\u0113\u0116-\u0122\u0124-\u012B\u012E-\u014D\u0150-\u017E\u0192\u01B5\u01F5\u0237\u02C6\u02C7\u02D8-\u02DD\u0311\u0391-\u03A1\u03A3-\u03A9\u03B1-\u03C9\u03D1\u03D2\u03D5\u03D6\u03DC\u03DD\u03F0\u03F1\u03F5\u03F6\u0401-\u040C\u040E-\u044F\u0451-\u045C\u045E\u045F\u2002-\u2005\u2007-\u2010\u2013-\u2016\u2018-\u201A\u201C-\u201E\u2020-\u2022\u2025\u2026\u2030-\u2035\u2039\u203A\u203E\u2041\u2043\u2044\u204F\u2057\u205F-\u2063\u20AC\u20DB\u20DC\u2102\u2105\u210A-\u2113\u2115-\u211E\u2122\u2124\u2127-\u2129\u212C\u212D\u212F-\u2131\u2133-\u2138\u2145-\u2148\u2153-\u215E\u2190-\u219B\u219D-\u21A7\u21A9-\u21AE\u21B0-\u21B3\u21B5-\u21B7\u21BA-\u21DB\u21DD\u21E4\u21E5\u21F5\u21FD-\u2205\u2207-\u2209\u220B\u220C\u220F-\u2214\u2216-\u2218\u221A\u221D-\u2238\u223A-\u2257\u2259\u225A\u225C\u225F-\u2262\u2264-\u228B\u228D-\u229B\u229D-\u22A5\u22A7-\u22B0\u22B2-\u22BB\u22BD-\u22DB\u22DE-\u22E3\u22E6-\u22F7\u22F9-\u22FE\u2305\u2306\u2308-\u2310\u2312\u2313\u2315\u2316\u231C-\u231F\u2322\u2323\u232D\u232E\u2336\u233D\u233F\u237C\u23B0\u23B1\u23B4-\u23B6\u23DC-\u23DF\u23E2\u23E7\u2423\u24C8\u2500\u2502\u250C\u2510\u2514\u2518\u251C\u2524\u252C\u2534\u253C\u2550-\u256C\u2580\u2584\u2588\u2591-\u2593\u25A1\u25AA\u25AB\u25AD\u25AE\u25B1\u25B3-\u25B5\u25B8\u25B9\u25BD-\u25BF\u25C2\u25C3\u25CA\u25CB\u25EC\u25EF\u25F8-\u25FC\u2605\u2606\u260E\u2640\u2642\u2660\u2663\u2665\u2666\u266A\u266D-\u266F\u2713\u2717\u2720\u2736\u2758\u2772\u2773\u27C8\u27C9\u27E6-\u27ED\u27F5-\u27FA\u27FC\u27FF\u2902-\u2905\u290C-\u2913\u2916\u2919-\u2920\u2923-\u292A\u2933\u2935-\u2939\u293C\u293D\u2945\u2948-\u294B\u294E-\u2976\u2978\u2979\u297B-\u297F\u2985\u2986\u298B-\u2996\u299A\u299C\u299D\u29A4-\u29B7\u29B9\u29BB\u29BC\u29BE-\u29C5\u29C9\u29CD-\u29D0\u29DC-\u29DE\u29E3-\u29E5\u29EB\u29F4\u29F6\u2A00-\u2A02\u2A04\u2A06\u2A0C\u2A0D\u2A10-\u2A17\u2A22-\u2A27\u2A29\u2A2A\u2A2D-\u2A31\u2A33-\u2A3C\u2A3F\u2A40\u2A42-\u2A4D\u2A50\u2A53-\u2A58\u2A5A-\u2A5D\u2A5F\u2A66\u2A6A\u2A6D-\u2A75\u2A77-\u2A9A\u2A9D-\u2AA2\u2AA4-\u2AB0\u2AB3-\u2AC8\u2ACB\u2ACC\u2ACF-\u2ADB\u2AE4\u2AE6-\u2AE9\u2AEB-\u2AF3\u2AFD\uFB00-\uFB04]|\uD835[\uDC9C\uDC9E\uDC9F\uDCA2\uDCA5\uDCA6\uDCA9-\uDCAC\uDCAE-\uDCB9\uDCBB\uDCBD-\uDCC3\uDCC5-\uDCCF\uDD04\uDD05\uDD07-\uDD0A\uDD0D-\uDD14\uDD16-\uDD1C\uDD1E-\uDD39\uDD3B-\uDD3E\uDD40-\uDD44\uDD46\uDD4A-\uDD50\uDD52-\uDD6B]/g; + var encodeMap = {'\xAD':'shy','\u200C':'zwnj','\u200D':'zwj','\u200E':'lrm','\u2063':'ic','\u2062':'it','\u2061':'af','\u200F':'rlm','\u200B':'ZeroWidthSpace','\u2060':'NoBreak','\u0311':'DownBreve','\u20DB':'tdot','\u20DC':'DotDot','\t':'Tab','\n':'NewLine','\u2008':'puncsp','\u205F':'MediumSpace','\u2009':'thinsp','\u200A':'hairsp','\u2004':'emsp13','\u2002':'ensp','\u2005':'emsp14','\u2003':'emsp','\u2007':'numsp','\xA0':'nbsp','\u205F\u200A':'ThickSpace','\u203E':'oline','_':'lowbar','\u2010':'dash','\u2013':'ndash','\u2014':'mdash','\u2015':'horbar',',':'comma',';':'semi','\u204F':'bsemi',':':'colon','\u2A74':'Colone','!':'excl','\xA1':'iexcl','?':'quest','\xBF':'iquest','.':'period','\u2025':'nldr','\u2026':'mldr','\xB7':'middot','\'':'apos','\u2018':'lsquo','\u2019':'rsquo','\u201A':'sbquo','\u2039':'lsaquo','\u203A':'rsaquo','"':'quot','\u201C':'ldquo','\u201D':'rdquo','\u201E':'bdquo','\xAB':'laquo','\xBB':'raquo','(':'lpar',')':'rpar','[':'lsqb',']':'rsqb','{':'lcub','}':'rcub','\u2308':'lceil','\u2309':'rceil','\u230A':'lfloor','\u230B':'rfloor','\u2985':'lopar','\u2986':'ropar','\u298B':'lbrke','\u298C':'rbrke','\u298D':'lbrkslu','\u298E':'rbrksld','\u298F':'lbrksld','\u2990':'rbrkslu','\u2991':'langd','\u2992':'rangd','\u2993':'lparlt','\u2994':'rpargt','\u2995':'gtlPar','\u2996':'ltrPar','\u27E6':'lobrk','\u27E7':'robrk','\u27E8':'lang','\u27E9':'rang','\u27EA':'Lang','\u27EB':'Rang','\u27EC':'loang','\u27ED':'roang','\u2772':'lbbrk','\u2773':'rbbrk','\u2016':'Vert','\xA7':'sect','\xB6':'para','@':'commat','*':'ast','/':'sol','undefined':null,'&':'amp','#':'num','%':'percnt','\u2030':'permil','\u2031':'pertenk','\u2020':'dagger','\u2021':'Dagger','\u2022':'bull','\u2043':'hybull','\u2032':'prime','\u2033':'Prime','\u2034':'tprime','\u2057':'qprime','\u2035':'bprime','\u2041':'caret','`':'grave','\xB4':'acute','\u02DC':'tilde','^':'Hat','\xAF':'macr','\u02D8':'breve','\u02D9':'dot','\xA8':'die','\u02DA':'ring','\u02DD':'dblac','\xB8':'cedil','\u02DB':'ogon','\u02C6':'circ','\u02C7':'caron','\xB0':'deg','\xA9':'copy','\xAE':'reg','\u2117':'copysr','\u2118':'wp','\u211E':'rx','\u2127':'mho','\u2129':'iiota','\u2190':'larr','\u219A':'nlarr','\u2192':'rarr','\u219B':'nrarr','\u2191':'uarr','\u2193':'darr','\u2194':'harr','\u21AE':'nharr','\u2195':'varr','\u2196':'nwarr','\u2197':'nearr','\u2198':'searr','\u2199':'swarr','\u219D':'rarrw','\u219D\u0338':'nrarrw','\u219E':'Larr','\u219F':'Uarr','\u21A0':'Rarr','\u21A1':'Darr','\u21A2':'larrtl','\u21A3':'rarrtl','\u21A4':'mapstoleft','\u21A5':'mapstoup','\u21A6':'map','\u21A7':'mapstodown','\u21A9':'larrhk','\u21AA':'rarrhk','\u21AB':'larrlp','\u21AC':'rarrlp','\u21AD':'harrw','\u21B0':'lsh','\u21B1':'rsh','\u21B2':'ldsh','\u21B3':'rdsh','\u21B5':'crarr','\u21B6':'cularr','\u21B7':'curarr','\u21BA':'olarr','\u21BB':'orarr','\u21BC':'lharu','\u21BD':'lhard','\u21BE':'uharr','\u21BF':'uharl','\u21C0':'rharu','\u21C1':'rhard','\u21C2':'dharr','\u21C3':'dharl','\u21C4':'rlarr','\u21C5':'udarr','\u21C6':'lrarr','\u21C7':'llarr','\u21C8':'uuarr','\u21C9':'rrarr','\u21CA':'ddarr','\u21CB':'lrhar','\u21CC':'rlhar','\u21D0':'lArr','\u21CD':'nlArr','\u21D1':'uArr','\u21D2':'rArr','\u21CF':'nrArr','\u21D3':'dArr','\u21D4':'iff','\u21CE':'nhArr','\u21D5':'vArr','\u21D6':'nwArr','\u21D7':'neArr','\u21D8':'seArr','\u21D9':'swArr','\u21DA':'lAarr','\u21DB':'rAarr','\u21DD':'zigrarr','\u21E4':'larrb','\u21E5':'rarrb','\u21F5':'duarr','\u21FD':'loarr','\u21FE':'roarr','\u21FF':'hoarr','\u2200':'forall','\u2201':'comp','\u2202':'part','\u2202\u0338':'npart','\u2203':'exist','\u2204':'nexist','\u2205':'empty','\u2207':'Del','\u2208':'in','\u2209':'notin','\u220B':'ni','\u220C':'notni','\u03F6':'bepsi','\u220F':'prod','\u2210':'coprod','\u2211':'sum','+':'plus','\xB1':'pm','\xF7':'div','\xD7':'times','<':'lt','\u226E':'nlt','<\u20D2':'nvlt','=':'equals','\u2260':'ne','=\u20E5':'bne','\u2A75':'Equal','>':'gt','\u226F':'ngt','>\u20D2':'nvgt','\xAC':'not','|':'vert','\xA6':'brvbar','\u2212':'minus','\u2213':'mp','\u2214':'plusdo','\u2044':'frasl','\u2216':'setmn','\u2217':'lowast','\u2218':'compfn','\u221A':'Sqrt','\u221D':'prop','\u221E':'infin','\u221F':'angrt','\u2220':'ang','\u2220\u20D2':'nang','\u2221':'angmsd','\u2222':'angsph','\u2223':'mid','\u2224':'nmid','\u2225':'par','\u2226':'npar','\u2227':'and','\u2228':'or','\u2229':'cap','\u2229\uFE00':'caps','\u222A':'cup','\u222A\uFE00':'cups','\u222B':'int','\u222C':'Int','\u222D':'tint','\u2A0C':'qint','\u222E':'oint','\u222F':'Conint','\u2230':'Cconint','\u2231':'cwint','\u2232':'cwconint','\u2233':'awconint','\u2234':'there4','\u2235':'becaus','\u2236':'ratio','\u2237':'Colon','\u2238':'minusd','\u223A':'mDDot','\u223B':'homtht','\u223C':'sim','\u2241':'nsim','\u223C\u20D2':'nvsim','\u223D':'bsim','\u223D\u0331':'race','\u223E':'ac','\u223E\u0333':'acE','\u223F':'acd','\u2240':'wr','\u2242':'esim','\u2242\u0338':'nesim','\u2243':'sime','\u2244':'nsime','\u2245':'cong','\u2247':'ncong','\u2246':'simne','\u2248':'ap','\u2249':'nap','\u224A':'ape','\u224B':'apid','\u224B\u0338':'napid','\u224C':'bcong','\u224D':'CupCap','\u226D':'NotCupCap','\u224D\u20D2':'nvap','\u224E':'bump','\u224E\u0338':'nbump','\u224F':'bumpe','\u224F\u0338':'nbumpe','\u2250':'doteq','\u2250\u0338':'nedot','\u2251':'eDot','\u2252':'efDot','\u2253':'erDot','\u2254':'colone','\u2255':'ecolon','\u2256':'ecir','\u2257':'cire','\u2259':'wedgeq','\u225A':'veeeq','\u225C':'trie','\u225F':'equest','\u2261':'equiv','\u2262':'nequiv','\u2261\u20E5':'bnequiv','\u2264':'le','\u2270':'nle','\u2264\u20D2':'nvle','\u2265':'ge','\u2271':'nge','\u2265\u20D2':'nvge','\u2266':'lE','\u2266\u0338':'nlE','\u2267':'gE','\u2267\u0338':'ngE','\u2268\uFE00':'lvnE','\u2268':'lnE','\u2269':'gnE','\u2269\uFE00':'gvnE','\u226A':'ll','\u226A\u0338':'nLtv','\u226A\u20D2':'nLt','\u226B':'gg','\u226B\u0338':'nGtv','\u226B\u20D2':'nGt','\u226C':'twixt','\u2272':'lsim','\u2274':'nlsim','\u2273':'gsim','\u2275':'ngsim','\u2276':'lg','\u2278':'ntlg','\u2277':'gl','\u2279':'ntgl','\u227A':'pr','\u2280':'npr','\u227B':'sc','\u2281':'nsc','\u227C':'prcue','\u22E0':'nprcue','\u227D':'sccue','\u22E1':'nsccue','\u227E':'prsim','\u227F':'scsim','\u227F\u0338':'NotSucceedsTilde','\u2282':'sub','\u2284':'nsub','\u2282\u20D2':'vnsub','\u2283':'sup','\u2285':'nsup','\u2283\u20D2':'vnsup','\u2286':'sube','\u2288':'nsube','\u2287':'supe','\u2289':'nsupe','\u228A\uFE00':'vsubne','\u228A':'subne','\u228B\uFE00':'vsupne','\u228B':'supne','\u228D':'cupdot','\u228E':'uplus','\u228F':'sqsub','\u228F\u0338':'NotSquareSubset','\u2290':'sqsup','\u2290\u0338':'NotSquareSuperset','\u2291':'sqsube','\u22E2':'nsqsube','\u2292':'sqsupe','\u22E3':'nsqsupe','\u2293':'sqcap','\u2293\uFE00':'sqcaps','\u2294':'sqcup','\u2294\uFE00':'sqcups','\u2295':'oplus','\u2296':'ominus','\u2297':'otimes','\u2298':'osol','\u2299':'odot','\u229A':'ocir','\u229B':'oast','\u229D':'odash','\u229E':'plusb','\u229F':'minusb','\u22A0':'timesb','\u22A1':'sdotb','\u22A2':'vdash','\u22AC':'nvdash','\u22A3':'dashv','\u22A4':'top','\u22A5':'bot','\u22A7':'models','\u22A8':'vDash','\u22AD':'nvDash','\u22A9':'Vdash','\u22AE':'nVdash','\u22AA':'Vvdash','\u22AB':'VDash','\u22AF':'nVDash','\u22B0':'prurel','\u22B2':'vltri','\u22EA':'nltri','\u22B3':'vrtri','\u22EB':'nrtri','\u22B4':'ltrie','\u22EC':'nltrie','\u22B4\u20D2':'nvltrie','\u22B5':'rtrie','\u22ED':'nrtrie','\u22B5\u20D2':'nvrtrie','\u22B6':'origof','\u22B7':'imof','\u22B8':'mumap','\u22B9':'hercon','\u22BA':'intcal','\u22BB':'veebar','\u22BD':'barvee','\u22BE':'angrtvb','\u22BF':'lrtri','\u22C0':'Wedge','\u22C1':'Vee','\u22C2':'xcap','\u22C3':'xcup','\u22C4':'diam','\u22C5':'sdot','\u22C6':'Star','\u22C7':'divonx','\u22C8':'bowtie','\u22C9':'ltimes','\u22CA':'rtimes','\u22CB':'lthree','\u22CC':'rthree','\u22CD':'bsime','\u22CE':'cuvee','\u22CF':'cuwed','\u22D0':'Sub','\u22D1':'Sup','\u22D2':'Cap','\u22D3':'Cup','\u22D4':'fork','\u22D5':'epar','\u22D6':'ltdot','\u22D7':'gtdot','\u22D8':'Ll','\u22D8\u0338':'nLl','\u22D9':'Gg','\u22D9\u0338':'nGg','\u22DA\uFE00':'lesg','\u22DA':'leg','\u22DB':'gel','\u22DB\uFE00':'gesl','\u22DE':'cuepr','\u22DF':'cuesc','\u22E6':'lnsim','\u22E7':'gnsim','\u22E8':'prnsim','\u22E9':'scnsim','\u22EE':'vellip','\u22EF':'ctdot','\u22F0':'utdot','\u22F1':'dtdot','\u22F2':'disin','\u22F3':'isinsv','\u22F4':'isins','\u22F5':'isindot','\u22F5\u0338':'notindot','\u22F6':'notinvc','\u22F7':'notinvb','\u22F9':'isinE','\u22F9\u0338':'notinE','\u22FA':'nisd','\u22FB':'xnis','\u22FC':'nis','\u22FD':'notnivc','\u22FE':'notnivb','\u2305':'barwed','\u2306':'Barwed','\u230C':'drcrop','\u230D':'dlcrop','\u230E':'urcrop','\u230F':'ulcrop','\u2310':'bnot','\u2312':'profline','\u2313':'profsurf','\u2315':'telrec','\u2316':'target','\u231C':'ulcorn','\u231D':'urcorn','\u231E':'dlcorn','\u231F':'drcorn','\u2322':'frown','\u2323':'smile','\u232D':'cylcty','\u232E':'profalar','\u2336':'topbot','\u233D':'ovbar','\u233F':'solbar','\u237C':'angzarr','\u23B0':'lmoust','\u23B1':'rmoust','\u23B4':'tbrk','\u23B5':'bbrk','\u23B6':'bbrktbrk','\u23DC':'OverParenthesis','\u23DD':'UnderParenthesis','\u23DE':'OverBrace','\u23DF':'UnderBrace','\u23E2':'trpezium','\u23E7':'elinters','\u2423':'blank','\u2500':'boxh','\u2502':'boxv','\u250C':'boxdr','\u2510':'boxdl','\u2514':'boxur','\u2518':'boxul','\u251C':'boxvr','\u2524':'boxvl','\u252C':'boxhd','\u2534':'boxhu','\u253C':'boxvh','\u2550':'boxH','\u2551':'boxV','\u2552':'boxdR','\u2553':'boxDr','\u2554':'boxDR','\u2555':'boxdL','\u2556':'boxDl','\u2557':'boxDL','\u2558':'boxuR','\u2559':'boxUr','\u255A':'boxUR','\u255B':'boxuL','\u255C':'boxUl','\u255D':'boxUL','\u255E':'boxvR','\u255F':'boxVr','\u2560':'boxVR','\u2561':'boxvL','\u2562':'boxVl','\u2563':'boxVL','\u2564':'boxHd','\u2565':'boxhD','\u2566':'boxHD','\u2567':'boxHu','\u2568':'boxhU','\u2569':'boxHU','\u256A':'boxvH','\u256B':'boxVh','\u256C':'boxVH','\u2580':'uhblk','\u2584':'lhblk','\u2588':'block','\u2591':'blk14','\u2592':'blk12','\u2593':'blk34','\u25A1':'squ','\u25AA':'squf','\u25AB':'EmptyVerySmallSquare','\u25AD':'rect','\u25AE':'marker','\u25B1':'fltns','\u25B3':'xutri','\u25B4':'utrif','\u25B5':'utri','\u25B8':'rtrif','\u25B9':'rtri','\u25BD':'xdtri','\u25BE':'dtrif','\u25BF':'dtri','\u25C2':'ltrif','\u25C3':'ltri','\u25CA':'loz','\u25CB':'cir','\u25EC':'tridot','\u25EF':'xcirc','\u25F8':'ultri','\u25F9':'urtri','\u25FA':'lltri','\u25FB':'EmptySmallSquare','\u25FC':'FilledSmallSquare','\u2605':'starf','\u2606':'star','\u260E':'phone','\u2640':'female','\u2642':'male','\u2660':'spades','\u2663':'clubs','\u2665':'hearts','\u2666':'diams','\u266A':'sung','\u2713':'check','\u2717':'cross','\u2720':'malt','\u2736':'sext','\u2758':'VerticalSeparator','\u27C8':'bsolhsub','\u27C9':'suphsol','\u27F5':'xlarr','\u27F6':'xrarr','\u27F7':'xharr','\u27F8':'xlArr','\u27F9':'xrArr','\u27FA':'xhArr','\u27FC':'xmap','\u27FF':'dzigrarr','\u2902':'nvlArr','\u2903':'nvrArr','\u2904':'nvHarr','\u2905':'Map','\u290C':'lbarr','\u290D':'rbarr','\u290E':'lBarr','\u290F':'rBarr','\u2910':'RBarr','\u2911':'DDotrahd','\u2912':'UpArrowBar','\u2913':'DownArrowBar','\u2916':'Rarrtl','\u2919':'latail','\u291A':'ratail','\u291B':'lAtail','\u291C':'rAtail','\u291D':'larrfs','\u291E':'rarrfs','\u291F':'larrbfs','\u2920':'rarrbfs','\u2923':'nwarhk','\u2924':'nearhk','\u2925':'searhk','\u2926':'swarhk','\u2927':'nwnear','\u2928':'toea','\u2929':'tosa','\u292A':'swnwar','\u2933':'rarrc','\u2933\u0338':'nrarrc','\u2935':'cudarrr','\u2936':'ldca','\u2937':'rdca','\u2938':'cudarrl','\u2939':'larrpl','\u293C':'curarrm','\u293D':'cularrp','\u2945':'rarrpl','\u2948':'harrcir','\u2949':'Uarrocir','\u294A':'lurdshar','\u294B':'ldrushar','\u294E':'LeftRightVector','\u294F':'RightUpDownVector','\u2950':'DownLeftRightVector','\u2951':'LeftUpDownVector','\u2952':'LeftVectorBar','\u2953':'RightVectorBar','\u2954':'RightUpVectorBar','\u2955':'RightDownVectorBar','\u2956':'DownLeftVectorBar','\u2957':'DownRightVectorBar','\u2958':'LeftUpVectorBar','\u2959':'LeftDownVectorBar','\u295A':'LeftTeeVector','\u295B':'RightTeeVector','\u295C':'RightUpTeeVector','\u295D':'RightDownTeeVector','\u295E':'DownLeftTeeVector','\u295F':'DownRightTeeVector','\u2960':'LeftUpTeeVector','\u2961':'LeftDownTeeVector','\u2962':'lHar','\u2963':'uHar','\u2964':'rHar','\u2965':'dHar','\u2966':'luruhar','\u2967':'ldrdhar','\u2968':'ruluhar','\u2969':'rdldhar','\u296A':'lharul','\u296B':'llhard','\u296C':'rharul','\u296D':'lrhard','\u296E':'udhar','\u296F':'duhar','\u2970':'RoundImplies','\u2971':'erarr','\u2972':'simrarr','\u2973':'larrsim','\u2974':'rarrsim','\u2975':'rarrap','\u2976':'ltlarr','\u2978':'gtrarr','\u2979':'subrarr','\u297B':'suplarr','\u297C':'lfisht','\u297D':'rfisht','\u297E':'ufisht','\u297F':'dfisht','\u299A':'vzigzag','\u299C':'vangrt','\u299D':'angrtvbd','\u29A4':'ange','\u29A5':'range','\u29A6':'dwangle','\u29A7':'uwangle','\u29A8':'angmsdaa','\u29A9':'angmsdab','\u29AA':'angmsdac','\u29AB':'angmsdad','\u29AC':'angmsdae','\u29AD':'angmsdaf','\u29AE':'angmsdag','\u29AF':'angmsdah','\u29B0':'bemptyv','\u29B1':'demptyv','\u29B2':'cemptyv','\u29B3':'raemptyv','\u29B4':'laemptyv','\u29B5':'ohbar','\u29B6':'omid','\u29B7':'opar','\u29B9':'operp','\u29BB':'olcross','\u29BC':'odsold','\u29BE':'olcir','\u29BF':'ofcir','\u29C0':'olt','\u29C1':'ogt','\u29C2':'cirscir','\u29C3':'cirE','\u29C4':'solb','\u29C5':'bsolb','\u29C9':'boxbox','\u29CD':'trisb','\u29CE':'rtriltri','\u29CF':'LeftTriangleBar','\u29CF\u0338':'NotLeftTriangleBar','\u29D0':'RightTriangleBar','\u29D0\u0338':'NotRightTriangleBar','\u29DC':'iinfin','\u29DD':'infintie','\u29DE':'nvinfin','\u29E3':'eparsl','\u29E4':'smeparsl','\u29E5':'eqvparsl','\u29EB':'lozf','\u29F4':'RuleDelayed','\u29F6':'dsol','\u2A00':'xodot','\u2A01':'xoplus','\u2A02':'xotime','\u2A04':'xuplus','\u2A06':'xsqcup','\u2A0D':'fpartint','\u2A10':'cirfnint','\u2A11':'awint','\u2A12':'rppolint','\u2A13':'scpolint','\u2A14':'npolint','\u2A15':'pointint','\u2A16':'quatint','\u2A17':'intlarhk','\u2A22':'pluscir','\u2A23':'plusacir','\u2A24':'simplus','\u2A25':'plusdu','\u2A26':'plussim','\u2A27':'plustwo','\u2A29':'mcomma','\u2A2A':'minusdu','\u2A2D':'loplus','\u2A2E':'roplus','\u2A2F':'Cross','\u2A30':'timesd','\u2A31':'timesbar','\u2A33':'smashp','\u2A34':'lotimes','\u2A35':'rotimes','\u2A36':'otimesas','\u2A37':'Otimes','\u2A38':'odiv','\u2A39':'triplus','\u2A3A':'triminus','\u2A3B':'tritime','\u2A3C':'iprod','\u2A3F':'amalg','\u2A40':'capdot','\u2A42':'ncup','\u2A43':'ncap','\u2A44':'capand','\u2A45':'cupor','\u2A46':'cupcap','\u2A47':'capcup','\u2A48':'cupbrcap','\u2A49':'capbrcup','\u2A4A':'cupcup','\u2A4B':'capcap','\u2A4C':'ccups','\u2A4D':'ccaps','\u2A50':'ccupssm','\u2A53':'And','\u2A54':'Or','\u2A55':'andand','\u2A56':'oror','\u2A57':'orslope','\u2A58':'andslope','\u2A5A':'andv','\u2A5B':'orv','\u2A5C':'andd','\u2A5D':'ord','\u2A5F':'wedbar','\u2A66':'sdote','\u2A6A':'simdot','\u2A6D':'congdot','\u2A6D\u0338':'ncongdot','\u2A6E':'easter','\u2A6F':'apacir','\u2A70':'apE','\u2A70\u0338':'napE','\u2A71':'eplus','\u2A72':'pluse','\u2A73':'Esim','\u2A77':'eDDot','\u2A78':'equivDD','\u2A79':'ltcir','\u2A7A':'gtcir','\u2A7B':'ltquest','\u2A7C':'gtquest','\u2A7D':'les','\u2A7D\u0338':'nles','\u2A7E':'ges','\u2A7E\u0338':'nges','\u2A7F':'lesdot','\u2A80':'gesdot','\u2A81':'lesdoto','\u2A82':'gesdoto','\u2A83':'lesdotor','\u2A84':'gesdotol','\u2A85':'lap','\u2A86':'gap','\u2A87':'lne','\u2A88':'gne','\u2A89':'lnap','\u2A8A':'gnap','\u2A8B':'lEg','\u2A8C':'gEl','\u2A8D':'lsime','\u2A8E':'gsime','\u2A8F':'lsimg','\u2A90':'gsiml','\u2A91':'lgE','\u2A92':'glE','\u2A93':'lesges','\u2A94':'gesles','\u2A95':'els','\u2A96':'egs','\u2A97':'elsdot','\u2A98':'egsdot','\u2A99':'el','\u2A9A':'eg','\u2A9D':'siml','\u2A9E':'simg','\u2A9F':'simlE','\u2AA0':'simgE','\u2AA1':'LessLess','\u2AA1\u0338':'NotNestedLessLess','\u2AA2':'GreaterGreater','\u2AA2\u0338':'NotNestedGreaterGreater','\u2AA4':'glj','\u2AA5':'gla','\u2AA6':'ltcc','\u2AA7':'gtcc','\u2AA8':'lescc','\u2AA9':'gescc','\u2AAA':'smt','\u2AAB':'lat','\u2AAC':'smte','\u2AAC\uFE00':'smtes','\u2AAD':'late','\u2AAD\uFE00':'lates','\u2AAE':'bumpE','\u2AAF':'pre','\u2AAF\u0338':'npre','\u2AB0':'sce','\u2AB0\u0338':'nsce','\u2AB3':'prE','\u2AB4':'scE','\u2AB5':'prnE','\u2AB6':'scnE','\u2AB7':'prap','\u2AB8':'scap','\u2AB9':'prnap','\u2ABA':'scnap','\u2ABB':'Pr','\u2ABC':'Sc','\u2ABD':'subdot','\u2ABE':'supdot','\u2ABF':'subplus','\u2AC0':'supplus','\u2AC1':'submult','\u2AC2':'supmult','\u2AC3':'subedot','\u2AC4':'supedot','\u2AC5':'subE','\u2AC5\u0338':'nsubE','\u2AC6':'supE','\u2AC6\u0338':'nsupE','\u2AC7':'subsim','\u2AC8':'supsim','\u2ACB\uFE00':'vsubnE','\u2ACB':'subnE','\u2ACC\uFE00':'vsupnE','\u2ACC':'supnE','\u2ACF':'csub','\u2AD0':'csup','\u2AD1':'csube','\u2AD2':'csupe','\u2AD3':'subsup','\u2AD4':'supsub','\u2AD5':'subsub','\u2AD6':'supsup','\u2AD7':'suphsub','\u2AD8':'supdsub','\u2AD9':'forkv','\u2ADA':'topfork','\u2ADB':'mlcp','\u2AE4':'Dashv','\u2AE6':'Vdashl','\u2AE7':'Barv','\u2AE8':'vBar','\u2AE9':'vBarv','\u2AEB':'Vbar','\u2AEC':'Not','\u2AED':'bNot','\u2AEE':'rnmid','\u2AEF':'cirmid','\u2AF0':'midcir','\u2AF1':'topcir','\u2AF2':'nhpar','\u2AF3':'parsim','\u2AFD':'parsl','\u2AFD\u20E5':'nparsl','\u266D':'flat','\u266E':'natur','\u266F':'sharp','\xA4':'curren','\xA2':'cent','$':'dollar','\xA3':'pound','\xA5':'yen','\u20AC':'euro','\xB9':'sup1','\xBD':'half','\u2153':'frac13','\xBC':'frac14','\u2155':'frac15','\u2159':'frac16','\u215B':'frac18','\xB2':'sup2','\u2154':'frac23','\u2156':'frac25','\xB3':'sup3','\xBE':'frac34','\u2157':'frac35','\u215C':'frac38','\u2158':'frac45','\u215A':'frac56','\u215D':'frac58','\u215E':'frac78','\uD835\uDCB6':'ascr','\uD835\uDD52':'aopf','\uD835\uDD1E':'afr','\uD835\uDD38':'Aopf','\uD835\uDD04':'Afr','\uD835\uDC9C':'Ascr','\xAA':'ordf','\xE1':'aacute','\xC1':'Aacute','\xE0':'agrave','\xC0':'Agrave','\u0103':'abreve','\u0102':'Abreve','\xE2':'acirc','\xC2':'Acirc','\xE5':'aring','\xC5':'angst','\xE4':'auml','\xC4':'Auml','\xE3':'atilde','\xC3':'Atilde','\u0105':'aogon','\u0104':'Aogon','\u0101':'amacr','\u0100':'Amacr','\xE6':'aelig','\xC6':'AElig','\uD835\uDCB7':'bscr','\uD835\uDD53':'bopf','\uD835\uDD1F':'bfr','\uD835\uDD39':'Bopf','\u212C':'Bscr','\uD835\uDD05':'Bfr','\uD835\uDD20':'cfr','\uD835\uDCB8':'cscr','\uD835\uDD54':'copf','\u212D':'Cfr','\uD835\uDC9E':'Cscr','\u2102':'Copf','\u0107':'cacute','\u0106':'Cacute','\u0109':'ccirc','\u0108':'Ccirc','\u010D':'ccaron','\u010C':'Ccaron','\u010B':'cdot','\u010A':'Cdot','\xE7':'ccedil','\xC7':'Ccedil','\u2105':'incare','\uD835\uDD21':'dfr','\u2146':'dd','\uD835\uDD55':'dopf','\uD835\uDCB9':'dscr','\uD835\uDC9F':'Dscr','\uD835\uDD07':'Dfr','\u2145':'DD','\uD835\uDD3B':'Dopf','\u010F':'dcaron','\u010E':'Dcaron','\u0111':'dstrok','\u0110':'Dstrok','\xF0':'eth','\xD0':'ETH','\u2147':'ee','\u212F':'escr','\uD835\uDD22':'efr','\uD835\uDD56':'eopf','\u2130':'Escr','\uD835\uDD08':'Efr','\uD835\uDD3C':'Eopf','\xE9':'eacute','\xC9':'Eacute','\xE8':'egrave','\xC8':'Egrave','\xEA':'ecirc','\xCA':'Ecirc','\u011B':'ecaron','\u011A':'Ecaron','\xEB':'euml','\xCB':'Euml','\u0117':'edot','\u0116':'Edot','\u0119':'eogon','\u0118':'Eogon','\u0113':'emacr','\u0112':'Emacr','\uD835\uDD23':'ffr','\uD835\uDD57':'fopf','\uD835\uDCBB':'fscr','\uD835\uDD09':'Ffr','\uD835\uDD3D':'Fopf','\u2131':'Fscr','\uFB00':'fflig','\uFB03':'ffilig','\uFB04':'ffllig','\uFB01':'filig','fj':'fjlig','\uFB02':'fllig','\u0192':'fnof','\u210A':'gscr','\uD835\uDD58':'gopf','\uD835\uDD24':'gfr','\uD835\uDCA2':'Gscr','\uD835\uDD3E':'Gopf','\uD835\uDD0A':'Gfr','\u01F5':'gacute','\u011F':'gbreve','\u011E':'Gbreve','\u011D':'gcirc','\u011C':'Gcirc','\u0121':'gdot','\u0120':'Gdot','\u0122':'Gcedil','\uD835\uDD25':'hfr','\u210E':'planckh','\uD835\uDCBD':'hscr','\uD835\uDD59':'hopf','\u210B':'Hscr','\u210C':'Hfr','\u210D':'Hopf','\u0125':'hcirc','\u0124':'Hcirc','\u210F':'hbar','\u0127':'hstrok','\u0126':'Hstrok','\uD835\uDD5A':'iopf','\uD835\uDD26':'ifr','\uD835\uDCBE':'iscr','\u2148':'ii','\uD835\uDD40':'Iopf','\u2110':'Iscr','\u2111':'Im','\xED':'iacute','\xCD':'Iacute','\xEC':'igrave','\xCC':'Igrave','\xEE':'icirc','\xCE':'Icirc','\xEF':'iuml','\xCF':'Iuml','\u0129':'itilde','\u0128':'Itilde','\u0130':'Idot','\u012F':'iogon','\u012E':'Iogon','\u012B':'imacr','\u012A':'Imacr','\u0133':'ijlig','\u0132':'IJlig','\u0131':'imath','\uD835\uDCBF':'jscr','\uD835\uDD5B':'jopf','\uD835\uDD27':'jfr','\uD835\uDCA5':'Jscr','\uD835\uDD0D':'Jfr','\uD835\uDD41':'Jopf','\u0135':'jcirc','\u0134':'Jcirc','\u0237':'jmath','\uD835\uDD5C':'kopf','\uD835\uDCC0':'kscr','\uD835\uDD28':'kfr','\uD835\uDCA6':'Kscr','\uD835\uDD42':'Kopf','\uD835\uDD0E':'Kfr','\u0137':'kcedil','\u0136':'Kcedil','\uD835\uDD29':'lfr','\uD835\uDCC1':'lscr','\u2113':'ell','\uD835\uDD5D':'lopf','\u2112':'Lscr','\uD835\uDD0F':'Lfr','\uD835\uDD43':'Lopf','\u013A':'lacute','\u0139':'Lacute','\u013E':'lcaron','\u013D':'Lcaron','\u013C':'lcedil','\u013B':'Lcedil','\u0142':'lstrok','\u0141':'Lstrok','\u0140':'lmidot','\u013F':'Lmidot','\uD835\uDD2A':'mfr','\uD835\uDD5E':'mopf','\uD835\uDCC2':'mscr','\uD835\uDD10':'Mfr','\uD835\uDD44':'Mopf','\u2133':'Mscr','\uD835\uDD2B':'nfr','\uD835\uDD5F':'nopf','\uD835\uDCC3':'nscr','\u2115':'Nopf','\uD835\uDCA9':'Nscr','\uD835\uDD11':'Nfr','\u0144':'nacute','\u0143':'Nacute','\u0148':'ncaron','\u0147':'Ncaron','\xF1':'ntilde','\xD1':'Ntilde','\u0146':'ncedil','\u0145':'Ncedil','\u2116':'numero','\u014B':'eng','\u014A':'ENG','\uD835\uDD60':'oopf','\uD835\uDD2C':'ofr','\u2134':'oscr','\uD835\uDCAA':'Oscr','\uD835\uDD12':'Ofr','\uD835\uDD46':'Oopf','\xBA':'ordm','\xF3':'oacute','\xD3':'Oacute','\xF2':'ograve','\xD2':'Ograve','\xF4':'ocirc','\xD4':'Ocirc','\xF6':'ouml','\xD6':'Ouml','\u0151':'odblac','\u0150':'Odblac','\xF5':'otilde','\xD5':'Otilde','\xF8':'oslash','\xD8':'Oslash','\u014D':'omacr','\u014C':'Omacr','\u0153':'oelig','\u0152':'OElig','\uD835\uDD2D':'pfr','\uD835\uDCC5':'pscr','\uD835\uDD61':'popf','\u2119':'Popf','\uD835\uDD13':'Pfr','\uD835\uDCAB':'Pscr','\uD835\uDD62':'qopf','\uD835\uDD2E':'qfr','\uD835\uDCC6':'qscr','\uD835\uDCAC':'Qscr','\uD835\uDD14':'Qfr','\u211A':'Qopf','\u0138':'kgreen','\uD835\uDD2F':'rfr','\uD835\uDD63':'ropf','\uD835\uDCC7':'rscr','\u211B':'Rscr','\u211C':'Re','\u211D':'Ropf','\u0155':'racute','\u0154':'Racute','\u0159':'rcaron','\u0158':'Rcaron','\u0157':'rcedil','\u0156':'Rcedil','\uD835\uDD64':'sopf','\uD835\uDCC8':'sscr','\uD835\uDD30':'sfr','\uD835\uDD4A':'Sopf','\uD835\uDD16':'Sfr','\uD835\uDCAE':'Sscr','\u24C8':'oS','\u015B':'sacute','\u015A':'Sacute','\u015D':'scirc','\u015C':'Scirc','\u0161':'scaron','\u0160':'Scaron','\u015F':'scedil','\u015E':'Scedil','\xDF':'szlig','\uD835\uDD31':'tfr','\uD835\uDCC9':'tscr','\uD835\uDD65':'topf','\uD835\uDCAF':'Tscr','\uD835\uDD17':'Tfr','\uD835\uDD4B':'Topf','\u0165':'tcaron','\u0164':'Tcaron','\u0163':'tcedil','\u0162':'Tcedil','\u2122':'trade','\u0167':'tstrok','\u0166':'Tstrok','\uD835\uDCCA':'uscr','\uD835\uDD66':'uopf','\uD835\uDD32':'ufr','\uD835\uDD4C':'Uopf','\uD835\uDD18':'Ufr','\uD835\uDCB0':'Uscr','\xFA':'uacute','\xDA':'Uacute','\xF9':'ugrave','\xD9':'Ugrave','\u016D':'ubreve','\u016C':'Ubreve','\xFB':'ucirc','\xDB':'Ucirc','\u016F':'uring','\u016E':'Uring','\xFC':'uuml','\xDC':'Uuml','\u0171':'udblac','\u0170':'Udblac','\u0169':'utilde','\u0168':'Utilde','\u0173':'uogon','\u0172':'Uogon','\u016B':'umacr','\u016A':'Umacr','\uD835\uDD33':'vfr','\uD835\uDD67':'vopf','\uD835\uDCCB':'vscr','\uD835\uDD19':'Vfr','\uD835\uDD4D':'Vopf','\uD835\uDCB1':'Vscr','\uD835\uDD68':'wopf','\uD835\uDCCC':'wscr','\uD835\uDD34':'wfr','\uD835\uDCB2':'Wscr','\uD835\uDD4E':'Wopf','\uD835\uDD1A':'Wfr','\u0175':'wcirc','\u0174':'Wcirc','\uD835\uDD35':'xfr','\uD835\uDCCD':'xscr','\uD835\uDD69':'xopf','\uD835\uDD4F':'Xopf','\uD835\uDD1B':'Xfr','\uD835\uDCB3':'Xscr','\uD835\uDD36':'yfr','\uD835\uDCCE':'yscr','\uD835\uDD6A':'yopf','\uD835\uDCB4':'Yscr','\uD835\uDD1C':'Yfr','\uD835\uDD50':'Yopf','\xFD':'yacute','\xDD':'Yacute','\u0177':'ycirc','\u0176':'Ycirc','\xFF':'yuml','\u0178':'Yuml','\uD835\uDCCF':'zscr','\uD835\uDD37':'zfr','\uD835\uDD6B':'zopf','\u2128':'Zfr','\u2124':'Zopf','\uD835\uDCB5':'Zscr','\u017A':'zacute','\u0179':'Zacute','\u017E':'zcaron','\u017D':'Zcaron','\u017C':'zdot','\u017B':'Zdot','\u01B5':'imped','\xFE':'thorn','\xDE':'THORN','\u0149':'napos','\u03B1':'alpha','\u0391':'Alpha','\u03B2':'beta','\u0392':'Beta','\u03B3':'gamma','\u0393':'Gamma','\u03B4':'delta','\u0394':'Delta','\u03B5':'epsi','\u03F5':'epsiv','\u0395':'Epsilon','\u03DD':'gammad','\u03DC':'Gammad','\u03B6':'zeta','\u0396':'Zeta','\u03B7':'eta','\u0397':'Eta','\u03B8':'theta','\u03D1':'thetav','\u0398':'Theta','\u03B9':'iota','\u0399':'Iota','\u03BA':'kappa','\u03F0':'kappav','\u039A':'Kappa','\u03BB':'lambda','\u039B':'Lambda','\u03BC':'mu','\xB5':'micro','\u039C':'Mu','\u03BD':'nu','\u039D':'Nu','\u03BE':'xi','\u039E':'Xi','\u03BF':'omicron','\u039F':'Omicron','\u03C0':'pi','\u03D6':'piv','\u03A0':'Pi','\u03C1':'rho','\u03F1':'rhov','\u03A1':'Rho','\u03C3':'sigma','\u03A3':'Sigma','\u03C2':'sigmaf','\u03C4':'tau','\u03A4':'Tau','\u03C5':'upsi','\u03A5':'Upsilon','\u03D2':'Upsi','\u03C6':'phi','\u03D5':'phiv','\u03A6':'Phi','\u03C7':'chi','\u03A7':'Chi','\u03C8':'psi','\u03A8':'Psi','\u03C9':'omega','\u03A9':'ohm','\u0430':'acy','\u0410':'Acy','\u0431':'bcy','\u0411':'Bcy','\u0432':'vcy','\u0412':'Vcy','\u0433':'gcy','\u0413':'Gcy','\u0453':'gjcy','\u0403':'GJcy','\u0434':'dcy','\u0414':'Dcy','\u0452':'djcy','\u0402':'DJcy','\u0435':'iecy','\u0415':'IEcy','\u0451':'iocy','\u0401':'IOcy','\u0454':'jukcy','\u0404':'Jukcy','\u0436':'zhcy','\u0416':'ZHcy','\u0437':'zcy','\u0417':'Zcy','\u0455':'dscy','\u0405':'DScy','\u0438':'icy','\u0418':'Icy','\u0456':'iukcy','\u0406':'Iukcy','\u0457':'yicy','\u0407':'YIcy','\u0439':'jcy','\u0419':'Jcy','\u0458':'jsercy','\u0408':'Jsercy','\u043A':'kcy','\u041A':'Kcy','\u045C':'kjcy','\u040C':'KJcy','\u043B':'lcy','\u041B':'Lcy','\u0459':'ljcy','\u0409':'LJcy','\u043C':'mcy','\u041C':'Mcy','\u043D':'ncy','\u041D':'Ncy','\u045A':'njcy','\u040A':'NJcy','\u043E':'ocy','\u041E':'Ocy','\u043F':'pcy','\u041F':'Pcy','\u0440':'rcy','\u0420':'Rcy','\u0441':'scy','\u0421':'Scy','\u0442':'tcy','\u0422':'Tcy','\u045B':'tshcy','\u040B':'TSHcy','\u0443':'ucy','\u0423':'Ucy','\u045E':'ubrcy','\u040E':'Ubrcy','\u0444':'fcy','\u0424':'Fcy','\u0445':'khcy','\u0425':'KHcy','\u0446':'tscy','\u0426':'TScy','\u0447':'chcy','\u0427':'CHcy','\u045F':'dzcy','\u040F':'DZcy','\u0448':'shcy','\u0428':'SHcy','\u0449':'shchcy','\u0429':'SHCHcy','\u044A':'hardcy','\u042A':'HARDcy','\u044B':'ycy','\u042B':'Ycy','\u044C':'softcy','\u042C':'SOFTcy','\u044D':'ecy','\u042D':'Ecy','\u044E':'yucy','\u042E':'YUcy','\u044F':'yacy','\u042F':'YAcy','\u2135':'aleph','\u2136':'beth','\u2137':'gimel','\u2138':'daleth'}; + + var regexEscape = /["&'<>`]/g; + var escapeMap = { + '"': '"', + '&': '&', + '\'': ''', + '<': '<', + // See https://mathiasbynens.be/notes/ambiguous-ampersands: in HTML, the + // following is not strictly necessary unless it’s part of a tag or an + // unquoted attribute value. We’re only escaping it to support those + // situations, and for XML support. + '>': '>', + // In Internet Explorer ≤ 8, the backtick character can be used + // to break out of (un)quoted attribute values or HTML comments. + // See http://html5sec.org/#102, http://html5sec.org/#108, and + // http://html5sec.org/#133. + '`': '`' + }; + + var regexInvalidEntity = /&#(?:[xX][^a-fA-F0-9]|[^0-9xX])/; + var regexInvalidRawCodePoint = /[\0-\x08\x0B\x0E-\x1F\x7F-\x9F\uFDD0-\uFDEF\uFFFE\uFFFF]|[\uD83F\uD87F\uD8BF\uD8FF\uD93F\uD97F\uD9BF\uD9FF\uDA3F\uDA7F\uDABF\uDAFF\uDB3F\uDB7F\uDBBF\uDBFF][\uDFFE\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF]/; + var regexDecode = /&(CounterClockwiseContourIntegral|DoubleLongLeftRightArrow|ClockwiseContourIntegral|NotNestedGreaterGreater|NotSquareSupersetEqual|DiacriticalDoubleAcute|NotRightTriangleEqual|NotSucceedsSlantEqual|NotPrecedesSlantEqual|CloseCurlyDoubleQuote|NegativeVeryThinSpace|DoubleContourIntegral|FilledVerySmallSquare|CapitalDifferentialD|OpenCurlyDoubleQuote|EmptyVerySmallSquare|NestedGreaterGreater|DoubleLongRightArrow|NotLeftTriangleEqual|NotGreaterSlantEqual|ReverseUpEquilibrium|DoubleLeftRightArrow|NotSquareSubsetEqual|NotDoubleVerticalBar|RightArrowLeftArrow|NotGreaterFullEqual|NotRightTriangleBar|SquareSupersetEqual|DownLeftRightVector|DoubleLongLeftArrow|leftrightsquigarrow|LeftArrowRightArrow|NegativeMediumSpace|blacktriangleright|RightDownVectorBar|PrecedesSlantEqual|RightDoubleBracket|SucceedsSlantEqual|NotLeftTriangleBar|RightTriangleEqual|SquareIntersection|RightDownTeeVector|ReverseEquilibrium|NegativeThickSpace|longleftrightarrow|Longleftrightarrow|LongLeftRightArrow|DownRightTeeVector|DownRightVectorBar|GreaterSlantEqual|SquareSubsetEqual|LeftDownVectorBar|LeftDoubleBracket|VerticalSeparator|rightleftharpoons|NotGreaterGreater|NotSquareSuperset|blacktriangleleft|blacktriangledown|NegativeThinSpace|LeftDownTeeVector|NotLessSlantEqual|leftrightharpoons|DoubleUpDownArrow|DoubleVerticalBar|LeftTriangleEqual|FilledSmallSquare|twoheadrightarrow|NotNestedLessLess|DownLeftTeeVector|DownLeftVectorBar|RightAngleBracket|NotTildeFullEqual|NotReverseElement|RightUpDownVector|DiacriticalTilde|NotSucceedsTilde|circlearrowright|NotPrecedesEqual|rightharpoondown|DoubleRightArrow|NotSucceedsEqual|NonBreakingSpace|NotRightTriangle|LessEqualGreater|RightUpTeeVector|LeftAngleBracket|GreaterFullEqual|DownArrowUpArrow|RightUpVectorBar|twoheadleftarrow|GreaterEqualLess|downharpoonright|RightTriangleBar|ntrianglerighteq|NotSupersetEqual|LeftUpDownVector|DiacriticalAcute|rightrightarrows|vartriangleright|UpArrowDownArrow|DiacriticalGrave|UnderParenthesis|EmptySmallSquare|LeftUpVectorBar|leftrightarrows|DownRightVector|downharpoonleft|trianglerighteq|ShortRightArrow|OverParenthesis|DoubleLeftArrow|DoubleDownArrow|NotSquareSubset|bigtriangledown|ntrianglelefteq|UpperRightArrow|curvearrowright|vartriangleleft|NotLeftTriangle|nleftrightarrow|LowerRightArrow|NotHumpDownHump|NotGreaterTilde|rightthreetimes|LeftUpTeeVector|NotGreaterEqual|straightepsilon|LeftTriangleBar|rightsquigarrow|ContourIntegral|rightleftarrows|CloseCurlyQuote|RightDownVector|LeftRightVector|nLeftrightarrow|leftharpoondown|circlearrowleft|SquareSuperset|OpenCurlyQuote|hookrightarrow|HorizontalLine|DiacriticalDot|NotLessGreater|ntriangleright|DoubleRightTee|InvisibleComma|InvisibleTimes|LowerLeftArrow|DownLeftVector|NotSubsetEqual|curvearrowleft|trianglelefteq|NotVerticalBar|TildeFullEqual|downdownarrows|NotGreaterLess|RightTeeVector|ZeroWidthSpace|looparrowright|LongRightArrow|doublebarwedge|ShortLeftArrow|ShortDownArrow|RightVectorBar|GreaterGreater|ReverseElement|rightharpoonup|LessSlantEqual|leftthreetimes|upharpoonright|rightarrowtail|LeftDownVector|Longrightarrow|NestedLessLess|UpperLeftArrow|nshortparallel|leftleftarrows|leftrightarrow|Leftrightarrow|LeftRightArrow|longrightarrow|upharpoonleft|RightArrowBar|ApplyFunction|LeftTeeVector|leftarrowtail|NotEqualTilde|varsubsetneqq|varsupsetneqq|RightTeeArrow|SucceedsEqual|SucceedsTilde|LeftVectorBar|SupersetEqual|hookleftarrow|DifferentialD|VerticalTilde|VeryThinSpace|blacktriangle|bigtriangleup|LessFullEqual|divideontimes|leftharpoonup|UpEquilibrium|ntriangleleft|RightTriangle|measuredangle|shortparallel|longleftarrow|Longleftarrow|LongLeftArrow|DoubleLeftTee|Poincareplane|PrecedesEqual|triangleright|DoubleUpArrow|RightUpVector|fallingdotseq|looparrowleft|PrecedesTilde|NotTildeEqual|NotTildeTilde|smallsetminus|Proportional|triangleleft|triangledown|UnderBracket|NotHumpEqual|exponentiale|ExponentialE|NotLessTilde|HilbertSpace|RightCeiling|blacklozenge|varsupsetneq|HumpDownHump|GreaterEqual|VerticalLine|LeftTeeArrow|NotLessEqual|DownTeeArrow|LeftTriangle|varsubsetneq|Intersection|NotCongruent|DownArrowBar|LeftUpVector|LeftArrowBar|risingdotseq|GreaterTilde|RoundImplies|SquareSubset|ShortUpArrow|NotSuperset|quaternions|precnapprox|backepsilon|preccurlyeq|OverBracket|blacksquare|MediumSpace|VerticalBar|circledcirc|circleddash|CircleMinus|CircleTimes|LessGreater|curlyeqprec|curlyeqsucc|diamondsuit|UpDownArrow|Updownarrow|RuleDelayed|Rrightarrow|updownarrow|RightVector|nRightarrow|nrightarrow|eqslantless|LeftCeiling|Equilibrium|SmallCircle|expectation|NotSucceeds|thickapprox|GreaterLess|SquareUnion|NotPrecedes|NotLessLess|straightphi|succnapprox|succcurlyeq|SubsetEqual|sqsupseteq|Proportion|Laplacetrf|ImaginaryI|supsetneqq|NotGreater|gtreqqless|NotElement|ThickSpace|TildeEqual|TildeTilde|Fouriertrf|rmoustache|EqualTilde|eqslantgtr|UnderBrace|LeftVector|UpArrowBar|nLeftarrow|nsubseteqq|subsetneqq|nsupseteqq|nleftarrow|succapprox|lessapprox|UpTeeArrow|upuparrows|curlywedge|lesseqqgtr|varepsilon|varnothing|RightFloor|complement|CirclePlus|sqsubseteq|Lleftarrow|circledast|RightArrow|Rightarrow|rightarrow|lmoustache|Bernoullis|precapprox|mapstoleft|mapstodown|longmapsto|dotsquare|downarrow|DoubleDot|nsubseteq|supsetneq|leftarrow|nsupseteq|subsetneq|ThinSpace|ngeqslant|subseteqq|HumpEqual|NotSubset|triangleq|NotCupCap|lesseqgtr|heartsuit|TripleDot|Leftarrow|Coproduct|Congruent|varpropto|complexes|gvertneqq|LeftArrow|LessTilde|supseteqq|MinusPlus|CircleDot|nleqslant|NotExists|gtreqless|nparallel|UnionPlus|LeftFloor|checkmark|CenterDot|centerdot|Mellintrf|gtrapprox|bigotimes|OverBrace|spadesuit|therefore|pitchfork|rationals|PlusMinus|Backslash|Therefore|DownBreve|backsimeq|backprime|DownArrow|nshortmid|Downarrow|lvertneqq|eqvparsl|imagline|imagpart|infintie|integers|Integral|intercal|LessLess|Uarrocir|intlarhk|sqsupset|angmsdaf|sqsubset|llcorner|vartheta|cupbrcap|lnapprox|Superset|SuchThat|succnsim|succneqq|angmsdag|biguplus|curlyvee|trpezium|Succeeds|NotTilde|bigwedge|angmsdah|angrtvbd|triminus|cwconint|fpartint|lrcorner|smeparsl|subseteq|urcorner|lurdshar|laemptyv|DDotrahd|approxeq|ldrushar|awconint|mapstoup|backcong|shortmid|triangle|geqslant|gesdotol|timesbar|circledR|circledS|setminus|multimap|naturals|scpolint|ncongdot|RightTee|boxminus|gnapprox|boxtimes|andslope|thicksim|angmsdaa|varsigma|cirfnint|rtriltri|angmsdab|rppolint|angmsdac|barwedge|drbkarow|clubsuit|thetasym|bsolhsub|capbrcup|dzigrarr|doteqdot|DotEqual|dotminus|UnderBar|NotEqual|realpart|otimesas|ulcorner|hksearow|hkswarow|parallel|PartialD|elinters|emptyset|plusacir|bbrktbrk|angmsdad|pointint|bigoplus|angmsdae|Precedes|bigsqcup|varkappa|notindot|supseteq|precneqq|precnsim|profalar|profline|profsurf|leqslant|lesdotor|raemptyv|subplus|notnivb|notnivc|subrarr|zigrarr|vzigzag|submult|subedot|Element|between|cirscir|larrbfs|larrsim|lotimes|lbrksld|lbrkslu|lozenge|ldrdhar|dbkarow|bigcirc|epsilon|simrarr|simplus|ltquest|Epsilon|luruhar|gtquest|maltese|npolint|eqcolon|npreceq|bigodot|ddagger|gtrless|bnequiv|harrcir|ddotseq|equivDD|backsim|demptyv|nsqsube|nsqsupe|Upsilon|nsubset|upsilon|minusdu|nsucceq|swarrow|nsupset|coloneq|searrow|boxplus|napprox|natural|asympeq|alefsym|congdot|nearrow|bigstar|diamond|supplus|tritime|LeftTee|nvinfin|triplus|NewLine|nvltrie|nvrtrie|nwarrow|nexists|Diamond|ruluhar|Implies|supmult|angzarr|suplarr|suphsub|questeq|because|digamma|Because|olcross|bemptyv|omicron|Omicron|rotimes|NoBreak|intprod|angrtvb|orderof|uwangle|suphsol|lesdoto|orslope|DownTee|realine|cudarrl|rdldhar|OverBar|supedot|lessdot|supdsub|topfork|succsim|rbrkslu|rbrksld|pertenk|cudarrr|isindot|planckh|lessgtr|pluscir|gesdoto|plussim|plustwo|lesssim|cularrp|rarrsim|Cayleys|notinva|notinvb|notinvc|UpArrow|Uparrow|uparrow|NotLess|dwangle|precsim|Product|curarrm|Cconint|dotplus|rarrbfs|ccupssm|Cedilla|cemptyv|notniva|quatint|frac35|frac38|frac45|frac56|frac58|frac78|tridot|xoplus|gacute|gammad|Gammad|lfisht|lfloor|bigcup|sqsupe|gbreve|Gbreve|lharul|sqsube|sqcups|Gcedil|apacir|llhard|lmidot|Lmidot|lmoust|andand|sqcaps|approx|Abreve|spades|circeq|tprime|divide|topcir|Assign|topbot|gesdot|divonx|xuplus|timesd|gesles|atilde|solbar|SOFTcy|loplus|timesb|lowast|lowbar|dlcorn|dlcrop|softcy|dollar|lparlt|thksim|lrhard|Atilde|lsaquo|smashp|bigvee|thinsp|wreath|bkarow|lsquor|lstrok|Lstrok|lthree|ltimes|ltlarr|DotDot|simdot|ltrPar|weierp|xsqcup|angmsd|sigmav|sigmaf|zeetrf|Zcaron|zcaron|mapsto|vsupne|thetav|cirmid|marker|mcomma|Zacute|vsubnE|there4|gtlPar|vsubne|bottom|gtrarr|SHCHcy|shchcy|midast|midcir|middot|minusb|minusd|gtrdot|bowtie|sfrown|mnplus|models|colone|seswar|Colone|mstpos|searhk|gtrsim|nacute|Nacute|boxbox|telrec|hairsp|Tcedil|nbumpe|scnsim|ncaron|Ncaron|ncedil|Ncedil|hamilt|Scedil|nearhk|hardcy|HARDcy|tcedil|Tcaron|commat|nequiv|nesear|tcaron|target|hearts|nexist|varrho|scedil|Scaron|scaron|hellip|Sacute|sacute|hercon|swnwar|compfn|rtimes|rthree|rsquor|rsaquo|zacute|wedgeq|homtht|barvee|barwed|Barwed|rpargt|horbar|conint|swarhk|roplus|nltrie|hslash|hstrok|Hstrok|rmoust|Conint|bprime|hybull|hyphen|iacute|Iacute|supsup|supsub|supsim|varphi|coprod|brvbar|agrave|Supset|supset|igrave|Igrave|notinE|Agrave|iiiint|iinfin|copysr|wedbar|Verbar|vangrt|becaus|incare|verbar|inodot|bullet|drcorn|intcal|drcrop|cularr|vellip|Utilde|bumpeq|cupcap|dstrok|Dstrok|CupCap|cupcup|cupdot|eacute|Eacute|supdot|iquest|easter|ecaron|Ecaron|ecolon|isinsv|utilde|itilde|Itilde|curarr|succeq|Bumpeq|cacute|ulcrop|nparsl|Cacute|nprcue|egrave|Egrave|nrarrc|nrarrw|subsup|subsub|nrtrie|jsercy|nsccue|Jsercy|kappav|kcedil|Kcedil|subsim|ulcorn|nsimeq|egsdot|veebar|kgreen|capand|elsdot|Subset|subset|curren|aacute|lacute|Lacute|emptyv|ntilde|Ntilde|lagran|lambda|Lambda|capcap|Ugrave|langle|subdot|emsp13|numero|emsp14|nvdash|nvDash|nVdash|nVDash|ugrave|ufisht|nvHarr|larrfs|nvlArr|larrhk|larrlp|larrpl|nvrArr|Udblac|nwarhk|larrtl|nwnear|oacute|Oacute|latail|lAtail|sstarf|lbrace|odblac|Odblac|lbrack|udblac|odsold|eparsl|lcaron|Lcaron|ograve|Ograve|lcedil|Lcedil|Aacute|ssmile|ssetmn|squarf|ldquor|capcup|ominus|cylcty|rharul|eqcirc|dagger|rfloor|rfisht|Dagger|daleth|equals|origof|capdot|equest|dcaron|Dcaron|rdquor|oslash|Oslash|otilde|Otilde|otimes|Otimes|urcrop|Ubreve|ubreve|Yacute|Uacute|uacute|Rcedil|rcedil|urcorn|parsim|Rcaron|Vdashl|rcaron|Tstrok|percnt|period|permil|Exists|yacute|rbrack|rbrace|phmmat|ccaron|Ccaron|planck|ccedil|plankv|tstrok|female|plusdo|plusdu|ffilig|plusmn|ffllig|Ccedil|rAtail|dfisht|bernou|ratail|Rarrtl|rarrtl|angsph|rarrpl|rarrlp|rarrhk|xwedge|xotime|forall|ForAll|Vvdash|vsupnE|preceq|bigcap|frac12|frac13|frac14|primes|rarrfs|prnsim|frac15|Square|frac16|square|lesdot|frac18|frac23|propto|prurel|rarrap|rangle|puncsp|frac25|Racute|qprime|racute|lesges|frac34|abreve|AElig|eqsim|utdot|setmn|urtri|Equal|Uring|seArr|uring|searr|dashv|Dashv|mumap|nabla|iogon|Iogon|sdote|sdotb|scsim|napid|napos|equiv|natur|Acirc|dblac|erarr|nbump|iprod|erDot|ucirc|awint|esdot|angrt|ncong|isinE|scnap|Scirc|scirc|ndash|isins|Ubrcy|nearr|neArr|isinv|nedot|ubrcy|acute|Ycirc|iukcy|Iukcy|xutri|nesim|caret|jcirc|Jcirc|caron|twixt|ddarr|sccue|exist|jmath|sbquo|ngeqq|angst|ccaps|lceil|ngsim|UpTee|delta|Delta|rtrif|nharr|nhArr|nhpar|rtrie|jukcy|Jukcy|kappa|rsquo|Kappa|nlarr|nlArr|TSHcy|rrarr|aogon|Aogon|fflig|xrarr|tshcy|ccirc|nleqq|filig|upsih|nless|dharl|nlsim|fjlig|ropar|nltri|dharr|robrk|roarr|fllig|fltns|roang|rnmid|subnE|subne|lAarr|trisb|Ccirc|acirc|ccups|blank|VDash|forkv|Vdash|langd|cedil|blk12|blk14|laquo|strns|diams|notin|vDash|larrb|blk34|block|disin|uplus|vdash|vBarv|aelig|starf|Wedge|check|xrArr|lates|lbarr|lBarr|notni|lbbrk|bcong|frasl|lbrke|frown|vrtri|vprop|vnsup|gamma|Gamma|wedge|xodot|bdquo|srarr|doteq|ldquo|boxdl|boxdL|gcirc|Gcirc|boxDl|boxDL|boxdr|boxdR|boxDr|TRADE|trade|rlhar|boxDR|vnsub|npart|vltri|rlarr|boxhd|boxhD|nprec|gescc|nrarr|nrArr|boxHd|boxHD|boxhu|boxhU|nrtri|boxHu|clubs|boxHU|times|colon|Colon|gimel|xlArr|Tilde|nsime|tilde|nsmid|nspar|THORN|thorn|xlarr|nsube|nsubE|thkap|xhArr|comma|nsucc|boxul|boxuL|nsupe|nsupE|gneqq|gnsim|boxUl|boxUL|grave|boxur|boxuR|boxUr|boxUR|lescc|angle|bepsi|boxvh|varpi|boxvH|numsp|Theta|gsime|gsiml|theta|boxVh|boxVH|boxvl|gtcir|gtdot|boxvL|boxVl|boxVL|crarr|cross|Cross|nvsim|boxvr|nwarr|nwArr|sqsup|dtdot|Uogon|lhard|lharu|dtrif|ocirc|Ocirc|lhblk|duarr|odash|sqsub|Hacek|sqcup|llarr|duhar|oelig|OElig|ofcir|boxvR|uogon|lltri|boxVr|csube|uuarr|ohbar|csupe|ctdot|olarr|olcir|harrw|oline|sqcap|omacr|Omacr|omega|Omega|boxVR|aleph|lneqq|lnsim|loang|loarr|rharu|lobrk|hcirc|operp|oplus|rhard|Hcirc|orarr|Union|order|ecirc|Ecirc|cuepr|szlig|cuesc|breve|reals|eDDot|Breve|hoarr|lopar|utrif|rdquo|Umacr|umacr|efDot|swArr|ultri|alpha|rceil|ovbar|swarr|Wcirc|wcirc|smtes|smile|bsemi|lrarr|aring|parsl|lrhar|bsime|uhblk|lrtri|cupor|Aring|uharr|uharl|slarr|rbrke|bsolb|lsime|rbbrk|RBarr|lsimg|phone|rBarr|rbarr|icirc|lsquo|Icirc|emacr|Emacr|ratio|simne|plusb|simlE|simgE|simeq|pluse|ltcir|ltdot|empty|xharr|xdtri|iexcl|Alpha|ltrie|rarrw|pound|ltrif|xcirc|bumpe|prcue|bumpE|asymp|amacr|cuvee|Sigma|sigma|iiint|udhar|iiota|ijlig|IJlig|supnE|imacr|Imacr|prime|Prime|image|prnap|eogon|Eogon|rarrc|mdash|mDDot|cuwed|imath|supne|imped|Amacr|udarr|prsim|micro|rarrb|cwint|raquo|infin|eplus|range|rangd|Ucirc|radic|minus|amalg|veeeq|rAarr|epsiv|ycirc|quest|sharp|quot|zwnj|Qscr|race|qscr|Qopf|qopf|qint|rang|Rang|Zscr|zscr|Zopf|zopf|rarr|rArr|Rarr|Pscr|pscr|prop|prod|prnE|prec|ZHcy|zhcy|prap|Zeta|zeta|Popf|popf|Zdot|plus|zdot|Yuml|yuml|phiv|YUcy|yucy|Yscr|yscr|perp|Yopf|yopf|part|para|YIcy|Ouml|rcub|yicy|YAcy|rdca|ouml|osol|Oscr|rdsh|yacy|real|oscr|xvee|andd|rect|andv|Xscr|oror|ordm|ordf|xscr|ange|aopf|Aopf|rHar|Xopf|opar|Oopf|xopf|xnis|rhov|oopf|omid|xmap|oint|apid|apos|ogon|ascr|Ascr|odot|odiv|xcup|xcap|ocir|oast|nvlt|nvle|nvgt|nvge|nvap|Wscr|wscr|auml|ntlg|ntgl|nsup|nsub|nsim|Nscr|nscr|nsce|Wopf|ring|npre|wopf|npar|Auml|Barv|bbrk|Nopf|nopf|nmid|nLtv|beta|ropf|Ropf|Beta|beth|nles|rpar|nleq|bnot|bNot|nldr|NJcy|rscr|Rscr|Vscr|vscr|rsqb|njcy|bopf|nisd|Bopf|rtri|Vopf|nGtv|ngtr|vopf|boxh|boxH|boxv|nges|ngeq|boxV|bscr|scap|Bscr|bsim|Vert|vert|bsol|bull|bump|caps|cdot|ncup|scnE|ncap|nbsp|napE|Cdot|cent|sdot|Vbar|nang|vBar|chcy|Mscr|mscr|sect|semi|CHcy|Mopf|mopf|sext|circ|cire|mldr|mlcp|cirE|comp|shcy|SHcy|vArr|varr|cong|copf|Copf|copy|COPY|malt|male|macr|lvnE|cscr|ltri|sime|ltcc|simg|Cscr|siml|csub|Uuml|lsqb|lsim|uuml|csup|Lscr|lscr|utri|smid|lpar|cups|smte|lozf|darr|Lopf|Uscr|solb|lopf|sopf|Sopf|lneq|uscr|spar|dArr|lnap|Darr|dash|Sqrt|LJcy|ljcy|lHar|dHar|Upsi|upsi|diam|lesg|djcy|DJcy|leqq|dopf|Dopf|dscr|Dscr|dscy|ldsh|ldca|squf|DScy|sscr|Sscr|dsol|lcub|late|star|Star|Uopf|Larr|lArr|larr|uopf|dtri|dzcy|sube|subE|Lang|lang|Kscr|kscr|Kopf|kopf|KJcy|kjcy|KHcy|khcy|DZcy|ecir|edot|eDot|Jscr|jscr|succ|Jopf|jopf|Edot|uHar|emsp|ensp|Iuml|iuml|eopf|isin|Iscr|iscr|Eopf|epar|sung|epsi|escr|sup1|sup2|sup3|Iota|iota|supe|supE|Iopf|iopf|IOcy|iocy|Escr|esim|Esim|imof|Uarr|QUOT|uArr|uarr|euml|IEcy|iecy|Idot|Euml|euro|excl|Hscr|hscr|Hopf|hopf|TScy|tscy|Tscr|hbar|tscr|flat|tbrk|fnof|hArr|harr|half|fopf|Fopf|tdot|gvnE|fork|trie|gtcc|fscr|Fscr|gdot|gsim|Gscr|gscr|Gopf|gopf|gneq|Gdot|tosa|gnap|Topf|topf|geqq|toea|GJcy|gjcy|tint|gesl|mid|Sfr|ggg|top|ges|gla|glE|glj|geq|gne|gEl|gel|gnE|Gcy|gcy|gap|Tfr|tfr|Tcy|tcy|Hat|Tau|Ffr|tau|Tab|hfr|Hfr|ffr|Fcy|fcy|icy|Icy|iff|ETH|eth|ifr|Ifr|Eta|eta|int|Int|Sup|sup|ucy|Ucy|Sum|sum|jcy|ENG|ufr|Ufr|eng|Jcy|jfr|els|ell|egs|Efr|efr|Jfr|uml|kcy|Kcy|Ecy|ecy|kfr|Kfr|lap|Sub|sub|lat|lcy|Lcy|leg|Dot|dot|lEg|leq|les|squ|div|die|lfr|Lfr|lgE|Dfr|dfr|Del|deg|Dcy|dcy|lne|lnE|sol|loz|smt|Cup|lrm|cup|lsh|Lsh|sim|shy|map|Map|mcy|Mcy|mfr|Mfr|mho|gfr|Gfr|sfr|cir|Chi|chi|nap|Cfr|vcy|Vcy|cfr|Scy|scy|ncy|Ncy|vee|Vee|Cap|cap|nfr|scE|sce|Nfr|nge|ngE|nGg|vfr|Vfr|ngt|bot|nGt|nis|niv|Rsh|rsh|nle|nlE|bne|Bfr|bfr|nLl|nlt|nLt|Bcy|bcy|not|Not|rlm|wfr|Wfr|npr|nsc|num|ocy|ast|Ocy|ofr|xfr|Xfr|Ofr|ogt|ohm|apE|olt|Rho|ape|rho|Rfr|rfr|ord|REG|ang|reg|orv|And|and|AMP|Rcy|amp|Afr|ycy|Ycy|yen|yfr|Yfr|rcy|par|pcy|Pcy|pfr|Pfr|phi|Phi|afr|Acy|acy|zcy|Zcy|piv|acE|acd|zfr|Zfr|pre|prE|psi|Psi|qfr|Qfr|zwj|Or|ge|Gg|gt|gg|el|oS|lt|Lt|LT|Re|lg|gl|eg|ne|Im|it|le|DD|wp|wr|nu|Nu|dd|lE|Sc|sc|pi|Pi|ee|af|ll|Ll|rx|gE|xi|pm|Xi|ic|pr|Pr|in|ni|mp|mu|ac|Mu|or|ap|Gt|GT|ii);|&(Aacute|Agrave|Atilde|Ccedil|Eacute|Egrave|Iacute|Igrave|Ntilde|Oacute|Ograve|Oslash|Otilde|Uacute|Ugrave|Yacute|aacute|agrave|atilde|brvbar|ccedil|curren|divide|eacute|egrave|frac12|frac14|frac34|iacute|igrave|iquest|middot|ntilde|oacute|ograve|oslash|otilde|plusmn|uacute|ugrave|yacute|AElig|Acirc|Aring|Ecirc|Icirc|Ocirc|THORN|Ucirc|acirc|acute|aelig|aring|cedil|ecirc|icirc|iexcl|laquo|micro|ocirc|pound|raquo|szlig|thorn|times|ucirc|Auml|COPY|Euml|Iuml|Ouml|QUOT|Uuml|auml|cent|copy|euml|iuml|macr|nbsp|ordf|ordm|ouml|para|quot|sect|sup1|sup2|sup3|uuml|yuml|AMP|ETH|REG|amp|deg|eth|not|reg|shy|uml|yen|GT|LT|gt|lt)(?!;)([=a-zA-Z0-9]?)|&#([0-9]+)(;?)|&#[xX]([a-fA-F0-9]+)(;?)|&([0-9a-zA-Z]+)/g; + var decodeMap = {'aacute':'\xE1','Aacute':'\xC1','abreve':'\u0103','Abreve':'\u0102','ac':'\u223E','acd':'\u223F','acE':'\u223E\u0333','acirc':'\xE2','Acirc':'\xC2','acute':'\xB4','acy':'\u0430','Acy':'\u0410','aelig':'\xE6','AElig':'\xC6','af':'\u2061','afr':'\uD835\uDD1E','Afr':'\uD835\uDD04','agrave':'\xE0','Agrave':'\xC0','alefsym':'\u2135','aleph':'\u2135','alpha':'\u03B1','Alpha':'\u0391','amacr':'\u0101','Amacr':'\u0100','amalg':'\u2A3F','amp':'&','AMP':'&','and':'\u2227','And':'\u2A53','andand':'\u2A55','andd':'\u2A5C','andslope':'\u2A58','andv':'\u2A5A','ang':'\u2220','ange':'\u29A4','angle':'\u2220','angmsd':'\u2221','angmsdaa':'\u29A8','angmsdab':'\u29A9','angmsdac':'\u29AA','angmsdad':'\u29AB','angmsdae':'\u29AC','angmsdaf':'\u29AD','angmsdag':'\u29AE','angmsdah':'\u29AF','angrt':'\u221F','angrtvb':'\u22BE','angrtvbd':'\u299D','angsph':'\u2222','angst':'\xC5','angzarr':'\u237C','aogon':'\u0105','Aogon':'\u0104','aopf':'\uD835\uDD52','Aopf':'\uD835\uDD38','ap':'\u2248','apacir':'\u2A6F','ape':'\u224A','apE':'\u2A70','apid':'\u224B','apos':'\'','ApplyFunction':'\u2061','approx':'\u2248','approxeq':'\u224A','aring':'\xE5','Aring':'\xC5','ascr':'\uD835\uDCB6','Ascr':'\uD835\uDC9C','Assign':'\u2254','ast':'*','asymp':'\u2248','asympeq':'\u224D','atilde':'\xE3','Atilde':'\xC3','auml':'\xE4','Auml':'\xC4','awconint':'\u2233','awint':'\u2A11','backcong':'\u224C','backepsilon':'\u03F6','backprime':'\u2035','backsim':'\u223D','backsimeq':'\u22CD','Backslash':'\u2216','Barv':'\u2AE7','barvee':'\u22BD','barwed':'\u2305','Barwed':'\u2306','barwedge':'\u2305','bbrk':'\u23B5','bbrktbrk':'\u23B6','bcong':'\u224C','bcy':'\u0431','Bcy':'\u0411','bdquo':'\u201E','becaus':'\u2235','because':'\u2235','Because':'\u2235','bemptyv':'\u29B0','bepsi':'\u03F6','bernou':'\u212C','Bernoullis':'\u212C','beta':'\u03B2','Beta':'\u0392','beth':'\u2136','between':'\u226C','bfr':'\uD835\uDD1F','Bfr':'\uD835\uDD05','bigcap':'\u22C2','bigcirc':'\u25EF','bigcup':'\u22C3','bigodot':'\u2A00','bigoplus':'\u2A01','bigotimes':'\u2A02','bigsqcup':'\u2A06','bigstar':'\u2605','bigtriangledown':'\u25BD','bigtriangleup':'\u25B3','biguplus':'\u2A04','bigvee':'\u22C1','bigwedge':'\u22C0','bkarow':'\u290D','blacklozenge':'\u29EB','blacksquare':'\u25AA','blacktriangle':'\u25B4','blacktriangledown':'\u25BE','blacktriangleleft':'\u25C2','blacktriangleright':'\u25B8','blank':'\u2423','blk12':'\u2592','blk14':'\u2591','blk34':'\u2593','block':'\u2588','bne':'=\u20E5','bnequiv':'\u2261\u20E5','bnot':'\u2310','bNot':'\u2AED','bopf':'\uD835\uDD53','Bopf':'\uD835\uDD39','bot':'\u22A5','bottom':'\u22A5','bowtie':'\u22C8','boxbox':'\u29C9','boxdl':'\u2510','boxdL':'\u2555','boxDl':'\u2556','boxDL':'\u2557','boxdr':'\u250C','boxdR':'\u2552','boxDr':'\u2553','boxDR':'\u2554','boxh':'\u2500','boxH':'\u2550','boxhd':'\u252C','boxhD':'\u2565','boxHd':'\u2564','boxHD':'\u2566','boxhu':'\u2534','boxhU':'\u2568','boxHu':'\u2567','boxHU':'\u2569','boxminus':'\u229F','boxplus':'\u229E','boxtimes':'\u22A0','boxul':'\u2518','boxuL':'\u255B','boxUl':'\u255C','boxUL':'\u255D','boxur':'\u2514','boxuR':'\u2558','boxUr':'\u2559','boxUR':'\u255A','boxv':'\u2502','boxV':'\u2551','boxvh':'\u253C','boxvH':'\u256A','boxVh':'\u256B','boxVH':'\u256C','boxvl':'\u2524','boxvL':'\u2561','boxVl':'\u2562','boxVL':'\u2563','boxvr':'\u251C','boxvR':'\u255E','boxVr':'\u255F','boxVR':'\u2560','bprime':'\u2035','breve':'\u02D8','Breve':'\u02D8','brvbar':'\xA6','bscr':'\uD835\uDCB7','Bscr':'\u212C','bsemi':'\u204F','bsim':'\u223D','bsime':'\u22CD','bsol':'\\','bsolb':'\u29C5','bsolhsub':'\u27C8','bull':'\u2022','bullet':'\u2022','bump':'\u224E','bumpe':'\u224F','bumpE':'\u2AAE','bumpeq':'\u224F','Bumpeq':'\u224E','cacute':'\u0107','Cacute':'\u0106','cap':'\u2229','Cap':'\u22D2','capand':'\u2A44','capbrcup':'\u2A49','capcap':'\u2A4B','capcup':'\u2A47','capdot':'\u2A40','CapitalDifferentialD':'\u2145','caps':'\u2229\uFE00','caret':'\u2041','caron':'\u02C7','Cayleys':'\u212D','ccaps':'\u2A4D','ccaron':'\u010D','Ccaron':'\u010C','ccedil':'\xE7','Ccedil':'\xC7','ccirc':'\u0109','Ccirc':'\u0108','Cconint':'\u2230','ccups':'\u2A4C','ccupssm':'\u2A50','cdot':'\u010B','Cdot':'\u010A','cedil':'\xB8','Cedilla':'\xB8','cemptyv':'\u29B2','cent':'\xA2','centerdot':'\xB7','CenterDot':'\xB7','cfr':'\uD835\uDD20','Cfr':'\u212D','chcy':'\u0447','CHcy':'\u0427','check':'\u2713','checkmark':'\u2713','chi':'\u03C7','Chi':'\u03A7','cir':'\u25CB','circ':'\u02C6','circeq':'\u2257','circlearrowleft':'\u21BA','circlearrowright':'\u21BB','circledast':'\u229B','circledcirc':'\u229A','circleddash':'\u229D','CircleDot':'\u2299','circledR':'\xAE','circledS':'\u24C8','CircleMinus':'\u2296','CirclePlus':'\u2295','CircleTimes':'\u2297','cire':'\u2257','cirE':'\u29C3','cirfnint':'\u2A10','cirmid':'\u2AEF','cirscir':'\u29C2','ClockwiseContourIntegral':'\u2232','CloseCurlyDoubleQuote':'\u201D','CloseCurlyQuote':'\u2019','clubs':'\u2663','clubsuit':'\u2663','colon':':','Colon':'\u2237','colone':'\u2254','Colone':'\u2A74','coloneq':'\u2254','comma':',','commat':'@','comp':'\u2201','compfn':'\u2218','complement':'\u2201','complexes':'\u2102','cong':'\u2245','congdot':'\u2A6D','Congruent':'\u2261','conint':'\u222E','Conint':'\u222F','ContourIntegral':'\u222E','copf':'\uD835\uDD54','Copf':'\u2102','coprod':'\u2210','Coproduct':'\u2210','copy':'\xA9','COPY':'\xA9','copysr':'\u2117','CounterClockwiseContourIntegral':'\u2233','crarr':'\u21B5','cross':'\u2717','Cross':'\u2A2F','cscr':'\uD835\uDCB8','Cscr':'\uD835\uDC9E','csub':'\u2ACF','csube':'\u2AD1','csup':'\u2AD0','csupe':'\u2AD2','ctdot':'\u22EF','cudarrl':'\u2938','cudarrr':'\u2935','cuepr':'\u22DE','cuesc':'\u22DF','cularr':'\u21B6','cularrp':'\u293D','cup':'\u222A','Cup':'\u22D3','cupbrcap':'\u2A48','cupcap':'\u2A46','CupCap':'\u224D','cupcup':'\u2A4A','cupdot':'\u228D','cupor':'\u2A45','cups':'\u222A\uFE00','curarr':'\u21B7','curarrm':'\u293C','curlyeqprec':'\u22DE','curlyeqsucc':'\u22DF','curlyvee':'\u22CE','curlywedge':'\u22CF','curren':'\xA4','curvearrowleft':'\u21B6','curvearrowright':'\u21B7','cuvee':'\u22CE','cuwed':'\u22CF','cwconint':'\u2232','cwint':'\u2231','cylcty':'\u232D','dagger':'\u2020','Dagger':'\u2021','daleth':'\u2138','darr':'\u2193','dArr':'\u21D3','Darr':'\u21A1','dash':'\u2010','dashv':'\u22A3','Dashv':'\u2AE4','dbkarow':'\u290F','dblac':'\u02DD','dcaron':'\u010F','Dcaron':'\u010E','dcy':'\u0434','Dcy':'\u0414','dd':'\u2146','DD':'\u2145','ddagger':'\u2021','ddarr':'\u21CA','DDotrahd':'\u2911','ddotseq':'\u2A77','deg':'\xB0','Del':'\u2207','delta':'\u03B4','Delta':'\u0394','demptyv':'\u29B1','dfisht':'\u297F','dfr':'\uD835\uDD21','Dfr':'\uD835\uDD07','dHar':'\u2965','dharl':'\u21C3','dharr':'\u21C2','DiacriticalAcute':'\xB4','DiacriticalDot':'\u02D9','DiacriticalDoubleAcute':'\u02DD','DiacriticalGrave':'`','DiacriticalTilde':'\u02DC','diam':'\u22C4','diamond':'\u22C4','Diamond':'\u22C4','diamondsuit':'\u2666','diams':'\u2666','die':'\xA8','DifferentialD':'\u2146','digamma':'\u03DD','disin':'\u22F2','div':'\xF7','divide':'\xF7','divideontimes':'\u22C7','divonx':'\u22C7','djcy':'\u0452','DJcy':'\u0402','dlcorn':'\u231E','dlcrop':'\u230D','dollar':'$','dopf':'\uD835\uDD55','Dopf':'\uD835\uDD3B','dot':'\u02D9','Dot':'\xA8','DotDot':'\u20DC','doteq':'\u2250','doteqdot':'\u2251','DotEqual':'\u2250','dotminus':'\u2238','dotplus':'\u2214','dotsquare':'\u22A1','doublebarwedge':'\u2306','DoubleContourIntegral':'\u222F','DoubleDot':'\xA8','DoubleDownArrow':'\u21D3','DoubleLeftArrow':'\u21D0','DoubleLeftRightArrow':'\u21D4','DoubleLeftTee':'\u2AE4','DoubleLongLeftArrow':'\u27F8','DoubleLongLeftRightArrow':'\u27FA','DoubleLongRightArrow':'\u27F9','DoubleRightArrow':'\u21D2','DoubleRightTee':'\u22A8','DoubleUpArrow':'\u21D1','DoubleUpDownArrow':'\u21D5','DoubleVerticalBar':'\u2225','downarrow':'\u2193','Downarrow':'\u21D3','DownArrow':'\u2193','DownArrowBar':'\u2913','DownArrowUpArrow':'\u21F5','DownBreve':'\u0311','downdownarrows':'\u21CA','downharpoonleft':'\u21C3','downharpoonright':'\u21C2','DownLeftRightVector':'\u2950','DownLeftTeeVector':'\u295E','DownLeftVector':'\u21BD','DownLeftVectorBar':'\u2956','DownRightTeeVector':'\u295F','DownRightVector':'\u21C1','DownRightVectorBar':'\u2957','DownTee':'\u22A4','DownTeeArrow':'\u21A7','drbkarow':'\u2910','drcorn':'\u231F','drcrop':'\u230C','dscr':'\uD835\uDCB9','Dscr':'\uD835\uDC9F','dscy':'\u0455','DScy':'\u0405','dsol':'\u29F6','dstrok':'\u0111','Dstrok':'\u0110','dtdot':'\u22F1','dtri':'\u25BF','dtrif':'\u25BE','duarr':'\u21F5','duhar':'\u296F','dwangle':'\u29A6','dzcy':'\u045F','DZcy':'\u040F','dzigrarr':'\u27FF','eacute':'\xE9','Eacute':'\xC9','easter':'\u2A6E','ecaron':'\u011B','Ecaron':'\u011A','ecir':'\u2256','ecirc':'\xEA','Ecirc':'\xCA','ecolon':'\u2255','ecy':'\u044D','Ecy':'\u042D','eDDot':'\u2A77','edot':'\u0117','eDot':'\u2251','Edot':'\u0116','ee':'\u2147','efDot':'\u2252','efr':'\uD835\uDD22','Efr':'\uD835\uDD08','eg':'\u2A9A','egrave':'\xE8','Egrave':'\xC8','egs':'\u2A96','egsdot':'\u2A98','el':'\u2A99','Element':'\u2208','elinters':'\u23E7','ell':'\u2113','els':'\u2A95','elsdot':'\u2A97','emacr':'\u0113','Emacr':'\u0112','empty':'\u2205','emptyset':'\u2205','EmptySmallSquare':'\u25FB','emptyv':'\u2205','EmptyVerySmallSquare':'\u25AB','emsp':'\u2003','emsp13':'\u2004','emsp14':'\u2005','eng':'\u014B','ENG':'\u014A','ensp':'\u2002','eogon':'\u0119','Eogon':'\u0118','eopf':'\uD835\uDD56','Eopf':'\uD835\uDD3C','epar':'\u22D5','eparsl':'\u29E3','eplus':'\u2A71','epsi':'\u03B5','epsilon':'\u03B5','Epsilon':'\u0395','epsiv':'\u03F5','eqcirc':'\u2256','eqcolon':'\u2255','eqsim':'\u2242','eqslantgtr':'\u2A96','eqslantless':'\u2A95','Equal':'\u2A75','equals':'=','EqualTilde':'\u2242','equest':'\u225F','Equilibrium':'\u21CC','equiv':'\u2261','equivDD':'\u2A78','eqvparsl':'\u29E5','erarr':'\u2971','erDot':'\u2253','escr':'\u212F','Escr':'\u2130','esdot':'\u2250','esim':'\u2242','Esim':'\u2A73','eta':'\u03B7','Eta':'\u0397','eth':'\xF0','ETH':'\xD0','euml':'\xEB','Euml':'\xCB','euro':'\u20AC','excl':'!','exist':'\u2203','Exists':'\u2203','expectation':'\u2130','exponentiale':'\u2147','ExponentialE':'\u2147','fallingdotseq':'\u2252','fcy':'\u0444','Fcy':'\u0424','female':'\u2640','ffilig':'\uFB03','fflig':'\uFB00','ffllig':'\uFB04','ffr':'\uD835\uDD23','Ffr':'\uD835\uDD09','filig':'\uFB01','FilledSmallSquare':'\u25FC','FilledVerySmallSquare':'\u25AA','fjlig':'fj','flat':'\u266D','fllig':'\uFB02','fltns':'\u25B1','fnof':'\u0192','fopf':'\uD835\uDD57','Fopf':'\uD835\uDD3D','forall':'\u2200','ForAll':'\u2200','fork':'\u22D4','forkv':'\u2AD9','Fouriertrf':'\u2131','fpartint':'\u2A0D','frac12':'\xBD','frac13':'\u2153','frac14':'\xBC','frac15':'\u2155','frac16':'\u2159','frac18':'\u215B','frac23':'\u2154','frac25':'\u2156','frac34':'\xBE','frac35':'\u2157','frac38':'\u215C','frac45':'\u2158','frac56':'\u215A','frac58':'\u215D','frac78':'\u215E','frasl':'\u2044','frown':'\u2322','fscr':'\uD835\uDCBB','Fscr':'\u2131','gacute':'\u01F5','gamma':'\u03B3','Gamma':'\u0393','gammad':'\u03DD','Gammad':'\u03DC','gap':'\u2A86','gbreve':'\u011F','Gbreve':'\u011E','Gcedil':'\u0122','gcirc':'\u011D','Gcirc':'\u011C','gcy':'\u0433','Gcy':'\u0413','gdot':'\u0121','Gdot':'\u0120','ge':'\u2265','gE':'\u2267','gel':'\u22DB','gEl':'\u2A8C','geq':'\u2265','geqq':'\u2267','geqslant':'\u2A7E','ges':'\u2A7E','gescc':'\u2AA9','gesdot':'\u2A80','gesdoto':'\u2A82','gesdotol':'\u2A84','gesl':'\u22DB\uFE00','gesles':'\u2A94','gfr':'\uD835\uDD24','Gfr':'\uD835\uDD0A','gg':'\u226B','Gg':'\u22D9','ggg':'\u22D9','gimel':'\u2137','gjcy':'\u0453','GJcy':'\u0403','gl':'\u2277','gla':'\u2AA5','glE':'\u2A92','glj':'\u2AA4','gnap':'\u2A8A','gnapprox':'\u2A8A','gne':'\u2A88','gnE':'\u2269','gneq':'\u2A88','gneqq':'\u2269','gnsim':'\u22E7','gopf':'\uD835\uDD58','Gopf':'\uD835\uDD3E','grave':'`','GreaterEqual':'\u2265','GreaterEqualLess':'\u22DB','GreaterFullEqual':'\u2267','GreaterGreater':'\u2AA2','GreaterLess':'\u2277','GreaterSlantEqual':'\u2A7E','GreaterTilde':'\u2273','gscr':'\u210A','Gscr':'\uD835\uDCA2','gsim':'\u2273','gsime':'\u2A8E','gsiml':'\u2A90','gt':'>','Gt':'\u226B','GT':'>','gtcc':'\u2AA7','gtcir':'\u2A7A','gtdot':'\u22D7','gtlPar':'\u2995','gtquest':'\u2A7C','gtrapprox':'\u2A86','gtrarr':'\u2978','gtrdot':'\u22D7','gtreqless':'\u22DB','gtreqqless':'\u2A8C','gtrless':'\u2277','gtrsim':'\u2273','gvertneqq':'\u2269\uFE00','gvnE':'\u2269\uFE00','Hacek':'\u02C7','hairsp':'\u200A','half':'\xBD','hamilt':'\u210B','hardcy':'\u044A','HARDcy':'\u042A','harr':'\u2194','hArr':'\u21D4','harrcir':'\u2948','harrw':'\u21AD','Hat':'^','hbar':'\u210F','hcirc':'\u0125','Hcirc':'\u0124','hearts':'\u2665','heartsuit':'\u2665','hellip':'\u2026','hercon':'\u22B9','hfr':'\uD835\uDD25','Hfr':'\u210C','HilbertSpace':'\u210B','hksearow':'\u2925','hkswarow':'\u2926','hoarr':'\u21FF','homtht':'\u223B','hookleftarrow':'\u21A9','hookrightarrow':'\u21AA','hopf':'\uD835\uDD59','Hopf':'\u210D','horbar':'\u2015','HorizontalLine':'\u2500','hscr':'\uD835\uDCBD','Hscr':'\u210B','hslash':'\u210F','hstrok':'\u0127','Hstrok':'\u0126','HumpDownHump':'\u224E','HumpEqual':'\u224F','hybull':'\u2043','hyphen':'\u2010','iacute':'\xED','Iacute':'\xCD','ic':'\u2063','icirc':'\xEE','Icirc':'\xCE','icy':'\u0438','Icy':'\u0418','Idot':'\u0130','iecy':'\u0435','IEcy':'\u0415','iexcl':'\xA1','iff':'\u21D4','ifr':'\uD835\uDD26','Ifr':'\u2111','igrave':'\xEC','Igrave':'\xCC','ii':'\u2148','iiiint':'\u2A0C','iiint':'\u222D','iinfin':'\u29DC','iiota':'\u2129','ijlig':'\u0133','IJlig':'\u0132','Im':'\u2111','imacr':'\u012B','Imacr':'\u012A','image':'\u2111','ImaginaryI':'\u2148','imagline':'\u2110','imagpart':'\u2111','imath':'\u0131','imof':'\u22B7','imped':'\u01B5','Implies':'\u21D2','in':'\u2208','incare':'\u2105','infin':'\u221E','infintie':'\u29DD','inodot':'\u0131','int':'\u222B','Int':'\u222C','intcal':'\u22BA','integers':'\u2124','Integral':'\u222B','intercal':'\u22BA','Intersection':'\u22C2','intlarhk':'\u2A17','intprod':'\u2A3C','InvisibleComma':'\u2063','InvisibleTimes':'\u2062','iocy':'\u0451','IOcy':'\u0401','iogon':'\u012F','Iogon':'\u012E','iopf':'\uD835\uDD5A','Iopf':'\uD835\uDD40','iota':'\u03B9','Iota':'\u0399','iprod':'\u2A3C','iquest':'\xBF','iscr':'\uD835\uDCBE','Iscr':'\u2110','isin':'\u2208','isindot':'\u22F5','isinE':'\u22F9','isins':'\u22F4','isinsv':'\u22F3','isinv':'\u2208','it':'\u2062','itilde':'\u0129','Itilde':'\u0128','iukcy':'\u0456','Iukcy':'\u0406','iuml':'\xEF','Iuml':'\xCF','jcirc':'\u0135','Jcirc':'\u0134','jcy':'\u0439','Jcy':'\u0419','jfr':'\uD835\uDD27','Jfr':'\uD835\uDD0D','jmath':'\u0237','jopf':'\uD835\uDD5B','Jopf':'\uD835\uDD41','jscr':'\uD835\uDCBF','Jscr':'\uD835\uDCA5','jsercy':'\u0458','Jsercy':'\u0408','jukcy':'\u0454','Jukcy':'\u0404','kappa':'\u03BA','Kappa':'\u039A','kappav':'\u03F0','kcedil':'\u0137','Kcedil':'\u0136','kcy':'\u043A','Kcy':'\u041A','kfr':'\uD835\uDD28','Kfr':'\uD835\uDD0E','kgreen':'\u0138','khcy':'\u0445','KHcy':'\u0425','kjcy':'\u045C','KJcy':'\u040C','kopf':'\uD835\uDD5C','Kopf':'\uD835\uDD42','kscr':'\uD835\uDCC0','Kscr':'\uD835\uDCA6','lAarr':'\u21DA','lacute':'\u013A','Lacute':'\u0139','laemptyv':'\u29B4','lagran':'\u2112','lambda':'\u03BB','Lambda':'\u039B','lang':'\u27E8','Lang':'\u27EA','langd':'\u2991','langle':'\u27E8','lap':'\u2A85','Laplacetrf':'\u2112','laquo':'\xAB','larr':'\u2190','lArr':'\u21D0','Larr':'\u219E','larrb':'\u21E4','larrbfs':'\u291F','larrfs':'\u291D','larrhk':'\u21A9','larrlp':'\u21AB','larrpl':'\u2939','larrsim':'\u2973','larrtl':'\u21A2','lat':'\u2AAB','latail':'\u2919','lAtail':'\u291B','late':'\u2AAD','lates':'\u2AAD\uFE00','lbarr':'\u290C','lBarr':'\u290E','lbbrk':'\u2772','lbrace':'{','lbrack':'[','lbrke':'\u298B','lbrksld':'\u298F','lbrkslu':'\u298D','lcaron':'\u013E','Lcaron':'\u013D','lcedil':'\u013C','Lcedil':'\u013B','lceil':'\u2308','lcub':'{','lcy':'\u043B','Lcy':'\u041B','ldca':'\u2936','ldquo':'\u201C','ldquor':'\u201E','ldrdhar':'\u2967','ldrushar':'\u294B','ldsh':'\u21B2','le':'\u2264','lE':'\u2266','LeftAngleBracket':'\u27E8','leftarrow':'\u2190','Leftarrow':'\u21D0','LeftArrow':'\u2190','LeftArrowBar':'\u21E4','LeftArrowRightArrow':'\u21C6','leftarrowtail':'\u21A2','LeftCeiling':'\u2308','LeftDoubleBracket':'\u27E6','LeftDownTeeVector':'\u2961','LeftDownVector':'\u21C3','LeftDownVectorBar':'\u2959','LeftFloor':'\u230A','leftharpoondown':'\u21BD','leftharpoonup':'\u21BC','leftleftarrows':'\u21C7','leftrightarrow':'\u2194','Leftrightarrow':'\u21D4','LeftRightArrow':'\u2194','leftrightarrows':'\u21C6','leftrightharpoons':'\u21CB','leftrightsquigarrow':'\u21AD','LeftRightVector':'\u294E','LeftTee':'\u22A3','LeftTeeArrow':'\u21A4','LeftTeeVector':'\u295A','leftthreetimes':'\u22CB','LeftTriangle':'\u22B2','LeftTriangleBar':'\u29CF','LeftTriangleEqual':'\u22B4','LeftUpDownVector':'\u2951','LeftUpTeeVector':'\u2960','LeftUpVector':'\u21BF','LeftUpVectorBar':'\u2958','LeftVector':'\u21BC','LeftVectorBar':'\u2952','leg':'\u22DA','lEg':'\u2A8B','leq':'\u2264','leqq':'\u2266','leqslant':'\u2A7D','les':'\u2A7D','lescc':'\u2AA8','lesdot':'\u2A7F','lesdoto':'\u2A81','lesdotor':'\u2A83','lesg':'\u22DA\uFE00','lesges':'\u2A93','lessapprox':'\u2A85','lessdot':'\u22D6','lesseqgtr':'\u22DA','lesseqqgtr':'\u2A8B','LessEqualGreater':'\u22DA','LessFullEqual':'\u2266','LessGreater':'\u2276','lessgtr':'\u2276','LessLess':'\u2AA1','lesssim':'\u2272','LessSlantEqual':'\u2A7D','LessTilde':'\u2272','lfisht':'\u297C','lfloor':'\u230A','lfr':'\uD835\uDD29','Lfr':'\uD835\uDD0F','lg':'\u2276','lgE':'\u2A91','lHar':'\u2962','lhard':'\u21BD','lharu':'\u21BC','lharul':'\u296A','lhblk':'\u2584','ljcy':'\u0459','LJcy':'\u0409','ll':'\u226A','Ll':'\u22D8','llarr':'\u21C7','llcorner':'\u231E','Lleftarrow':'\u21DA','llhard':'\u296B','lltri':'\u25FA','lmidot':'\u0140','Lmidot':'\u013F','lmoust':'\u23B0','lmoustache':'\u23B0','lnap':'\u2A89','lnapprox':'\u2A89','lne':'\u2A87','lnE':'\u2268','lneq':'\u2A87','lneqq':'\u2268','lnsim':'\u22E6','loang':'\u27EC','loarr':'\u21FD','lobrk':'\u27E6','longleftarrow':'\u27F5','Longleftarrow':'\u27F8','LongLeftArrow':'\u27F5','longleftrightarrow':'\u27F7','Longleftrightarrow':'\u27FA','LongLeftRightArrow':'\u27F7','longmapsto':'\u27FC','longrightarrow':'\u27F6','Longrightarrow':'\u27F9','LongRightArrow':'\u27F6','looparrowleft':'\u21AB','looparrowright':'\u21AC','lopar':'\u2985','lopf':'\uD835\uDD5D','Lopf':'\uD835\uDD43','loplus':'\u2A2D','lotimes':'\u2A34','lowast':'\u2217','lowbar':'_','LowerLeftArrow':'\u2199','LowerRightArrow':'\u2198','loz':'\u25CA','lozenge':'\u25CA','lozf':'\u29EB','lpar':'(','lparlt':'\u2993','lrarr':'\u21C6','lrcorner':'\u231F','lrhar':'\u21CB','lrhard':'\u296D','lrm':'\u200E','lrtri':'\u22BF','lsaquo':'\u2039','lscr':'\uD835\uDCC1','Lscr':'\u2112','lsh':'\u21B0','Lsh':'\u21B0','lsim':'\u2272','lsime':'\u2A8D','lsimg':'\u2A8F','lsqb':'[','lsquo':'\u2018','lsquor':'\u201A','lstrok':'\u0142','Lstrok':'\u0141','lt':'<','Lt':'\u226A','LT':'<','ltcc':'\u2AA6','ltcir':'\u2A79','ltdot':'\u22D6','lthree':'\u22CB','ltimes':'\u22C9','ltlarr':'\u2976','ltquest':'\u2A7B','ltri':'\u25C3','ltrie':'\u22B4','ltrif':'\u25C2','ltrPar':'\u2996','lurdshar':'\u294A','luruhar':'\u2966','lvertneqq':'\u2268\uFE00','lvnE':'\u2268\uFE00','macr':'\xAF','male':'\u2642','malt':'\u2720','maltese':'\u2720','map':'\u21A6','Map':'\u2905','mapsto':'\u21A6','mapstodown':'\u21A7','mapstoleft':'\u21A4','mapstoup':'\u21A5','marker':'\u25AE','mcomma':'\u2A29','mcy':'\u043C','Mcy':'\u041C','mdash':'\u2014','mDDot':'\u223A','measuredangle':'\u2221','MediumSpace':'\u205F','Mellintrf':'\u2133','mfr':'\uD835\uDD2A','Mfr':'\uD835\uDD10','mho':'\u2127','micro':'\xB5','mid':'\u2223','midast':'*','midcir':'\u2AF0','middot':'\xB7','minus':'\u2212','minusb':'\u229F','minusd':'\u2238','minusdu':'\u2A2A','MinusPlus':'\u2213','mlcp':'\u2ADB','mldr':'\u2026','mnplus':'\u2213','models':'\u22A7','mopf':'\uD835\uDD5E','Mopf':'\uD835\uDD44','mp':'\u2213','mscr':'\uD835\uDCC2','Mscr':'\u2133','mstpos':'\u223E','mu':'\u03BC','Mu':'\u039C','multimap':'\u22B8','mumap':'\u22B8','nabla':'\u2207','nacute':'\u0144','Nacute':'\u0143','nang':'\u2220\u20D2','nap':'\u2249','napE':'\u2A70\u0338','napid':'\u224B\u0338','napos':'\u0149','napprox':'\u2249','natur':'\u266E','natural':'\u266E','naturals':'\u2115','nbsp':'\xA0','nbump':'\u224E\u0338','nbumpe':'\u224F\u0338','ncap':'\u2A43','ncaron':'\u0148','Ncaron':'\u0147','ncedil':'\u0146','Ncedil':'\u0145','ncong':'\u2247','ncongdot':'\u2A6D\u0338','ncup':'\u2A42','ncy':'\u043D','Ncy':'\u041D','ndash':'\u2013','ne':'\u2260','nearhk':'\u2924','nearr':'\u2197','neArr':'\u21D7','nearrow':'\u2197','nedot':'\u2250\u0338','NegativeMediumSpace':'\u200B','NegativeThickSpace':'\u200B','NegativeThinSpace':'\u200B','NegativeVeryThinSpace':'\u200B','nequiv':'\u2262','nesear':'\u2928','nesim':'\u2242\u0338','NestedGreaterGreater':'\u226B','NestedLessLess':'\u226A','NewLine':'\n','nexist':'\u2204','nexists':'\u2204','nfr':'\uD835\uDD2B','Nfr':'\uD835\uDD11','nge':'\u2271','ngE':'\u2267\u0338','ngeq':'\u2271','ngeqq':'\u2267\u0338','ngeqslant':'\u2A7E\u0338','nges':'\u2A7E\u0338','nGg':'\u22D9\u0338','ngsim':'\u2275','ngt':'\u226F','nGt':'\u226B\u20D2','ngtr':'\u226F','nGtv':'\u226B\u0338','nharr':'\u21AE','nhArr':'\u21CE','nhpar':'\u2AF2','ni':'\u220B','nis':'\u22FC','nisd':'\u22FA','niv':'\u220B','njcy':'\u045A','NJcy':'\u040A','nlarr':'\u219A','nlArr':'\u21CD','nldr':'\u2025','nle':'\u2270','nlE':'\u2266\u0338','nleftarrow':'\u219A','nLeftarrow':'\u21CD','nleftrightarrow':'\u21AE','nLeftrightarrow':'\u21CE','nleq':'\u2270','nleqq':'\u2266\u0338','nleqslant':'\u2A7D\u0338','nles':'\u2A7D\u0338','nless':'\u226E','nLl':'\u22D8\u0338','nlsim':'\u2274','nlt':'\u226E','nLt':'\u226A\u20D2','nltri':'\u22EA','nltrie':'\u22EC','nLtv':'\u226A\u0338','nmid':'\u2224','NoBreak':'\u2060','NonBreakingSpace':'\xA0','nopf':'\uD835\uDD5F','Nopf':'\u2115','not':'\xAC','Not':'\u2AEC','NotCongruent':'\u2262','NotCupCap':'\u226D','NotDoubleVerticalBar':'\u2226','NotElement':'\u2209','NotEqual':'\u2260','NotEqualTilde':'\u2242\u0338','NotExists':'\u2204','NotGreater':'\u226F','NotGreaterEqual':'\u2271','NotGreaterFullEqual':'\u2267\u0338','NotGreaterGreater':'\u226B\u0338','NotGreaterLess':'\u2279','NotGreaterSlantEqual':'\u2A7E\u0338','NotGreaterTilde':'\u2275','NotHumpDownHump':'\u224E\u0338','NotHumpEqual':'\u224F\u0338','notin':'\u2209','notindot':'\u22F5\u0338','notinE':'\u22F9\u0338','notinva':'\u2209','notinvb':'\u22F7','notinvc':'\u22F6','NotLeftTriangle':'\u22EA','NotLeftTriangleBar':'\u29CF\u0338','NotLeftTriangleEqual':'\u22EC','NotLess':'\u226E','NotLessEqual':'\u2270','NotLessGreater':'\u2278','NotLessLess':'\u226A\u0338','NotLessSlantEqual':'\u2A7D\u0338','NotLessTilde':'\u2274','NotNestedGreaterGreater':'\u2AA2\u0338','NotNestedLessLess':'\u2AA1\u0338','notni':'\u220C','notniva':'\u220C','notnivb':'\u22FE','notnivc':'\u22FD','NotPrecedes':'\u2280','NotPrecedesEqual':'\u2AAF\u0338','NotPrecedesSlantEqual':'\u22E0','NotReverseElement':'\u220C','NotRightTriangle':'\u22EB','NotRightTriangleBar':'\u29D0\u0338','NotRightTriangleEqual':'\u22ED','NotSquareSubset':'\u228F\u0338','NotSquareSubsetEqual':'\u22E2','NotSquareSuperset':'\u2290\u0338','NotSquareSupersetEqual':'\u22E3','NotSubset':'\u2282\u20D2','NotSubsetEqual':'\u2288','NotSucceeds':'\u2281','NotSucceedsEqual':'\u2AB0\u0338','NotSucceedsSlantEqual':'\u22E1','NotSucceedsTilde':'\u227F\u0338','NotSuperset':'\u2283\u20D2','NotSupersetEqual':'\u2289','NotTilde':'\u2241','NotTildeEqual':'\u2244','NotTildeFullEqual':'\u2247','NotTildeTilde':'\u2249','NotVerticalBar':'\u2224','npar':'\u2226','nparallel':'\u2226','nparsl':'\u2AFD\u20E5','npart':'\u2202\u0338','npolint':'\u2A14','npr':'\u2280','nprcue':'\u22E0','npre':'\u2AAF\u0338','nprec':'\u2280','npreceq':'\u2AAF\u0338','nrarr':'\u219B','nrArr':'\u21CF','nrarrc':'\u2933\u0338','nrarrw':'\u219D\u0338','nrightarrow':'\u219B','nRightarrow':'\u21CF','nrtri':'\u22EB','nrtrie':'\u22ED','nsc':'\u2281','nsccue':'\u22E1','nsce':'\u2AB0\u0338','nscr':'\uD835\uDCC3','Nscr':'\uD835\uDCA9','nshortmid':'\u2224','nshortparallel':'\u2226','nsim':'\u2241','nsime':'\u2244','nsimeq':'\u2244','nsmid':'\u2224','nspar':'\u2226','nsqsube':'\u22E2','nsqsupe':'\u22E3','nsub':'\u2284','nsube':'\u2288','nsubE':'\u2AC5\u0338','nsubset':'\u2282\u20D2','nsubseteq':'\u2288','nsubseteqq':'\u2AC5\u0338','nsucc':'\u2281','nsucceq':'\u2AB0\u0338','nsup':'\u2285','nsupe':'\u2289','nsupE':'\u2AC6\u0338','nsupset':'\u2283\u20D2','nsupseteq':'\u2289','nsupseteqq':'\u2AC6\u0338','ntgl':'\u2279','ntilde':'\xF1','Ntilde':'\xD1','ntlg':'\u2278','ntriangleleft':'\u22EA','ntrianglelefteq':'\u22EC','ntriangleright':'\u22EB','ntrianglerighteq':'\u22ED','nu':'\u03BD','Nu':'\u039D','num':'#','numero':'\u2116','numsp':'\u2007','nvap':'\u224D\u20D2','nvdash':'\u22AC','nvDash':'\u22AD','nVdash':'\u22AE','nVDash':'\u22AF','nvge':'\u2265\u20D2','nvgt':'>\u20D2','nvHarr':'\u2904','nvinfin':'\u29DE','nvlArr':'\u2902','nvle':'\u2264\u20D2','nvlt':'<\u20D2','nvltrie':'\u22B4\u20D2','nvrArr':'\u2903','nvrtrie':'\u22B5\u20D2','nvsim':'\u223C\u20D2','nwarhk':'\u2923','nwarr':'\u2196','nwArr':'\u21D6','nwarrow':'\u2196','nwnear':'\u2927','oacute':'\xF3','Oacute':'\xD3','oast':'\u229B','ocir':'\u229A','ocirc':'\xF4','Ocirc':'\xD4','ocy':'\u043E','Ocy':'\u041E','odash':'\u229D','odblac':'\u0151','Odblac':'\u0150','odiv':'\u2A38','odot':'\u2299','odsold':'\u29BC','oelig':'\u0153','OElig':'\u0152','ofcir':'\u29BF','ofr':'\uD835\uDD2C','Ofr':'\uD835\uDD12','ogon':'\u02DB','ograve':'\xF2','Ograve':'\xD2','ogt':'\u29C1','ohbar':'\u29B5','ohm':'\u03A9','oint':'\u222E','olarr':'\u21BA','olcir':'\u29BE','olcross':'\u29BB','oline':'\u203E','olt':'\u29C0','omacr':'\u014D','Omacr':'\u014C','omega':'\u03C9','Omega':'\u03A9','omicron':'\u03BF','Omicron':'\u039F','omid':'\u29B6','ominus':'\u2296','oopf':'\uD835\uDD60','Oopf':'\uD835\uDD46','opar':'\u29B7','OpenCurlyDoubleQuote':'\u201C','OpenCurlyQuote':'\u2018','operp':'\u29B9','oplus':'\u2295','or':'\u2228','Or':'\u2A54','orarr':'\u21BB','ord':'\u2A5D','order':'\u2134','orderof':'\u2134','ordf':'\xAA','ordm':'\xBA','origof':'\u22B6','oror':'\u2A56','orslope':'\u2A57','orv':'\u2A5B','oS':'\u24C8','oscr':'\u2134','Oscr':'\uD835\uDCAA','oslash':'\xF8','Oslash':'\xD8','osol':'\u2298','otilde':'\xF5','Otilde':'\xD5','otimes':'\u2297','Otimes':'\u2A37','otimesas':'\u2A36','ouml':'\xF6','Ouml':'\xD6','ovbar':'\u233D','OverBar':'\u203E','OverBrace':'\u23DE','OverBracket':'\u23B4','OverParenthesis':'\u23DC','par':'\u2225','para':'\xB6','parallel':'\u2225','parsim':'\u2AF3','parsl':'\u2AFD','part':'\u2202','PartialD':'\u2202','pcy':'\u043F','Pcy':'\u041F','percnt':'%','period':'.','permil':'\u2030','perp':'\u22A5','pertenk':'\u2031','pfr':'\uD835\uDD2D','Pfr':'\uD835\uDD13','phi':'\u03C6','Phi':'\u03A6','phiv':'\u03D5','phmmat':'\u2133','phone':'\u260E','pi':'\u03C0','Pi':'\u03A0','pitchfork':'\u22D4','piv':'\u03D6','planck':'\u210F','planckh':'\u210E','plankv':'\u210F','plus':'+','plusacir':'\u2A23','plusb':'\u229E','pluscir':'\u2A22','plusdo':'\u2214','plusdu':'\u2A25','pluse':'\u2A72','PlusMinus':'\xB1','plusmn':'\xB1','plussim':'\u2A26','plustwo':'\u2A27','pm':'\xB1','Poincareplane':'\u210C','pointint':'\u2A15','popf':'\uD835\uDD61','Popf':'\u2119','pound':'\xA3','pr':'\u227A','Pr':'\u2ABB','prap':'\u2AB7','prcue':'\u227C','pre':'\u2AAF','prE':'\u2AB3','prec':'\u227A','precapprox':'\u2AB7','preccurlyeq':'\u227C','Precedes':'\u227A','PrecedesEqual':'\u2AAF','PrecedesSlantEqual':'\u227C','PrecedesTilde':'\u227E','preceq':'\u2AAF','precnapprox':'\u2AB9','precneqq':'\u2AB5','precnsim':'\u22E8','precsim':'\u227E','prime':'\u2032','Prime':'\u2033','primes':'\u2119','prnap':'\u2AB9','prnE':'\u2AB5','prnsim':'\u22E8','prod':'\u220F','Product':'\u220F','profalar':'\u232E','profline':'\u2312','profsurf':'\u2313','prop':'\u221D','Proportion':'\u2237','Proportional':'\u221D','propto':'\u221D','prsim':'\u227E','prurel':'\u22B0','pscr':'\uD835\uDCC5','Pscr':'\uD835\uDCAB','psi':'\u03C8','Psi':'\u03A8','puncsp':'\u2008','qfr':'\uD835\uDD2E','Qfr':'\uD835\uDD14','qint':'\u2A0C','qopf':'\uD835\uDD62','Qopf':'\u211A','qprime':'\u2057','qscr':'\uD835\uDCC6','Qscr':'\uD835\uDCAC','quaternions':'\u210D','quatint':'\u2A16','quest':'?','questeq':'\u225F','quot':'"','QUOT':'"','rAarr':'\u21DB','race':'\u223D\u0331','racute':'\u0155','Racute':'\u0154','radic':'\u221A','raemptyv':'\u29B3','rang':'\u27E9','Rang':'\u27EB','rangd':'\u2992','range':'\u29A5','rangle':'\u27E9','raquo':'\xBB','rarr':'\u2192','rArr':'\u21D2','Rarr':'\u21A0','rarrap':'\u2975','rarrb':'\u21E5','rarrbfs':'\u2920','rarrc':'\u2933','rarrfs':'\u291E','rarrhk':'\u21AA','rarrlp':'\u21AC','rarrpl':'\u2945','rarrsim':'\u2974','rarrtl':'\u21A3','Rarrtl':'\u2916','rarrw':'\u219D','ratail':'\u291A','rAtail':'\u291C','ratio':'\u2236','rationals':'\u211A','rbarr':'\u290D','rBarr':'\u290F','RBarr':'\u2910','rbbrk':'\u2773','rbrace':'}','rbrack':']','rbrke':'\u298C','rbrksld':'\u298E','rbrkslu':'\u2990','rcaron':'\u0159','Rcaron':'\u0158','rcedil':'\u0157','Rcedil':'\u0156','rceil':'\u2309','rcub':'}','rcy':'\u0440','Rcy':'\u0420','rdca':'\u2937','rdldhar':'\u2969','rdquo':'\u201D','rdquor':'\u201D','rdsh':'\u21B3','Re':'\u211C','real':'\u211C','realine':'\u211B','realpart':'\u211C','reals':'\u211D','rect':'\u25AD','reg':'\xAE','REG':'\xAE','ReverseElement':'\u220B','ReverseEquilibrium':'\u21CB','ReverseUpEquilibrium':'\u296F','rfisht':'\u297D','rfloor':'\u230B','rfr':'\uD835\uDD2F','Rfr':'\u211C','rHar':'\u2964','rhard':'\u21C1','rharu':'\u21C0','rharul':'\u296C','rho':'\u03C1','Rho':'\u03A1','rhov':'\u03F1','RightAngleBracket':'\u27E9','rightarrow':'\u2192','Rightarrow':'\u21D2','RightArrow':'\u2192','RightArrowBar':'\u21E5','RightArrowLeftArrow':'\u21C4','rightarrowtail':'\u21A3','RightCeiling':'\u2309','RightDoubleBracket':'\u27E7','RightDownTeeVector':'\u295D','RightDownVector':'\u21C2','RightDownVectorBar':'\u2955','RightFloor':'\u230B','rightharpoondown':'\u21C1','rightharpoonup':'\u21C0','rightleftarrows':'\u21C4','rightleftharpoons':'\u21CC','rightrightarrows':'\u21C9','rightsquigarrow':'\u219D','RightTee':'\u22A2','RightTeeArrow':'\u21A6','RightTeeVector':'\u295B','rightthreetimes':'\u22CC','RightTriangle':'\u22B3','RightTriangleBar':'\u29D0','RightTriangleEqual':'\u22B5','RightUpDownVector':'\u294F','RightUpTeeVector':'\u295C','RightUpVector':'\u21BE','RightUpVectorBar':'\u2954','RightVector':'\u21C0','RightVectorBar':'\u2953','ring':'\u02DA','risingdotseq':'\u2253','rlarr':'\u21C4','rlhar':'\u21CC','rlm':'\u200F','rmoust':'\u23B1','rmoustache':'\u23B1','rnmid':'\u2AEE','roang':'\u27ED','roarr':'\u21FE','robrk':'\u27E7','ropar':'\u2986','ropf':'\uD835\uDD63','Ropf':'\u211D','roplus':'\u2A2E','rotimes':'\u2A35','RoundImplies':'\u2970','rpar':')','rpargt':'\u2994','rppolint':'\u2A12','rrarr':'\u21C9','Rrightarrow':'\u21DB','rsaquo':'\u203A','rscr':'\uD835\uDCC7','Rscr':'\u211B','rsh':'\u21B1','Rsh':'\u21B1','rsqb':']','rsquo':'\u2019','rsquor':'\u2019','rthree':'\u22CC','rtimes':'\u22CA','rtri':'\u25B9','rtrie':'\u22B5','rtrif':'\u25B8','rtriltri':'\u29CE','RuleDelayed':'\u29F4','ruluhar':'\u2968','rx':'\u211E','sacute':'\u015B','Sacute':'\u015A','sbquo':'\u201A','sc':'\u227B','Sc':'\u2ABC','scap':'\u2AB8','scaron':'\u0161','Scaron':'\u0160','sccue':'\u227D','sce':'\u2AB0','scE':'\u2AB4','scedil':'\u015F','Scedil':'\u015E','scirc':'\u015D','Scirc':'\u015C','scnap':'\u2ABA','scnE':'\u2AB6','scnsim':'\u22E9','scpolint':'\u2A13','scsim':'\u227F','scy':'\u0441','Scy':'\u0421','sdot':'\u22C5','sdotb':'\u22A1','sdote':'\u2A66','searhk':'\u2925','searr':'\u2198','seArr':'\u21D8','searrow':'\u2198','sect':'\xA7','semi':';','seswar':'\u2929','setminus':'\u2216','setmn':'\u2216','sext':'\u2736','sfr':'\uD835\uDD30','Sfr':'\uD835\uDD16','sfrown':'\u2322','sharp':'\u266F','shchcy':'\u0449','SHCHcy':'\u0429','shcy':'\u0448','SHcy':'\u0428','ShortDownArrow':'\u2193','ShortLeftArrow':'\u2190','shortmid':'\u2223','shortparallel':'\u2225','ShortRightArrow':'\u2192','ShortUpArrow':'\u2191','shy':'\xAD','sigma':'\u03C3','Sigma':'\u03A3','sigmaf':'\u03C2','sigmav':'\u03C2','sim':'\u223C','simdot':'\u2A6A','sime':'\u2243','simeq':'\u2243','simg':'\u2A9E','simgE':'\u2AA0','siml':'\u2A9D','simlE':'\u2A9F','simne':'\u2246','simplus':'\u2A24','simrarr':'\u2972','slarr':'\u2190','SmallCircle':'\u2218','smallsetminus':'\u2216','smashp':'\u2A33','smeparsl':'\u29E4','smid':'\u2223','smile':'\u2323','smt':'\u2AAA','smte':'\u2AAC','smtes':'\u2AAC\uFE00','softcy':'\u044C','SOFTcy':'\u042C','sol':'/','solb':'\u29C4','solbar':'\u233F','sopf':'\uD835\uDD64','Sopf':'\uD835\uDD4A','spades':'\u2660','spadesuit':'\u2660','spar':'\u2225','sqcap':'\u2293','sqcaps':'\u2293\uFE00','sqcup':'\u2294','sqcups':'\u2294\uFE00','Sqrt':'\u221A','sqsub':'\u228F','sqsube':'\u2291','sqsubset':'\u228F','sqsubseteq':'\u2291','sqsup':'\u2290','sqsupe':'\u2292','sqsupset':'\u2290','sqsupseteq':'\u2292','squ':'\u25A1','square':'\u25A1','Square':'\u25A1','SquareIntersection':'\u2293','SquareSubset':'\u228F','SquareSubsetEqual':'\u2291','SquareSuperset':'\u2290','SquareSupersetEqual':'\u2292','SquareUnion':'\u2294','squarf':'\u25AA','squf':'\u25AA','srarr':'\u2192','sscr':'\uD835\uDCC8','Sscr':'\uD835\uDCAE','ssetmn':'\u2216','ssmile':'\u2323','sstarf':'\u22C6','star':'\u2606','Star':'\u22C6','starf':'\u2605','straightepsilon':'\u03F5','straightphi':'\u03D5','strns':'\xAF','sub':'\u2282','Sub':'\u22D0','subdot':'\u2ABD','sube':'\u2286','subE':'\u2AC5','subedot':'\u2AC3','submult':'\u2AC1','subne':'\u228A','subnE':'\u2ACB','subplus':'\u2ABF','subrarr':'\u2979','subset':'\u2282','Subset':'\u22D0','subseteq':'\u2286','subseteqq':'\u2AC5','SubsetEqual':'\u2286','subsetneq':'\u228A','subsetneqq':'\u2ACB','subsim':'\u2AC7','subsub':'\u2AD5','subsup':'\u2AD3','succ':'\u227B','succapprox':'\u2AB8','succcurlyeq':'\u227D','Succeeds':'\u227B','SucceedsEqual':'\u2AB0','SucceedsSlantEqual':'\u227D','SucceedsTilde':'\u227F','succeq':'\u2AB0','succnapprox':'\u2ABA','succneqq':'\u2AB6','succnsim':'\u22E9','succsim':'\u227F','SuchThat':'\u220B','sum':'\u2211','Sum':'\u2211','sung':'\u266A','sup':'\u2283','Sup':'\u22D1','sup1':'\xB9','sup2':'\xB2','sup3':'\xB3','supdot':'\u2ABE','supdsub':'\u2AD8','supe':'\u2287','supE':'\u2AC6','supedot':'\u2AC4','Superset':'\u2283','SupersetEqual':'\u2287','suphsol':'\u27C9','suphsub':'\u2AD7','suplarr':'\u297B','supmult':'\u2AC2','supne':'\u228B','supnE':'\u2ACC','supplus':'\u2AC0','supset':'\u2283','Supset':'\u22D1','supseteq':'\u2287','supseteqq':'\u2AC6','supsetneq':'\u228B','supsetneqq':'\u2ACC','supsim':'\u2AC8','supsub':'\u2AD4','supsup':'\u2AD6','swarhk':'\u2926','swarr':'\u2199','swArr':'\u21D9','swarrow':'\u2199','swnwar':'\u292A','szlig':'\xDF','Tab':'\t','target':'\u2316','tau':'\u03C4','Tau':'\u03A4','tbrk':'\u23B4','tcaron':'\u0165','Tcaron':'\u0164','tcedil':'\u0163','Tcedil':'\u0162','tcy':'\u0442','Tcy':'\u0422','tdot':'\u20DB','telrec':'\u2315','tfr':'\uD835\uDD31','Tfr':'\uD835\uDD17','there4':'\u2234','therefore':'\u2234','Therefore':'\u2234','theta':'\u03B8','Theta':'\u0398','thetasym':'\u03D1','thetav':'\u03D1','thickapprox':'\u2248','thicksim':'\u223C','ThickSpace':'\u205F\u200A','thinsp':'\u2009','ThinSpace':'\u2009','thkap':'\u2248','thksim':'\u223C','thorn':'\xFE','THORN':'\xDE','tilde':'\u02DC','Tilde':'\u223C','TildeEqual':'\u2243','TildeFullEqual':'\u2245','TildeTilde':'\u2248','times':'\xD7','timesb':'\u22A0','timesbar':'\u2A31','timesd':'\u2A30','tint':'\u222D','toea':'\u2928','top':'\u22A4','topbot':'\u2336','topcir':'\u2AF1','topf':'\uD835\uDD65','Topf':'\uD835\uDD4B','topfork':'\u2ADA','tosa':'\u2929','tprime':'\u2034','trade':'\u2122','TRADE':'\u2122','triangle':'\u25B5','triangledown':'\u25BF','triangleleft':'\u25C3','trianglelefteq':'\u22B4','triangleq':'\u225C','triangleright':'\u25B9','trianglerighteq':'\u22B5','tridot':'\u25EC','trie':'\u225C','triminus':'\u2A3A','TripleDot':'\u20DB','triplus':'\u2A39','trisb':'\u29CD','tritime':'\u2A3B','trpezium':'\u23E2','tscr':'\uD835\uDCC9','Tscr':'\uD835\uDCAF','tscy':'\u0446','TScy':'\u0426','tshcy':'\u045B','TSHcy':'\u040B','tstrok':'\u0167','Tstrok':'\u0166','twixt':'\u226C','twoheadleftarrow':'\u219E','twoheadrightarrow':'\u21A0','uacute':'\xFA','Uacute':'\xDA','uarr':'\u2191','uArr':'\u21D1','Uarr':'\u219F','Uarrocir':'\u2949','ubrcy':'\u045E','Ubrcy':'\u040E','ubreve':'\u016D','Ubreve':'\u016C','ucirc':'\xFB','Ucirc':'\xDB','ucy':'\u0443','Ucy':'\u0423','udarr':'\u21C5','udblac':'\u0171','Udblac':'\u0170','udhar':'\u296E','ufisht':'\u297E','ufr':'\uD835\uDD32','Ufr':'\uD835\uDD18','ugrave':'\xF9','Ugrave':'\xD9','uHar':'\u2963','uharl':'\u21BF','uharr':'\u21BE','uhblk':'\u2580','ulcorn':'\u231C','ulcorner':'\u231C','ulcrop':'\u230F','ultri':'\u25F8','umacr':'\u016B','Umacr':'\u016A','uml':'\xA8','UnderBar':'_','UnderBrace':'\u23DF','UnderBracket':'\u23B5','UnderParenthesis':'\u23DD','Union':'\u22C3','UnionPlus':'\u228E','uogon':'\u0173','Uogon':'\u0172','uopf':'\uD835\uDD66','Uopf':'\uD835\uDD4C','uparrow':'\u2191','Uparrow':'\u21D1','UpArrow':'\u2191','UpArrowBar':'\u2912','UpArrowDownArrow':'\u21C5','updownarrow':'\u2195','Updownarrow':'\u21D5','UpDownArrow':'\u2195','UpEquilibrium':'\u296E','upharpoonleft':'\u21BF','upharpoonright':'\u21BE','uplus':'\u228E','UpperLeftArrow':'\u2196','UpperRightArrow':'\u2197','upsi':'\u03C5','Upsi':'\u03D2','upsih':'\u03D2','upsilon':'\u03C5','Upsilon':'\u03A5','UpTee':'\u22A5','UpTeeArrow':'\u21A5','upuparrows':'\u21C8','urcorn':'\u231D','urcorner':'\u231D','urcrop':'\u230E','uring':'\u016F','Uring':'\u016E','urtri':'\u25F9','uscr':'\uD835\uDCCA','Uscr':'\uD835\uDCB0','utdot':'\u22F0','utilde':'\u0169','Utilde':'\u0168','utri':'\u25B5','utrif':'\u25B4','uuarr':'\u21C8','uuml':'\xFC','Uuml':'\xDC','uwangle':'\u29A7','vangrt':'\u299C','varepsilon':'\u03F5','varkappa':'\u03F0','varnothing':'\u2205','varphi':'\u03D5','varpi':'\u03D6','varpropto':'\u221D','varr':'\u2195','vArr':'\u21D5','varrho':'\u03F1','varsigma':'\u03C2','varsubsetneq':'\u228A\uFE00','varsubsetneqq':'\u2ACB\uFE00','varsupsetneq':'\u228B\uFE00','varsupsetneqq':'\u2ACC\uFE00','vartheta':'\u03D1','vartriangleleft':'\u22B2','vartriangleright':'\u22B3','vBar':'\u2AE8','Vbar':'\u2AEB','vBarv':'\u2AE9','vcy':'\u0432','Vcy':'\u0412','vdash':'\u22A2','vDash':'\u22A8','Vdash':'\u22A9','VDash':'\u22AB','Vdashl':'\u2AE6','vee':'\u2228','Vee':'\u22C1','veebar':'\u22BB','veeeq':'\u225A','vellip':'\u22EE','verbar':'|','Verbar':'\u2016','vert':'|','Vert':'\u2016','VerticalBar':'\u2223','VerticalLine':'|','VerticalSeparator':'\u2758','VerticalTilde':'\u2240','VeryThinSpace':'\u200A','vfr':'\uD835\uDD33','Vfr':'\uD835\uDD19','vltri':'\u22B2','vnsub':'\u2282\u20D2','vnsup':'\u2283\u20D2','vopf':'\uD835\uDD67','Vopf':'\uD835\uDD4D','vprop':'\u221D','vrtri':'\u22B3','vscr':'\uD835\uDCCB','Vscr':'\uD835\uDCB1','vsubne':'\u228A\uFE00','vsubnE':'\u2ACB\uFE00','vsupne':'\u228B\uFE00','vsupnE':'\u2ACC\uFE00','Vvdash':'\u22AA','vzigzag':'\u299A','wcirc':'\u0175','Wcirc':'\u0174','wedbar':'\u2A5F','wedge':'\u2227','Wedge':'\u22C0','wedgeq':'\u2259','weierp':'\u2118','wfr':'\uD835\uDD34','Wfr':'\uD835\uDD1A','wopf':'\uD835\uDD68','Wopf':'\uD835\uDD4E','wp':'\u2118','wr':'\u2240','wreath':'\u2240','wscr':'\uD835\uDCCC','Wscr':'\uD835\uDCB2','xcap':'\u22C2','xcirc':'\u25EF','xcup':'\u22C3','xdtri':'\u25BD','xfr':'\uD835\uDD35','Xfr':'\uD835\uDD1B','xharr':'\u27F7','xhArr':'\u27FA','xi':'\u03BE','Xi':'\u039E','xlarr':'\u27F5','xlArr':'\u27F8','xmap':'\u27FC','xnis':'\u22FB','xodot':'\u2A00','xopf':'\uD835\uDD69','Xopf':'\uD835\uDD4F','xoplus':'\u2A01','xotime':'\u2A02','xrarr':'\u27F6','xrArr':'\u27F9','xscr':'\uD835\uDCCD','Xscr':'\uD835\uDCB3','xsqcup':'\u2A06','xuplus':'\u2A04','xutri':'\u25B3','xvee':'\u22C1','xwedge':'\u22C0','yacute':'\xFD','Yacute':'\xDD','yacy':'\u044F','YAcy':'\u042F','ycirc':'\u0177','Ycirc':'\u0176','ycy':'\u044B','Ycy':'\u042B','yen':'\xA5','yfr':'\uD835\uDD36','Yfr':'\uD835\uDD1C','yicy':'\u0457','YIcy':'\u0407','yopf':'\uD835\uDD6A','Yopf':'\uD835\uDD50','yscr':'\uD835\uDCCE','Yscr':'\uD835\uDCB4','yucy':'\u044E','YUcy':'\u042E','yuml':'\xFF','Yuml':'\u0178','zacute':'\u017A','Zacute':'\u0179','zcaron':'\u017E','Zcaron':'\u017D','zcy':'\u0437','Zcy':'\u0417','zdot':'\u017C','Zdot':'\u017B','zeetrf':'\u2128','ZeroWidthSpace':'\u200B','zeta':'\u03B6','Zeta':'\u0396','zfr':'\uD835\uDD37','Zfr':'\u2128','zhcy':'\u0436','ZHcy':'\u0416','zigrarr':'\u21DD','zopf':'\uD835\uDD6B','Zopf':'\u2124','zscr':'\uD835\uDCCF','Zscr':'\uD835\uDCB5','zwj':'\u200D','zwnj':'\u200C'}; + var decodeMapLegacy = {'aacute':'\xE1','Aacute':'\xC1','acirc':'\xE2','Acirc':'\xC2','acute':'\xB4','aelig':'\xE6','AElig':'\xC6','agrave':'\xE0','Agrave':'\xC0','amp':'&','AMP':'&','aring':'\xE5','Aring':'\xC5','atilde':'\xE3','Atilde':'\xC3','auml':'\xE4','Auml':'\xC4','brvbar':'\xA6','ccedil':'\xE7','Ccedil':'\xC7','cedil':'\xB8','cent':'\xA2','copy':'\xA9','COPY':'\xA9','curren':'\xA4','deg':'\xB0','divide':'\xF7','eacute':'\xE9','Eacute':'\xC9','ecirc':'\xEA','Ecirc':'\xCA','egrave':'\xE8','Egrave':'\xC8','eth':'\xF0','ETH':'\xD0','euml':'\xEB','Euml':'\xCB','frac12':'\xBD','frac14':'\xBC','frac34':'\xBE','gt':'>','GT':'>','iacute':'\xED','Iacute':'\xCD','icirc':'\xEE','Icirc':'\xCE','iexcl':'\xA1','igrave':'\xEC','Igrave':'\xCC','iquest':'\xBF','iuml':'\xEF','Iuml':'\xCF','laquo':'\xAB','lt':'<','LT':'<','macr':'\xAF','micro':'\xB5','middot':'\xB7','nbsp':'\xA0','not':'\xAC','ntilde':'\xF1','Ntilde':'\xD1','oacute':'\xF3','Oacute':'\xD3','ocirc':'\xF4','Ocirc':'\xD4','ograve':'\xF2','Ograve':'\xD2','ordf':'\xAA','ordm':'\xBA','oslash':'\xF8','Oslash':'\xD8','otilde':'\xF5','Otilde':'\xD5','ouml':'\xF6','Ouml':'\xD6','para':'\xB6','plusmn':'\xB1','pound':'\xA3','quot':'"','QUOT':'"','raquo':'\xBB','reg':'\xAE','REG':'\xAE','sect':'\xA7','shy':'\xAD','sup1':'\xB9','sup2':'\xB2','sup3':'\xB3','szlig':'\xDF','thorn':'\xFE','THORN':'\xDE','times':'\xD7','uacute':'\xFA','Uacute':'\xDA','ucirc':'\xFB','Ucirc':'\xDB','ugrave':'\xF9','Ugrave':'\xD9','uml':'\xA8','uuml':'\xFC','Uuml':'\xDC','yacute':'\xFD','Yacute':'\xDD','yen':'\xA5','yuml':'\xFF'}; + var decodeMapNumeric = {'0':'\uFFFD','128':'\u20AC','130':'\u201A','131':'\u0192','132':'\u201E','133':'\u2026','134':'\u2020','135':'\u2021','136':'\u02C6','137':'\u2030','138':'\u0160','139':'\u2039','140':'\u0152','142':'\u017D','145':'\u2018','146':'\u2019','147':'\u201C','148':'\u201D','149':'\u2022','150':'\u2013','151':'\u2014','152':'\u02DC','153':'\u2122','154':'\u0161','155':'\u203A','156':'\u0153','158':'\u017E','159':'\u0178'}; + var invalidReferenceCodePoints = [1,2,3,4,5,6,7,8,11,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,64976,64977,64978,64979,64980,64981,64982,64983,64984,64985,64986,64987,64988,64989,64990,64991,64992,64993,64994,64995,64996,64997,64998,64999,65000,65001,65002,65003,65004,65005,65006,65007,65534,65535,131070,131071,196606,196607,262142,262143,327678,327679,393214,393215,458750,458751,524286,524287,589822,589823,655358,655359,720894,720895,786430,786431,851966,851967,917502,917503,983038,983039,1048574,1048575,1114110,1114111]; + + /*--------------------------------------------------------------------------*/ + + var stringFromCharCode = String.fromCharCode; + + var object = {}; + var hasOwnProperty = object.hasOwnProperty; + var has = function(object, propertyName) { + return hasOwnProperty.call(object, propertyName); + }; + + var contains = function(array, value) { + var index = -1; + var length = array.length; + while (++index < length) { + if (array[index] == value) { + return true; + } + } + return false; + }; + + var merge = function(options, defaults) { + if (!options) { + return defaults; + } + var result = {}; + var key; + for (key in defaults) { + // A `hasOwnProperty` check is not needed here, since only recognized + // option names are used anyway. Any others are ignored. + result[key] = has(options, key) ? options[key] : defaults[key]; + } + return result; + }; + + // Modified version of `ucs2encode`; see https://mths.be/punycode. + var codePointToSymbol = function(codePoint, strict) { + var output = ''; + if ((codePoint >= 0xD800 && codePoint <= 0xDFFF) || codePoint > 0x10FFFF) { + // See issue #4: + // “Otherwise, if the number is in the range 0xD800 to 0xDFFF or is + // greater than 0x10FFFF, then this is a parse error. Return a U+FFFD + // REPLACEMENT CHARACTER.” + if (strict) { + parseError('character reference outside the permissible Unicode range'); + } + return '\uFFFD'; + } + if (has(decodeMapNumeric, codePoint)) { + if (strict) { + parseError('disallowed character reference'); + } + return decodeMapNumeric[codePoint]; + } + if (strict && contains(invalidReferenceCodePoints, codePoint)) { + parseError('disallowed character reference'); + } + if (codePoint > 0xFFFF) { + codePoint -= 0x10000; + output += stringFromCharCode(codePoint >>> 10 & 0x3FF | 0xD800); + codePoint = 0xDC00 | codePoint & 0x3FF; + } + output += stringFromCharCode(codePoint); + return output; + }; + + var hexEscape = function(codePoint) { + return '&#x' + codePoint.toString(16).toUpperCase() + ';'; + }; + + var decEscape = function(codePoint) { + return '&#' + codePoint + ';'; + }; + + var parseError = function(message) { + throw Error('Parse error: ' + message); + }; + + /*--------------------------------------------------------------------------*/ + + var encode = function(string, options) { + options = merge(options, encode.options); + var strict = options.strict; + if (strict && regexInvalidRawCodePoint.test(string)) { + parseError('forbidden code point'); + } + var encodeEverything = options.encodeEverything; + var useNamedReferences = options.useNamedReferences; + var allowUnsafeSymbols = options.allowUnsafeSymbols; + var escapeCodePoint = options.decimal ? decEscape : hexEscape; + + var escapeBmpSymbol = function(symbol) { + return escapeCodePoint(symbol.charCodeAt(0)); + }; + + if (encodeEverything) { + // Encode ASCII symbols. + string = string.replace(regexAsciiWhitelist, function(symbol) { + // Use named references if requested & possible. + if (useNamedReferences && has(encodeMap, symbol)) { + return '&' + encodeMap[symbol] + ';'; + } + return escapeBmpSymbol(symbol); + }); + // Shorten a few escapes that represent two symbols, of which at least one + // is within the ASCII range. + if (useNamedReferences) { + string = string + .replace(/>\u20D2/g, '>⃒') + .replace(/<\u20D2/g, '<⃒') + .replace(/fj/g, 'fj'); + } + // Encode non-ASCII symbols. + if (useNamedReferences) { + // Encode non-ASCII symbols that can be replaced with a named reference. + string = string.replace(regexEncodeNonAscii, function(string) { + // Note: there is no need to check `has(encodeMap, string)` here. + return '&' + encodeMap[string] + ';'; + }); + } + // Note: any remaining non-ASCII symbols are handled outside of the `if`. + } else if (useNamedReferences) { + // Apply named character references. + // Encode `<>"'&` using named character references. + if (!allowUnsafeSymbols) { + string = string.replace(regexEscape, function(string) { + return '&' + encodeMap[string] + ';'; // no need to check `has()` here + }); + } + // Shorten escapes that represent two symbols, of which at least one is + // `<>"'&`. + string = string + .replace(/>\u20D2/g, '>⃒') + .replace(/<\u20D2/g, '<⃒'); + // Encode non-ASCII symbols that can be replaced with a named reference. + string = string.replace(regexEncodeNonAscii, function(string) { + // Note: there is no need to check `has(encodeMap, string)` here. + return '&' + encodeMap[string] + ';'; + }); + } else if (!allowUnsafeSymbols) { + // Encode `<>"'&` using hexadecimal escapes, now that they’re not handled + // using named character references. + string = string.replace(regexEscape, escapeBmpSymbol); + } + return string + // Encode astral symbols. + .replace(regexAstralSymbols, function($0) { + // https://mathiasbynens.be/notes/javascript-encoding#surrogate-formulae + var high = $0.charCodeAt(0); + var low = $0.charCodeAt(1); + var codePoint = (high - 0xD800) * 0x400 + low - 0xDC00 + 0x10000; + return escapeCodePoint(codePoint); + }) + // Encode any remaining BMP symbols that are not printable ASCII symbols + // using a hexadecimal escape. + .replace(regexBmpWhitelist, escapeBmpSymbol); + }; + // Expose default options (so they can be overridden globally). + encode.options = { + 'allowUnsafeSymbols': false, + 'encodeEverything': false, + 'strict': false, + 'useNamedReferences': false, + 'decimal' : false + }; + + var decode = function(html, options) { + options = merge(options, decode.options); + var strict = options.strict; + if (strict && regexInvalidEntity.test(html)) { + parseError('malformed character reference'); + } + return html.replace(regexDecode, function($0, $1, $2, $3, $4, $5, $6, $7, $8) { + var codePoint; + var semicolon; + var decDigits; + var hexDigits; + var reference; + var next; + + if ($1) { + reference = $1; + // Note: there is no need to check `has(decodeMap, reference)`. + return decodeMap[reference]; + } + + if ($2) { + // Decode named character references without trailing `;`, e.g. `&`. + // This is only a parse error if it gets converted to `&`, or if it is + // followed by `=` in an attribute context. + reference = $2; + next = $3; + if (next && options.isAttributeValue) { + if (strict && next == '=') { + parseError('`&` did not start a character reference'); + } + return $0; + } else { + if (strict) { + parseError( + 'named character reference was not terminated by a semicolon' + ); + } + // Note: there is no need to check `has(decodeMapLegacy, reference)`. + return decodeMapLegacy[reference] + (next || ''); + } + } + + if ($4) { + // Decode decimal escapes, e.g. `𝌆`. + decDigits = $4; + semicolon = $5; + if (strict && !semicolon) { + parseError('character reference was not terminated by a semicolon'); + } + codePoint = parseInt(decDigits, 10); + return codePointToSymbol(codePoint, strict); + } + + if ($6) { + // Decode hexadecimal escapes, e.g. `𝌆`. + hexDigits = $6; + semicolon = $7; + if (strict && !semicolon) { + parseError('character reference was not terminated by a semicolon'); + } + codePoint = parseInt(hexDigits, 16); + return codePointToSymbol(codePoint, strict); + } + + // If we’re still here, `if ($7)` is implied; it’s an ambiguous + // ampersand for sure. https://mths.be/notes/ambiguous-ampersands + if (strict) { + parseError( + 'named character reference was not terminated by a semicolon' + ); + } + return $0; + }); + }; + // Expose default options (so they can be overridden globally). + decode.options = { + 'isAttributeValue': false, + 'strict': false + }; + + var escape = function(string) { + return string.replace(regexEscape, function($0) { + // Note: there is no need to check `has(escapeMap, $0)` here. + return escapeMap[$0]; + }); + }; + + /*--------------------------------------------------------------------------*/ + + var he = { + 'version': '1.2.0', + 'encode': encode, + 'decode': decode, + 'escape': escape, + 'unescape': decode + }; + + // Some AMD build optimizers, like r.js, check for specific condition patterns + // like the following: + if ( + false + ) { + define(function() { + return he; + }); + } else if (freeExports && !freeExports.nodeType) { + if (freeModule) { // in Node.js, io.js, or RingoJS v0.8.0+ + freeModule.exports = he; + } else { // in Narwhal or RingoJS v0.7.0- + for (var key in he) { + has(he, key) && (freeExports[key] = he[key]); + } + } + } else { // in Rhino or a web browser + root.he = he; + } + +}(this)); + +}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{}],55:[function(require,module,exports){ exports.read = function (buffer, offset, isLE, mLen, nBytes) { var e, m - var eLen = nBytes * 8 - mLen - 1 + var eLen = (nBytes * 8) - mLen - 1 var eMax = (1 << eLen) - 1 var eBias = eMax >> 1 var nBits = -7 @@ -9936,12 +13612,12 @@ e = s & ((1 << (-nBits)) - 1) s >>= (-nBits) nBits += eLen - for (; nBits > 0; e = e * 256 + buffer[offset + i], i += d, nBits -= 8) {} + for (; nBits > 0; e = (e * 256) + buffer[offset + i], i += d, nBits -= 8) {} m = e & ((1 << (-nBits)) - 1) e >>= (-nBits) nBits += mLen - for (; nBits > 0; m = m * 256 + buffer[offset + i], i += d, nBits -= 8) {} + for (; nBits > 0; m = (m * 256) + buffer[offset + i], i += d, nBits -= 8) {} if (e === 0) { e = 1 - eBias @@ -9956,7 +13632,7 @@ exports.write = function (buffer, value, offset, isLE, mLen, nBytes) { var e, m, c - var eLen = nBytes * 8 - mLen - 1 + var eLen = (nBytes * 8) - mLen - 1 var eMax = (1 << eLen) - 1 var eBias = eMax >> 1 var rt = (mLen === 23 ? Math.pow(2, -24) - Math.pow(2, -77) : 0) @@ -9989,7 +13665,7 @@ m = 0 e = eMax } else if (e + eBias >= 1) { - m = (value * c - 1) * Math.pow(2, mLen) + m = ((value * c) - 1) * Math.pow(2, mLen) e = e + eBias } else { m = value * Math.pow(2, eBias - 1) * Math.pow(2, mLen) @@ -10006,7 +13682,7 @@ buffer[offset + i - d] |= s * 128 } -},{}],53:[function(require,module,exports){ +},{}],56:[function(require,module,exports){ if (typeof Object.create === 'function') { // implementation from standard node.js 'util' module module.exports = function inherits(ctor, superCtor) { @@ -10031,26 +13707,37 @@ } } -},{}],54:[function(require,module,exports){ -/** - * Determine if an object is Buffer +},{}],57:[function(require,module,exports){ +/*! + * Determine if an object is a Buffer * - * Author: Feross Aboukhadijeh <feross@feross.org> <http://feross.org> - * License: MIT - * - * `npm install is-buffer` + * @author Feross Aboukhadijeh <https://feross.org> + * @license MIT */ +// The _isBuffer check is for Safari 5-7 support, because it's missing +// Object.prototype.constructor. Remove this eventually module.exports = function (obj) { - return !!(obj != null && - (obj._isBuffer || // For Safari 5-7 (missing Object.prototype.constructor) - (obj.constructor && - typeof obj.constructor.isBuffer === 'function' && - obj.constructor.isBuffer(obj)) - )) + return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer) } -},{}],55:[function(require,module,exports){ +function isBuffer (obj) { + return !!obj.constructor && typeof obj.constructor.isBuffer === 'function' && obj.constructor.isBuffer(obj) +} + +// For Node v0.10 support. Remove this eventually. +function isSlowBuffer (obj) { + return typeof obj.readFloatLE === 'function' && typeof obj.slice === 'function' && isBuffer(obj.slice(0, 0)) +} + +},{}],58:[function(require,module,exports){ +var toString = {}.toString; + +module.exports = Array.isArray || function (arr) { + return toString.call(arr) == '[object Array]'; +}; + +},{}],59:[function(require,module,exports){ (function (process){ var path = require('path'); var fs = require('fs'); @@ -10152,63 +13839,486 @@ }; }).call(this,require('_process')) -},{"_process":58,"fs":43,"path":43}],56:[function(require,module,exports){ -exports.endianness = function () { return 'LE' }; +},{"_process":69,"fs":42,"path":42}],60:[function(require,module,exports){ +/** + * Helpers. + */ -exports.hostname = function () { - if (typeof location !== 'undefined') { - return location.hostname - } - else return ''; +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var w = d * 7; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} [options] + * @throws {Error} throw an error if val is not a non-empty string or a number + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options) { + options = options || {}; + var type = typeof val; + if (type === 'string' && val.length > 0) { + return parse(val); + } else if (type === 'number' && isNaN(val) === false) { + return options.long ? fmtLong(val) : fmtShort(val); + } + throw new Error( + 'val is not a non-empty string or a valid number. val=' + + JSON.stringify(val) + ); }; -exports.loadavg = function () { return [] }; +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ -exports.uptime = function () { return 0 }; +function parse(str) { + str = String(str); + if (str.length > 100) { + return; + } + var match = /^((?:\d+)?\-?\d?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)?$/i.exec( + str + ); + if (!match) { + return; + } + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'yrs': + case 'yr': + case 'y': + return n * y; + case 'weeks': + case 'week': + case 'w': + return n * w; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'hrs': + case 'hr': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'mins': + case 'min': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 'secs': + case 'sec': + case 's': + return n * s; + case 'milliseconds': + case 'millisecond': + case 'msecs': + case 'msec': + case 'ms': + return n; + default: + return undefined; + } +} -exports.freemem = function () { - return Number.MAX_VALUE; +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtShort(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return Math.round(ms / d) + 'd'; + } + if (msAbs >= h) { + return Math.round(ms / h) + 'h'; + } + if (msAbs >= m) { + return Math.round(ms / m) + 'm'; + } + if (msAbs >= s) { + return Math.round(ms / s) + 's'; + } + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function fmtLong(ms) { + var msAbs = Math.abs(ms); + if (msAbs >= d) { + return plural(ms, msAbs, d, 'day'); + } + if (msAbs >= h) { + return plural(ms, msAbs, h, 'hour'); + } + if (msAbs >= m) { + return plural(ms, msAbs, m, 'minute'); + } + if (msAbs >= s) { + return plural(ms, msAbs, s, 'second'); + } + return ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, msAbs, n, name) { + var isPlural = msAbs >= n * 1.5; + return Math.round(ms / n) + ' ' + name + (isPlural ? 's' : ''); +} + +},{}],61:[function(require,module,exports){ +'use strict'; + +var keysShim; +if (!Object.keys) { + // modified from https://github.com/es-shims/es5-shim + var has = Object.prototype.hasOwnProperty; + var toStr = Object.prototype.toString; + var isArgs = require('./isArguments'); // eslint-disable-line global-require + var isEnumerable = Object.prototype.propertyIsEnumerable; + var hasDontEnumBug = !isEnumerable.call({ toString: null }, 'toString'); + var hasProtoEnumBug = isEnumerable.call(function () {}, 'prototype'); + var dontEnums = [ + 'toString', + 'toLocaleString', + 'valueOf', + 'hasOwnProperty', + 'isPrototypeOf', + 'propertyIsEnumerable', + 'constructor' + ]; + var equalsConstructorPrototype = function (o) { + var ctor = o.constructor; + return ctor && ctor.prototype === o; + }; + var excludedKeys = { + $applicationCache: true, + $console: true, + $external: true, + $frame: true, + $frameElement: true, + $frames: true, + $innerHeight: true, + $innerWidth: true, + $outerHeight: true, + $outerWidth: true, + $pageXOffset: true, + $pageYOffset: true, + $parent: true, + $scrollLeft: true, + $scrollTop: true, + $scrollX: true, + $scrollY: true, + $self: true, + $webkitIndexedDB: true, + $webkitStorageInfo: true, + $window: true + }; + var hasAutomationEqualityBug = (function () { + /* global window */ + if (typeof window === 'undefined') { return false; } + for (var k in window) { + try { + if (!excludedKeys['$' + k] && has.call(window, k) && window[k] !== null && typeof window[k] === 'object') { + try { + equalsConstructorPrototype(window[k]); + } catch (e) { + return true; + } + } + } catch (e) { + return true; + } + } + return false; + }()); + var equalsConstructorPrototypeIfNotBuggy = function (o) { + /* global window */ + if (typeof window === 'undefined' || !hasAutomationEqualityBug) { + return equalsConstructorPrototype(o); + } + try { + return equalsConstructorPrototype(o); + } catch (e) { + return false; + } + }; + + keysShim = function keys(object) { + var isObject = object !== null && typeof object === 'object'; + var isFunction = toStr.call(object) === '[object Function]'; + var isArguments = isArgs(object); + var isString = isObject && toStr.call(object) === '[object String]'; + var theKeys = []; + + if (!isObject && !isFunction && !isArguments) { + throw new TypeError('Object.keys called on a non-object'); + } + + var skipProto = hasProtoEnumBug && isFunction; + if (isString && object.length > 0 && !has.call(object, 0)) { + for (var i = 0; i < object.length; ++i) { + theKeys.push(String(i)); + } + } + + if (isArguments && object.length > 0) { + for (var j = 0; j < object.length; ++j) { + theKeys.push(String(j)); + } + } else { + for (var name in object) { + if (!(skipProto && name === 'prototype') && has.call(object, name)) { + theKeys.push(String(name)); + } + } + } + + if (hasDontEnumBug) { + var skipConstructor = equalsConstructorPrototypeIfNotBuggy(object); + + for (var k = 0; k < dontEnums.length; ++k) { + if (!(skipConstructor && dontEnums[k] === 'constructor') && has.call(object, dontEnums[k])) { + theKeys.push(dontEnums[k]); + } + } + } + return theKeys; + }; +} +module.exports = keysShim; + +},{"./isArguments":63}],62:[function(require,module,exports){ +'use strict'; + +var slice = Array.prototype.slice; +var isArgs = require('./isArguments'); + +var origKeys = Object.keys; +var keysShim = origKeys ? function keys(o) { return origKeys(o); } : require('./implementation'); + +var originalKeys = Object.keys; + +keysShim.shim = function shimObjectKeys() { + if (Object.keys) { + var keysWorksWithArguments = (function () { + // Safari 5.0 bug + var args = Object.keys(arguments); + return args && args.length === arguments.length; + }(1, 2)); + if (!keysWorksWithArguments) { + Object.keys = function keys(object) { // eslint-disable-line func-name-matching + if (isArgs(object)) { + return originalKeys(slice.call(object)); + } + return originalKeys(object); + }; + } + } else { + Object.keys = keysShim; + } + return Object.keys || keysShim; }; -exports.totalmem = function () { - return Number.MAX_VALUE; +module.exports = keysShim; + +},{"./implementation":61,"./isArguments":63}],63:[function(require,module,exports){ +'use strict'; + +var toStr = Object.prototype.toString; + +module.exports = function isArguments(value) { + var str = toStr.call(value); + var isArgs = str === '[object Arguments]'; + if (!isArgs) { + isArgs = str !== '[object Array]' && + value !== null && + typeof value === 'object' && + typeof value.length === 'number' && + value.length >= 0 && + toStr.call(value.callee) === '[object Function]'; + } + return isArgs; }; -exports.cpus = function () { return [] }; +},{}],64:[function(require,module,exports){ +'use strict'; -exports.type = function () { return 'Browser' }; +// modified from https://github.com/es-shims/es6-shim +var keys = require('object-keys'); +var bind = require('function-bind'); +var canBeObject = function (obj) { + return typeof obj !== 'undefined' && obj !== null; +}; +var hasSymbols = require('has-symbols/shams')(); +var toObject = Object; +var push = bind.call(Function.call, Array.prototype.push); +var propIsEnumerable = bind.call(Function.call, Object.prototype.propertyIsEnumerable); +var originalGetSymbols = hasSymbols ? Object.getOwnPropertySymbols : null; -exports.release = function () { - if (typeof navigator !== 'undefined') { - return navigator.appVersion; - } - return ''; +module.exports = function assign(target, source1) { + if (!canBeObject(target)) { throw new TypeError('target must be an object'); } + var objTarget = toObject(target); + var s, source, i, props, syms, value, key; + for (s = 1; s < arguments.length; ++s) { + source = toObject(arguments[s]); + props = keys(source); + var getSymbols = hasSymbols && (Object.getOwnPropertySymbols || originalGetSymbols); + if (getSymbols) { + syms = getSymbols(source); + for (i = 0; i < syms.length; ++i) { + key = syms[i]; + if (propIsEnumerable(source, key)) { + push(props, key); + } + } + } + for (i = 0; i < props.length; ++i) { + key = props[i]; + value = source[key]; + if (propIsEnumerable(source, key)) { + objTarget[key] = value; + } + } + } + return objTarget; }; -exports.networkInterfaces -= exports.getNetworkInterfaces -= function () { return {} }; +},{"function-bind":52,"has-symbols/shams":53,"object-keys":62}],65:[function(require,module,exports){ +'use strict'; -exports.arch = function () { return 'javascript' }; +var defineProperties = require('define-properties'); -exports.platform = function () { return 'browser' }; +var implementation = require('./implementation'); +var getPolyfill = require('./polyfill'); +var shim = require('./shim'); -exports.tmpdir = exports.tmpDir = function () { - return '/tmp'; +var polyfill = getPolyfill(); + +defineProperties(polyfill, { + getPolyfill: getPolyfill, + implementation: implementation, + shim: shim +}); + +module.exports = polyfill; + +},{"./implementation":64,"./polyfill":66,"./shim":67,"define-properties":47}],66:[function(require,module,exports){ +'use strict'; + +var implementation = require('./implementation'); + +var lacksProperEnumerationOrder = function () { + if (!Object.assign) { + return false; + } + // v8, specifically in node 4.x, has a bug with incorrect property enumeration order + // note: this does not detect the bug unless there's 20 characters + var str = 'abcdefghijklmnopqrst'; + var letters = str.split(''); + var map = {}; + for (var i = 0; i < letters.length; ++i) { + map[letters[i]] = letters[i]; + } + var obj = Object.assign({}, map); + var actual = ''; + for (var k in obj) { + actual += k; + } + return str !== actual; }; -exports.EOL = '\n'; +var assignHasPendingExceptions = function () { + if (!Object.assign || !Object.preventExtensions) { + return false; + } + // Firefox 37 still has "pending exception" logic in its Object.assign implementation, + // which is 72% slower than our shim, and Firefox 40's native implementation. + var thrower = Object.preventExtensions({ 1: 2 }); + try { + Object.assign(thrower, 'xy'); + } catch (e) { + return thrower[1] === 'y'; + } + return false; +}; -},{}],57:[function(require,module,exports){ +module.exports = function getPolyfill() { + if (!Object.assign) { + return implementation; + } + if (lacksProperEnumerationOrder()) { + return implementation; + } + if (assignHasPendingExceptions()) { + return implementation; + } + return Object.assign; +}; + +},{"./implementation":64}],67:[function(require,module,exports){ +'use strict'; + +var define = require('define-properties'); +var getPolyfill = require('./polyfill'); + +module.exports = function shimAssign() { + var polyfill = getPolyfill(); + define( + Object, + { assign: polyfill }, + { assign: function () { return Object.assign !== polyfill; } } + ); + return polyfill; +}; + +},{"./polyfill":66,"define-properties":47}],68:[function(require,module,exports){ (function (process){ 'use strict'; if (!process.version || process.version.indexOf('v0.') === 0 || process.version.indexOf('v1.') === 0 && process.version.indexOf('v1.8.') !== 0) { - module.exports = nextTick; + module.exports = { nextTick: nextTick }; } else { - module.exports = process.nextTick; + module.exports = process } function nextTick(fn, arg1, arg2, arg3) { @@ -10245,11 +14355,98 @@ } } -}).call(this,require('_process')) -},{"_process":58}],58:[function(require,module,exports){ -// shim for using process in browser +}).call(this,require('_process')) +},{"_process":69}],69:[function(require,module,exports){ +// shim for using process in browser var process = module.exports = {}; + +// cached from whatever global is present so that test runners that stub it +// don't break things. But we need to wrap it in a try catch in case it is +// wrapped in strict mode code which doesn't define any globals. It's inside a +// function because try/catches deoptimize in certain engines. + +var cachedSetTimeout; +var cachedClearTimeout; + +function defaultSetTimout() { + throw new Error('setTimeout has not been defined'); +} +function defaultClearTimeout () { + throw new Error('clearTimeout has not been defined'); +} +(function () { + try { + if (typeof setTimeout === 'function') { + cachedSetTimeout = setTimeout; + } else { + cachedSetTimeout = defaultSetTimout; + } + } catch (e) { + cachedSetTimeout = defaultSetTimout; + } + try { + if (typeof clearTimeout === 'function') { + cachedClearTimeout = clearTimeout; + } else { + cachedClearTimeout = defaultClearTimeout; + } + } catch (e) { + cachedClearTimeout = defaultClearTimeout; + } +} ()) +function runTimeout(fun) { + if (cachedSetTimeout === setTimeout) { + //normal enviroments in sane situations + return setTimeout(fun, 0); + } + // if setTimeout wasn't available but was latter defined + if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { + cachedSetTimeout = setTimeout; + return setTimeout(fun, 0); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedSetTimeout(fun, 0); + } catch(e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedSetTimeout.call(null, fun, 0); + } catch(e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error + return cachedSetTimeout.call(this, fun, 0); + } + } + + +} +function runClearTimeout(marker) { + if (cachedClearTimeout === clearTimeout) { + //normal enviroments in sane situations + return clearTimeout(marker); + } + // if clearTimeout wasn't available but was latter defined + if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { + cachedClearTimeout = clearTimeout; + return clearTimeout(marker); + } + try { + // when when somebody has screwed with setTimeout but no I.E. maddness + return cachedClearTimeout(marker); + } catch (e){ + try { + // When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally + return cachedClearTimeout.call(null, marker); + } catch (e){ + // same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. + // Some versions of I.E. have different rules for clearTimeout vs setTimeout + return cachedClearTimeout.call(this, marker); + } + } + + + +} var queue = []; var draining = false; var currentQueue; @@ -10274,7 +14471,7 @@ if (draining) { return; } - var timeout = setTimeout(cleanUpNextTick); + var timeout = runTimeout(cleanUpNextTick); draining = true; var len = queue.length; @@ -10291,7 +14488,7 @@ } currentQueue = null; draining = false; - clearTimeout(timeout); + runClearTimeout(timeout); } process.nextTick = function (fun) { @@ -10303,7 +14500,7 @@ } queue.push(new Item(fun, args)); if (queue.length === 1 && !draining) { - setTimeout(drainQueue, 0); + runTimeout(drainQueue); } }; @@ -10331,6 +14528,10 @@ process.removeListener = noop; process.removeAllListeners = noop; process.emit = noop; +process.prependListener = noop; +process.prependOnceListener = noop; + +process.listeners = function (name) { return [] } process.binding = function (name) { throw new Error('process.binding is not supported'); @@ -10342,7 +14543,2357 @@ }; process.umask = function() { return 0; }; -},{}],59:[function(require,module,exports){ +},{}],70:[function(require,module,exports){ +module.exports = require('./lib/_stream_duplex.js'); + +},{"./lib/_stream_duplex.js":71}],71:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// a duplex stream is just a stream that is both readable and writable. +// Since JS doesn't have multiple prototypal inheritance, this class +// prototypally inherits from Readable, and then parasitically from +// Writable. + +'use strict'; + +/*<replacement>*/ + +var pna = require('process-nextick-args'); +/*</replacement>*/ + +/*<replacement>*/ +var objectKeys = Object.keys || function (obj) { + var keys = []; + for (var key in obj) { + keys.push(key); + }return keys; +}; +/*</replacement>*/ + +module.exports = Duplex; + +/*<replacement>*/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/*</replacement>*/ + +var Readable = require('./_stream_readable'); +var Writable = require('./_stream_writable'); + +util.inherits(Duplex, Readable); + +{ + // avoid scope creep, the keys array can then be collected + var keys = objectKeys(Writable.prototype); + for (var v = 0; v < keys.length; v++) { + var method = keys[v]; + if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; + } +} + +function Duplex(options) { + if (!(this instanceof Duplex)) return new Duplex(options); + + Readable.call(this, options); + Writable.call(this, options); + + if (options && options.readable === false) this.readable = false; + + if (options && options.writable === false) this.writable = false; + + this.allowHalfOpen = true; + if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; + + this.once('end', onend); +} + +Object.defineProperty(Duplex.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._writableState.highWaterMark; + } +}); + +// the no-half-open enforcer +function onend() { + // if we allow half-open state, or if the writable side ended, + // then we're ok. + if (this.allowHalfOpen || this._writableState.ended) return; + + // no more data can be written. + // But allow more writes to happen in this tick. + pna.nextTick(onEndNT, this); +} + +function onEndNT(self) { + self.end(); +} + +Object.defineProperty(Duplex.prototype, 'destroyed', { + get: function () { + if (this._readableState === undefined || this._writableState === undefined) { + return false; + } + return this._readableState.destroyed && this._writableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (this._readableState === undefined || this._writableState === undefined) { + return; + } + + // backward compatibility, the user is explicitly + // managing destroyed + this._readableState.destroyed = value; + this._writableState.destroyed = value; + } +}); + +Duplex.prototype._destroy = function (err, cb) { + this.push(null); + this.end(); + + pna.nextTick(cb, err); +}; +},{"./_stream_readable":73,"./_stream_writable":75,"core-util-is":44,"inherits":56,"process-nextick-args":68}],72:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// a passthrough stream. +// basically just the most minimal sort of Transform stream. +// Every written chunk gets output as-is. + +'use strict'; + +module.exports = PassThrough; + +var Transform = require('./_stream_transform'); + +/*<replacement>*/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/*</replacement>*/ + +util.inherits(PassThrough, Transform); + +function PassThrough(options) { + if (!(this instanceof PassThrough)) return new PassThrough(options); + + Transform.call(this, options); +} + +PassThrough.prototype._transform = function (chunk, encoding, cb) { + cb(null, chunk); +}; +},{"./_stream_transform":74,"core-util-is":44,"inherits":56}],73:[function(require,module,exports){ +(function (process,global){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +'use strict'; + +/*<replacement>*/ + +var pna = require('process-nextick-args'); +/*</replacement>*/ + +module.exports = Readable; + +/*<replacement>*/ +var isArray = require('isarray'); +/*</replacement>*/ + +/*<replacement>*/ +var Duplex; +/*</replacement>*/ + +Readable.ReadableState = ReadableState; + +/*<replacement>*/ +var EE = require('events').EventEmitter; + +var EElistenerCount = function (emitter, type) { + return emitter.listeners(type).length; +}; +/*</replacement>*/ + +/*<replacement>*/ +var Stream = require('./internal/streams/stream'); +/*</replacement>*/ + +/*<replacement>*/ + +var Buffer = require('safe-buffer').Buffer; +var OurUint8Array = global.Uint8Array || function () {}; +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} + +/*</replacement>*/ + +/*<replacement>*/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/*</replacement>*/ + +/*<replacement>*/ +var debugUtil = require('util'); +var debug = void 0; +if (debugUtil && debugUtil.debuglog) { + debug = debugUtil.debuglog('stream'); +} else { + debug = function () {}; +} +/*</replacement>*/ + +var BufferList = require('./internal/streams/BufferList'); +var destroyImpl = require('./internal/streams/destroy'); +var StringDecoder; + +util.inherits(Readable, Stream); + +var kProxyEvents = ['error', 'close', 'destroy', 'pause', 'resume']; + +function prependListener(emitter, event, fn) { + // Sadly this is not cacheable as some libraries bundle their own + // event emitter implementation with them. + if (typeof emitter.prependListener === 'function') return emitter.prependListener(event, fn); + + // This is a hack to make sure that our error handler is attached before any + // userland ones. NEVER DO THIS. This is here only because this code needs + // to continue to work with older versions of Node.js that do not include + // the prependListener() method. The goal is to eventually remove this hack. + if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; +} + +function ReadableState(options, stream) { + Duplex = Duplex || require('./_stream_duplex'); + + options = options || {}; + + // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. + var isDuplex = stream instanceof Duplex; + + // object stream flag. Used to make read(n) ignore n and to + // make all the buffer merging and length checks go away + this.objectMode = !!options.objectMode; + + if (isDuplex) this.objectMode = this.objectMode || !!options.readableObjectMode; + + // the point at which it stops calling _read() to fill the buffer + // Note: 0 is a valid value, means "don't call _read preemptively ever" + var hwm = options.highWaterMark; + var readableHwm = options.readableHighWaterMark; + var defaultHwm = this.objectMode ? 16 : 16 * 1024; + + if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (readableHwm || readableHwm === 0)) this.highWaterMark = readableHwm;else this.highWaterMark = defaultHwm; + + // cast to ints. + this.highWaterMark = Math.floor(this.highWaterMark); + + // A linked list is used to store data chunks instead of an array because the + // linked list can remove elements from the beginning faster than + // array.shift() + this.buffer = new BufferList(); + this.length = 0; + this.pipes = null; + this.pipesCount = 0; + this.flowing = null; + this.ended = false; + this.endEmitted = false; + this.reading = false; + + // a flag to be able to tell if the event 'readable'/'data' is emitted + // immediately, or on a later tick. We set this to true at first, because + // any actions that shouldn't happen until "later" should generally also + // not happen before the first read call. + this.sync = true; + + // whenever we return null, then we set a flag to say + // that we're awaiting a 'readable' event emission. + this.needReadable = false; + this.emittedReadable = false; + this.readableListening = false; + this.resumeScheduled = false; + + // has it been destroyed + this.destroyed = false; + + // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + this.defaultEncoding = options.defaultEncoding || 'utf8'; + + // the number of writers that are awaiting a drain event in .pipe()s + this.awaitDrain = 0; + + // if true, a maybeReadMore has been scheduled + this.readingMore = false; + + this.decoder = null; + this.encoding = null; + if (options.encoding) { + if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; + this.decoder = new StringDecoder(options.encoding); + this.encoding = options.encoding; + } +} + +function Readable(options) { + Duplex = Duplex || require('./_stream_duplex'); + + if (!(this instanceof Readable)) return new Readable(options); + + this._readableState = new ReadableState(options, this); + + // legacy + this.readable = true; + + if (options) { + if (typeof options.read === 'function') this._read = options.read; + + if (typeof options.destroy === 'function') this._destroy = options.destroy; + } + + Stream.call(this); +} + +Object.defineProperty(Readable.prototype, 'destroyed', { + get: function () { + if (this._readableState === undefined) { + return false; + } + return this._readableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._readableState) { + return; + } + + // backward compatibility, the user is explicitly + // managing destroyed + this._readableState.destroyed = value; + } +}); + +Readable.prototype.destroy = destroyImpl.destroy; +Readable.prototype._undestroy = destroyImpl.undestroy; +Readable.prototype._destroy = function (err, cb) { + this.push(null); + cb(err); +}; + +// Manually shove something into the read() buffer. +// This returns true if the highWaterMark has not been hit yet, +// similar to how Writable.write() returns true if you should +// write() some more. +Readable.prototype.push = function (chunk, encoding) { + var state = this._readableState; + var skipChunkCheck; + + if (!state.objectMode) { + if (typeof chunk === 'string') { + encoding = encoding || state.defaultEncoding; + if (encoding !== state.encoding) { + chunk = Buffer.from(chunk, encoding); + encoding = ''; + } + skipChunkCheck = true; + } + } else { + skipChunkCheck = true; + } + + return readableAddChunk(this, chunk, encoding, false, skipChunkCheck); +}; + +// Unshift should *always* be something directly out of read() +Readable.prototype.unshift = function (chunk) { + return readableAddChunk(this, chunk, null, true, false); +}; + +function readableAddChunk(stream, chunk, encoding, addToFront, skipChunkCheck) { + var state = stream._readableState; + if (chunk === null) { + state.reading = false; + onEofChunk(stream, state); + } else { + var er; + if (!skipChunkCheck) er = chunkInvalid(state, chunk); + if (er) { + stream.emit('error', er); + } else if (state.objectMode || chunk && chunk.length > 0) { + if (typeof chunk !== 'string' && !state.objectMode && Object.getPrototypeOf(chunk) !== Buffer.prototype) { + chunk = _uint8ArrayToBuffer(chunk); + } + + if (addToFront) { + if (state.endEmitted) stream.emit('error', new Error('stream.unshift() after end event'));else addChunk(stream, state, chunk, true); + } else if (state.ended) { + stream.emit('error', new Error('stream.push() after EOF')); + } else { + state.reading = false; + if (state.decoder && !encoding) { + chunk = state.decoder.write(chunk); + if (state.objectMode || chunk.length !== 0) addChunk(stream, state, chunk, false);else maybeReadMore(stream, state); + } else { + addChunk(stream, state, chunk, false); + } + } + } else if (!addToFront) { + state.reading = false; + } + } + + return needMoreData(state); +} + +function addChunk(stream, state, chunk, addToFront) { + if (state.flowing && state.length === 0 && !state.sync) { + stream.emit('data', chunk); + stream.read(0); + } else { + // update the buffer info. + state.length += state.objectMode ? 1 : chunk.length; + if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); + + if (state.needReadable) emitReadable(stream); + } + maybeReadMore(stream, state); +} + +function chunkInvalid(state, chunk) { + var er; + if (!_isUint8Array(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + er = new TypeError('Invalid non-string/buffer chunk'); + } + return er; +} + +// if it's past the high water mark, we can push in some more. +// Also, if we have no data yet, we can stand some +// more bytes. This is to work around cases where hwm=0, +// such as the repl. Also, if the push() triggered a +// readable event, and the user called read(largeNumber) such that +// needReadable was set, then we ought to push more, so that another +// 'readable' event will be triggered. +function needMoreData(state) { + return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); +} + +Readable.prototype.isPaused = function () { + return this._readableState.flowing === false; +}; + +// backwards compatibility. +Readable.prototype.setEncoding = function (enc) { + if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; + this._readableState.decoder = new StringDecoder(enc); + this._readableState.encoding = enc; + return this; +}; + +// Don't raise the hwm > 8MB +var MAX_HWM = 0x800000; +function computeNewHighWaterMark(n) { + if (n >= MAX_HWM) { + n = MAX_HWM; + } else { + // Get the next highest power of 2 to prevent increasing hwm excessively in + // tiny amounts + n--; + n |= n >>> 1; + n |= n >>> 2; + n |= n >>> 4; + n |= n >>> 8; + n |= n >>> 16; + n++; + } + return n; +} + +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function howMuchToRead(n, state) { + if (n <= 0 || state.length === 0 && state.ended) return 0; + if (state.objectMode) return 1; + if (n !== n) { + // Only flow one buffer at a time + if (state.flowing && state.length) return state.buffer.head.data.length;else return state.length; + } + // If we're asking for more than the current hwm, then raise the hwm. + if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); + if (n <= state.length) return n; + // Don't have enough + if (!state.ended) { + state.needReadable = true; + return 0; + } + return state.length; +} + +// you can override either this method, or the async _read(n) below. +Readable.prototype.read = function (n) { + debug('read', n); + n = parseInt(n, 10); + var state = this._readableState; + var nOrig = n; + + if (n !== 0) state.emittedReadable = false; + + // if we're doing read(0) to trigger a readable event, but we + // already have a bunch of data in the buffer, then just trigger + // the 'readable' event and move on. + if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) { + debug('read: emitReadable', state.length, state.ended); + if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); + return null; + } + + n = howMuchToRead(n, state); + + // if we've ended, and we're now clear, then finish it up. + if (n === 0 && state.ended) { + if (state.length === 0) endReadable(this); + return null; + } + + // All the actual chunk generation logic needs to be + // *below* the call to _read. The reason is that in certain + // synthetic stream cases, such as passthrough streams, _read + // may be a completely synchronous operation which may change + // the state of the read buffer, providing enough data when + // before there was *not* enough. + // + // So, the steps are: + // 1. Figure out what the state of things will be after we do + // a read from the buffer. + // + // 2. If that resulting state will trigger a _read, then call _read. + // Note that this may be asynchronous, or synchronous. Yes, it is + // deeply ugly to write APIs this way, but that still doesn't mean + // that the Readable class should behave improperly, as streams are + // designed to be sync/async agnostic. + // Take note if the _read call is sync or async (ie, if the read call + // has returned yet), so that we know whether or not it's safe to emit + // 'readable' etc. + // + // 3. Actually pull the requested chunks out of the buffer and return. + + // if we need a readable event, then we need to do some reading. + var doRead = state.needReadable; + debug('need readable', doRead); + + // if we currently have less than the highWaterMark, then also read some + if (state.length === 0 || state.length - n < state.highWaterMark) { + doRead = true; + debug('length less than watermark', doRead); + } + + // however, if we've ended, then there's no point, and if we're already + // reading, then it's unnecessary. + if (state.ended || state.reading) { + doRead = false; + debug('reading or ended', doRead); + } else if (doRead) { + debug('do read'); + state.reading = true; + state.sync = true; + // if the length is currently zero, then we *need* a readable event. + if (state.length === 0) state.needReadable = true; + // call internal read method + this._read(state.highWaterMark); + state.sync = false; + // If _read pushed data synchronously, then `reading` will be false, + // and we need to re-evaluate how much data we can return to the user. + if (!state.reading) n = howMuchToRead(nOrig, state); + } + + var ret; + if (n > 0) ret = fromList(n, state);else ret = null; + + if (ret === null) { + state.needReadable = true; + n = 0; + } else { + state.length -= n; + } + + if (state.length === 0) { + // If we have nothing in the buffer, then we want to know + // as soon as we *do* get something into the buffer. + if (!state.ended) state.needReadable = true; + + // If we tried to read() past the EOF, then emit end on the next tick. + if (nOrig !== n && state.ended) endReadable(this); + } + + if (ret !== null) this.emit('data', ret); + + return ret; +}; + +function onEofChunk(stream, state) { + if (state.ended) return; + if (state.decoder) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) { + state.buffer.push(chunk); + state.length += state.objectMode ? 1 : chunk.length; + } + } + state.ended = true; + + // emit 'readable' now to make sure it gets picked up. + emitReadable(stream); +} + +// Don't emit readable right away in sync mode, because this can trigger +// another read() call => stack overflow. This way, it might trigger +// a nextTick recursion warning, but that's not so bad. +function emitReadable(stream) { + var state = stream._readableState; + state.needReadable = false; + if (!state.emittedReadable) { + debug('emitReadable', state.flowing); + state.emittedReadable = true; + if (state.sync) pna.nextTick(emitReadable_, stream);else emitReadable_(stream); + } +} + +function emitReadable_(stream) { + debug('emit readable'); + stream.emit('readable'); + flow(stream); +} + +// at this point, the user has presumably seen the 'readable' event, +// and called read() to consume some data. that may have triggered +// in turn another _read(n) call, in which case reading = true if +// it's in progress. +// However, if we're not ended, or reading, and the length < hwm, +// then go ahead and try to read some more preemptively. +function maybeReadMore(stream, state) { + if (!state.readingMore) { + state.readingMore = true; + pna.nextTick(maybeReadMore_, stream, state); + } +} + +function maybeReadMore_(stream, state) { + var len = state.length; + while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { + debug('maybeReadMore read 0'); + stream.read(0); + if (len === state.length) + // didn't get any data, stop spinning. + break;else len = state.length; + } + state.readingMore = false; +} + +// abstract method. to be overridden in specific implementation classes. +// call cb(er, data) where data is <= n in length. +// for virtual (non-string, non-buffer) streams, "length" is somewhat +// arbitrary, and perhaps not very meaningful. +Readable.prototype._read = function (n) { + this.emit('error', new Error('_read() is not implemented')); +}; + +Readable.prototype.pipe = function (dest, pipeOpts) { + var src = this; + var state = this._readableState; + + switch (state.pipesCount) { + case 0: + state.pipes = dest; + break; + case 1: + state.pipes = [state.pipes, dest]; + break; + default: + state.pipes.push(dest); + break; + } + state.pipesCount += 1; + debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); + + var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; + + var endFn = doEnd ? onend : unpipe; + if (state.endEmitted) pna.nextTick(endFn);else src.once('end', endFn); + + dest.on('unpipe', onunpipe); + function onunpipe(readable, unpipeInfo) { + debug('onunpipe'); + if (readable === src) { + if (unpipeInfo && unpipeInfo.hasUnpiped === false) { + unpipeInfo.hasUnpiped = true; + cleanup(); + } + } + } + + function onend() { + debug('onend'); + dest.end(); + } + + // when the dest drains, it reduces the awaitDrain counter + // on the source. This would be more elegant with a .once() + // handler in flow(), but adding and removing repeatedly is + // too slow. + var ondrain = pipeOnDrain(src); + dest.on('drain', ondrain); + + var cleanedUp = false; + function cleanup() { + debug('cleanup'); + // cleanup event handlers once the pipe is broken + dest.removeListener('close', onclose); + dest.removeListener('finish', onfinish); + dest.removeListener('drain', ondrain); + dest.removeListener('error', onerror); + dest.removeListener('unpipe', onunpipe); + src.removeListener('end', onend); + src.removeListener('end', unpipe); + src.removeListener('data', ondata); + + cleanedUp = true; + + // if the reader is waiting for a drain event from this + // specific writer, then it would cause it to never start + // flowing again. + // So, if this is awaiting a drain, then we just call it now. + // If we don't know, then assume that we are waiting for one. + if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); + } + + // If the user pushes more data while we're writing to dest then we'll end up + // in ondata again. However, we only want to increase awaitDrain once because + // dest will only emit one 'drain' event for the multiple writes. + // => Introduce a guard on increasing awaitDrain. + var increasedAwaitDrain = false; + src.on('data', ondata); + function ondata(chunk) { + debug('ondata'); + increasedAwaitDrain = false; + var ret = dest.write(chunk); + if (false === ret && !increasedAwaitDrain) { + // If the user unpiped during `dest.write()`, it is possible + // to get stuck in a permanently paused state if that write + // also returned false. + // => Check whether `dest` is still a piping destination. + if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { + debug('false write response, pause', src._readableState.awaitDrain); + src._readableState.awaitDrain++; + increasedAwaitDrain = true; + } + src.pause(); + } + } + + // if the dest has an error, then stop piping into it. + // however, don't suppress the throwing behavior for this. + function onerror(er) { + debug('onerror', er); + unpipe(); + dest.removeListener('error', onerror); + if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er); + } + + // Make sure our error handler is attached before userland ones. + prependListener(dest, 'error', onerror); + + // Both close and finish should trigger unpipe, but only once. + function onclose() { + dest.removeListener('finish', onfinish); + unpipe(); + } + dest.once('close', onclose); + function onfinish() { + debug('onfinish'); + dest.removeListener('close', onclose); + unpipe(); + } + dest.once('finish', onfinish); + + function unpipe() { + debug('unpipe'); + src.unpipe(dest); + } + + // tell the dest that it's being piped to + dest.emit('pipe', src); + + // start the flow if it hasn't been started already. + if (!state.flowing) { + debug('pipe resume'); + src.resume(); + } + + return dest; +}; + +function pipeOnDrain(src) { + return function () { + var state = src._readableState; + debug('pipeOnDrain', state.awaitDrain); + if (state.awaitDrain) state.awaitDrain--; + if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { + state.flowing = true; + flow(src); + } + }; +} + +Readable.prototype.unpipe = function (dest) { + var state = this._readableState; + var unpipeInfo = { hasUnpiped: false }; + + // if we're not piping anywhere, then do nothing. + if (state.pipesCount === 0) return this; + + // just one destination. most common case. + if (state.pipesCount === 1) { + // passed in one, but it's not the right one. + if (dest && dest !== state.pipes) return this; + + if (!dest) dest = state.pipes; + + // got a match. + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + if (dest) dest.emit('unpipe', this, unpipeInfo); + return this; + } + + // slow case. multiple pipe destinations. + + if (!dest) { + // remove all. + var dests = state.pipes; + var len = state.pipesCount; + state.pipes = null; + state.pipesCount = 0; + state.flowing = false; + + for (var i = 0; i < len; i++) { + dests[i].emit('unpipe', this, unpipeInfo); + }return this; + } + + // try to find the right one. + var index = indexOf(state.pipes, dest); + if (index === -1) return this; + + state.pipes.splice(index, 1); + state.pipesCount -= 1; + if (state.pipesCount === 1) state.pipes = state.pipes[0]; + + dest.emit('unpipe', this, unpipeInfo); + + return this; +}; + +// set up data events if they are asked for +// Ensure readable listeners eventually get something +Readable.prototype.on = function (ev, fn) { + var res = Stream.prototype.on.call(this, ev, fn); + + if (ev === 'data') { + // Start flowing on next tick if stream isn't explicitly paused + if (this._readableState.flowing !== false) this.resume(); + } else if (ev === 'readable') { + var state = this._readableState; + if (!state.endEmitted && !state.readableListening) { + state.readableListening = state.needReadable = true; + state.emittedReadable = false; + if (!state.reading) { + pna.nextTick(nReadingNextTick, this); + } else if (state.length) { + emitReadable(this); + } + } + } + + return res; +}; +Readable.prototype.addListener = Readable.prototype.on; + +function nReadingNextTick(self) { + debug('readable nexttick read 0'); + self.read(0); +} + +// pause() and resume() are remnants of the legacy readable stream API +// If the user uses them, then switch into old mode. +Readable.prototype.resume = function () { + var state = this._readableState; + if (!state.flowing) { + debug('resume'); + state.flowing = true; + resume(this, state); + } + return this; +}; + +function resume(stream, state) { + if (!state.resumeScheduled) { + state.resumeScheduled = true; + pna.nextTick(resume_, stream, state); + } +} + +function resume_(stream, state) { + if (!state.reading) { + debug('resume read 0'); + stream.read(0); + } + + state.resumeScheduled = false; + state.awaitDrain = 0; + stream.emit('resume'); + flow(stream); + if (state.flowing && !state.reading) stream.read(0); +} + +Readable.prototype.pause = function () { + debug('call pause flowing=%j', this._readableState.flowing); + if (false !== this._readableState.flowing) { + debug('pause'); + this._readableState.flowing = false; + this.emit('pause'); + } + return this; +}; + +function flow(stream) { + var state = stream._readableState; + debug('flow', state.flowing); + while (state.flowing && stream.read() !== null) {} +} + +// wrap an old-style stream as the async data source. +// This is *not* part of the readable stream interface. +// It is an ugly unfortunate mess of history. +Readable.prototype.wrap = function (stream) { + var _this = this; + + var state = this._readableState; + var paused = false; + + stream.on('end', function () { + debug('wrapped end'); + if (state.decoder && !state.ended) { + var chunk = state.decoder.end(); + if (chunk && chunk.length) _this.push(chunk); + } + + _this.push(null); + }); + + stream.on('data', function (chunk) { + debug('wrapped data'); + if (state.decoder) chunk = state.decoder.write(chunk); + + // don't skip over falsy values in objectMode + if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; + + var ret = _this.push(chunk); + if (!ret) { + paused = true; + stream.pause(); + } + }); + + // proxy all the other methods. + // important when wrapping filters and duplexes. + for (var i in stream) { + if (this[i] === undefined && typeof stream[i] === 'function') { + this[i] = function (method) { + return function () { + return stream[method].apply(stream, arguments); + }; + }(i); + } + } + + // proxy certain important events. + for (var n = 0; n < kProxyEvents.length; n++) { + stream.on(kProxyEvents[n], this.emit.bind(this, kProxyEvents[n])); + } + + // when we try to consume some more bytes, simply unpause the + // underlying stream. + this._read = function (n) { + debug('wrapped _read', n); + if (paused) { + paused = false; + stream.resume(); + } + }; + + return this; +}; + +Object.defineProperty(Readable.prototype, 'readableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._readableState.highWaterMark; + } +}); + +// exposed for testing purposes only. +Readable._fromList = fromList; + +// Pluck off n bytes from an array of buffers. +// Length is the combined lengths of all the buffers in the list. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function fromList(n, state) { + // nothing buffered + if (state.length === 0) return null; + + var ret; + if (state.objectMode) ret = state.buffer.shift();else if (!n || n >= state.length) { + // read it all, truncate the list + if (state.decoder) ret = state.buffer.join('');else if (state.buffer.length === 1) ret = state.buffer.head.data;else ret = state.buffer.concat(state.length); + state.buffer.clear(); + } else { + // read part of list + ret = fromListPartial(n, state.buffer, state.decoder); + } + + return ret; +} + +// Extracts only enough buffered data to satisfy the amount requested. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function fromListPartial(n, list, hasStrings) { + var ret; + if (n < list.head.data.length) { + // slice is the same for buffers and strings + ret = list.head.data.slice(0, n); + list.head.data = list.head.data.slice(n); + } else if (n === list.head.data.length) { + // first chunk is a perfect match + ret = list.shift(); + } else { + // result spans more than one buffer + ret = hasStrings ? copyFromBufferString(n, list) : copyFromBuffer(n, list); + } + return ret; +} + +// Copies a specified amount of characters from the list of buffered data +// chunks. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function copyFromBufferString(n, list) { + var p = list.head; + var c = 1; + var ret = p.data; + n -= ret.length; + while (p = p.next) { + var str = p.data; + var nb = n > str.length ? str.length : n; + if (nb === str.length) ret += str;else ret += str.slice(0, n); + n -= nb; + if (n === 0) { + if (nb === str.length) { + ++c; + if (p.next) list.head = p.next;else list.head = list.tail = null; + } else { + list.head = p; + p.data = str.slice(nb); + } + break; + } + ++c; + } + list.length -= c; + return ret; +} + +// Copies a specified amount of bytes from the list of buffered data chunks. +// This function is designed to be inlinable, so please take care when making +// changes to the function body. +function copyFromBuffer(n, list) { + var ret = Buffer.allocUnsafe(n); + var p = list.head; + var c = 1; + p.data.copy(ret); + n -= p.data.length; + while (p = p.next) { + var buf = p.data; + var nb = n > buf.length ? buf.length : n; + buf.copy(ret, ret.length - n, 0, nb); + n -= nb; + if (n === 0) { + if (nb === buf.length) { + ++c; + if (p.next) list.head = p.next;else list.head = list.tail = null; + } else { + list.head = p; + p.data = buf.slice(nb); + } + break; + } + ++c; + } + list.length -= c; + return ret; +} + +function endReadable(stream) { + var state = stream._readableState; + + // If we get here before consuming all the bytes, then that is a + // bug in node. Should never happen. + if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream'); + + if (!state.endEmitted) { + state.ended = true; + pna.nextTick(endReadableNT, state, stream); + } +} + +function endReadableNT(state, stream) { + // Check that we didn't get one last unshift. + if (!state.endEmitted && state.length === 0) { + state.endEmitted = true; + stream.readable = false; + stream.emit('end'); + } +} + +function indexOf(xs, x) { + for (var i = 0, l = xs.length; i < l; i++) { + if (xs[i] === x) return i; + } + return -1; +} +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) +},{"./_stream_duplex":71,"./internal/streams/BufferList":76,"./internal/streams/destroy":77,"./internal/streams/stream":78,"_process":69,"core-util-is":44,"events":50,"inherits":56,"isarray":58,"process-nextick-args":68,"safe-buffer":83,"string_decoder/":85,"util":40}],74:[function(require,module,exports){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// a transform stream is a readable/writable stream where you do +// something with the data. Sometimes it's called a "filter", +// but that's not a great name for it, since that implies a thing where +// some bits pass through, and others are simply ignored. (That would +// be a valid example of a transform, of course.) +// +// While the output is causally related to the input, it's not a +// necessarily symmetric or synchronous transformation. For example, +// a zlib stream might take multiple plain-text writes(), and then +// emit a single compressed chunk some time in the future. +// +// Here's how this works: +// +// The Transform stream has all the aspects of the readable and writable +// stream classes. When you write(chunk), that calls _write(chunk,cb) +// internally, and returns false if there's a lot of pending writes +// buffered up. When you call read(), that calls _read(n) until +// there's enough pending readable data buffered up. +// +// In a transform stream, the written data is placed in a buffer. When +// _read(n) is called, it transforms the queued up data, calling the +// buffered _write cb's as it consumes chunks. If consuming a single +// written chunk would result in multiple output chunks, then the first +// outputted bit calls the readcb, and subsequent chunks just go into +// the read buffer, and will cause it to emit 'readable' if necessary. +// +// This way, back-pressure is actually determined by the reading side, +// since _read has to be called to start processing a new chunk. However, +// a pathological inflate type of transform can cause excessive buffering +// here. For example, imagine a stream where every byte of input is +// interpreted as an integer from 0-255, and then results in that many +// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in +// 1kb of data being output. In this case, you could write a very small +// amount of input, and end up with a very large amount of output. In +// such a pathological inflating mechanism, there'd be no way to tell +// the system to stop doing the transform. A single 4MB write could +// cause the system to run out of memory. +// +// However, even in such a pathological case, only a single written chunk +// would be consumed, and then the rest would wait (un-transformed) until +// the results of the previous transformed chunk were consumed. + +'use strict'; + +module.exports = Transform; + +var Duplex = require('./_stream_duplex'); + +/*<replacement>*/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/*</replacement>*/ + +util.inherits(Transform, Duplex); + +function afterTransform(er, data) { + var ts = this._transformState; + ts.transforming = false; + + var cb = ts.writecb; + + if (!cb) { + return this.emit('error', new Error('write callback called multiple times')); + } + + ts.writechunk = null; + ts.writecb = null; + + if (data != null) // single equals check for both `null` and `undefined` + this.push(data); + + cb(er); + + var rs = this._readableState; + rs.reading = false; + if (rs.needReadable || rs.length < rs.highWaterMark) { + this._read(rs.highWaterMark); + } +} + +function Transform(options) { + if (!(this instanceof Transform)) return new Transform(options); + + Duplex.call(this, options); + + this._transformState = { + afterTransform: afterTransform.bind(this), + needTransform: false, + transforming: false, + writecb: null, + writechunk: null, + writeencoding: null + }; + + // start out asking for a readable event once data is transformed. + this._readableState.needReadable = true; + + // we have implemented the _read method, and done the other things + // that Readable wants before the first _read call, so unset the + // sync guard flag. + this._readableState.sync = false; + + if (options) { + if (typeof options.transform === 'function') this._transform = options.transform; + + if (typeof options.flush === 'function') this._flush = options.flush; + } + + // When the writable side finishes, then flush out anything remaining. + this.on('prefinish', prefinish); +} + +function prefinish() { + var _this = this; + + if (typeof this._flush === 'function') { + this._flush(function (er, data) { + done(_this, er, data); + }); + } else { + done(this, null, null); + } +} + +Transform.prototype.push = function (chunk, encoding) { + this._transformState.needTransform = false; + return Duplex.prototype.push.call(this, chunk, encoding); +}; + +// This is the part where you do stuff! +// override this function in implementation classes. +// 'chunk' is an input chunk. +// +// Call `push(newChunk)` to pass along transformed output +// to the readable side. You may call 'push' zero or more times. +// +// Call `cb(err)` when you are done with this chunk. If you pass +// an error, then that'll put the hurt on the whole operation. If you +// never call cb(), then you'll never get another chunk. +Transform.prototype._transform = function (chunk, encoding, cb) { + throw new Error('_transform() is not implemented'); +}; + +Transform.prototype._write = function (chunk, encoding, cb) { + var ts = this._transformState; + ts.writecb = cb; + ts.writechunk = chunk; + ts.writeencoding = encoding; + if (!ts.transforming) { + var rs = this._readableState; + if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); + } +}; + +// Doesn't matter what the args are here. +// _transform does all the work. +// That we got here means that the readable side wants more data. +Transform.prototype._read = function (n) { + var ts = this._transformState; + + if (ts.writechunk !== null && ts.writecb && !ts.transforming) { + ts.transforming = true; + this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); + } else { + // mark that we need a transform, so that any data that comes in + // will get processed, now that we've asked for it. + ts.needTransform = true; + } +}; + +Transform.prototype._destroy = function (err, cb) { + var _this2 = this; + + Duplex.prototype._destroy.call(this, err, function (err2) { + cb(err2); + _this2.emit('close'); + }); +}; + +function done(stream, er, data) { + if (er) return stream.emit('error', er); + + if (data != null) // single equals check for both `null` and `undefined` + stream.push(data); + + // if there's nothing in the write buffer, then that means + // that nothing more will ever be provided + if (stream._writableState.length) throw new Error('Calling transform done when ws.length != 0'); + + if (stream._transformState.transforming) throw new Error('Calling transform done when still transforming'); + + return stream.push(null); +} +},{"./_stream_duplex":71,"core-util-is":44,"inherits":56}],75:[function(require,module,exports){ +(function (process,global,setImmediate){ +// Copyright Joyent, Inc. and other Node contributors. +// +// Permission is hereby granted, free of charge, to any person obtaining a +// copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to permit +// persons to whom the Software is furnished to do so, subject to the +// following conditions: +// +// The above copyright notice and this permission notice shall be included +// in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN +// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE +// USE OR OTHER DEALINGS IN THE SOFTWARE. + +// A bit simpler than readable streams. +// Implement an async ._write(chunk, encoding, cb), and it'll handle all +// the drain event emission and buffering. + +'use strict'; + +/*<replacement>*/ + +var pna = require('process-nextick-args'); +/*</replacement>*/ + +module.exports = Writable; + +/* <replacement> */ +function WriteReq(chunk, encoding, cb) { + this.chunk = chunk; + this.encoding = encoding; + this.callback = cb; + this.next = null; +} + +// It seems a linked list but it is not +// there will be only 2 of these for each stream +function CorkedRequest(state) { + var _this = this; + + this.next = null; + this.entry = null; + this.finish = function () { + onCorkedFinish(_this, state); + }; +} +/* </replacement> */ + +/*<replacement>*/ +var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : pna.nextTick; +/*</replacement>*/ + +/*<replacement>*/ +var Duplex; +/*</replacement>*/ + +Writable.WritableState = WritableState; + +/*<replacement>*/ +var util = require('core-util-is'); +util.inherits = require('inherits'); +/*</replacement>*/ + +/*<replacement>*/ +var internalUtil = { + deprecate: require('util-deprecate') +}; +/*</replacement>*/ + +/*<replacement>*/ +var Stream = require('./internal/streams/stream'); +/*</replacement>*/ + +/*<replacement>*/ + +var Buffer = require('safe-buffer').Buffer; +var OurUint8Array = global.Uint8Array || function () {}; +function _uint8ArrayToBuffer(chunk) { + return Buffer.from(chunk); +} +function _isUint8Array(obj) { + return Buffer.isBuffer(obj) || obj instanceof OurUint8Array; +} + +/*</replacement>*/ + +var destroyImpl = require('./internal/streams/destroy'); + +util.inherits(Writable, Stream); + +function nop() {} + +function WritableState(options, stream) { + Duplex = Duplex || require('./_stream_duplex'); + + options = options || {}; + + // Duplex streams are both readable and writable, but share + // the same options object. + // However, some cases require setting options to different + // values for the readable and the writable sides of the duplex stream. + // These options can be provided separately as readableXXX and writableXXX. + var isDuplex = stream instanceof Duplex; + + // object stream flag to indicate whether or not this stream + // contains buffers or objects. + this.objectMode = !!options.objectMode; + + if (isDuplex) this.objectMode = this.objectMode || !!options.writableObjectMode; + + // the point at which write() starts returning false + // Note: 0 is a valid value, means that we always return false if + // the entire buffer is not flushed immediately on write() + var hwm = options.highWaterMark; + var writableHwm = options.writableHighWaterMark; + var defaultHwm = this.objectMode ? 16 : 16 * 1024; + + if (hwm || hwm === 0) this.highWaterMark = hwm;else if (isDuplex && (writableHwm || writableHwm === 0)) this.highWaterMark = writableHwm;else this.highWaterMark = defaultHwm; + + // cast to ints. + this.highWaterMark = Math.floor(this.highWaterMark); + + // if _final has been called + this.finalCalled = false; + + // drain event flag. + this.needDrain = false; + // at the start of calling end() + this.ending = false; + // when end() has been called, and returned + this.ended = false; + // when 'finish' is emitted + this.finished = false; + + // has it been destroyed + this.destroyed = false; + + // should we decode strings into buffers before passing to _write? + // this is here so that some node-core streams can optimize string + // handling at a lower level. + var noDecode = options.decodeStrings === false; + this.decodeStrings = !noDecode; + + // Crypto is kind of old and crusty. Historically, its default string + // encoding is 'binary' so we have to make this configurable. + // Everything else in the universe uses 'utf8', though. + this.defaultEncoding = options.defaultEncoding || 'utf8'; + + // not an actual buffer we keep track of, but a measurement + // of how much we're waiting to get pushed to some underlying + // socket or file. + this.length = 0; + + // a flag to see when we're in the middle of a write. + this.writing = false; + + // when true all writes will be buffered until .uncork() call + this.corked = 0; + + // a flag to be able to tell if the onwrite cb is called immediately, + // or on a later tick. We set this to true at first, because any + // actions that shouldn't happen until "later" should generally also + // not happen before the first write call. + this.sync = true; + + // a flag to know if we're processing previously buffered items, which + // may call the _write() callback in the same tick, so that we don't + // end up in an overlapped onwrite situation. + this.bufferProcessing = false; + + // the callback that's passed to _write(chunk,cb) + this.onwrite = function (er) { + onwrite(stream, er); + }; + + // the callback that the user supplies to write(chunk,encoding,cb) + this.writecb = null; + + // the amount that is being written when _write is called. + this.writelen = 0; + + this.bufferedRequest = null; + this.lastBufferedRequest = null; + + // number of pending user-supplied write callbacks + // this must be 0 before 'finish' can be emitted + this.pendingcb = 0; + + // emit prefinish if the only thing we're waiting for is _write cbs + // This is relevant for synchronous Transform streams + this.prefinished = false; + + // True if the error was already emitted and should not be thrown again + this.errorEmitted = false; + + // count buffered requests + this.bufferedRequestCount = 0; + + // allocate the first CorkedRequest, there is always + // one allocated and free to use, and we maintain at most two + this.corkedRequestsFree = new CorkedRequest(this); +} + +WritableState.prototype.getBuffer = function getBuffer() { + var current = this.bufferedRequest; + var out = []; + while (current) { + out.push(current); + current = current.next; + } + return out; +}; + +(function () { + try { + Object.defineProperty(WritableState.prototype, 'buffer', { + get: internalUtil.deprecate(function () { + return this.getBuffer(); + }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.', 'DEP0003') + }); + } catch (_) {} +})(); + +// Test _writableState for inheritance to account for Duplex streams, +// whose prototype chain only points to Readable. +var realHasInstance; +if (typeof Symbol === 'function' && Symbol.hasInstance && typeof Function.prototype[Symbol.hasInstance] === 'function') { + realHasInstance = Function.prototype[Symbol.hasInstance]; + Object.defineProperty(Writable, Symbol.hasInstance, { + value: function (object) { + if (realHasInstance.call(this, object)) return true; + if (this !== Writable) return false; + + return object && object._writableState instanceof WritableState; + } + }); +} else { + realHasInstance = function (object) { + return object instanceof this; + }; +} + +function Writable(options) { + Duplex = Duplex || require('./_stream_duplex'); + + // Writable ctor is applied to Duplexes, too. + // `realHasInstance` is necessary because using plain `instanceof` + // would return false, as no `_writableState` property is attached. + + // Trying to use the custom `instanceof` for Writable here will also break the + // Node.js LazyTransform implementation, which has a non-trivial getter for + // `_writableState` that would lead to infinite recursion. + if (!realHasInstance.call(Writable, this) && !(this instanceof Duplex)) { + return new Writable(options); + } + + this._writableState = new WritableState(options, this); + + // legacy. + this.writable = true; + + if (options) { + if (typeof options.write === 'function') this._write = options.write; + + if (typeof options.writev === 'function') this._writev = options.writev; + + if (typeof options.destroy === 'function') this._destroy = options.destroy; + + if (typeof options.final === 'function') this._final = options.final; + } + + Stream.call(this); +} + +// Otherwise people can pipe Writable streams, which is just wrong. +Writable.prototype.pipe = function () { + this.emit('error', new Error('Cannot pipe, not readable')); +}; + +function writeAfterEnd(stream, cb) { + var er = new Error('write after end'); + // TODO: defer error events consistently everywhere, not just the cb + stream.emit('error', er); + pna.nextTick(cb, er); +} + +// Checks that a user-supplied chunk is valid, especially for the particular +// mode the stream is in. Currently this means that `null` is never accepted +// and undefined/non-string values are only allowed in object mode. +function validChunk(stream, state, chunk, cb) { + var valid = true; + var er = false; + + if (chunk === null) { + er = new TypeError('May not write null values to stream'); + } else if (typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { + er = new TypeError('Invalid non-string/buffer chunk'); + } + if (er) { + stream.emit('error', er); + pna.nextTick(cb, er); + valid = false; + } + return valid; +} + +Writable.prototype.write = function (chunk, encoding, cb) { + var state = this._writableState; + var ret = false; + var isBuf = !state.objectMode && _isUint8Array(chunk); + + if (isBuf && !Buffer.isBuffer(chunk)) { + chunk = _uint8ArrayToBuffer(chunk); + } + + if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } + + if (isBuf) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; + + if (typeof cb !== 'function') cb = nop; + + if (state.ended) writeAfterEnd(this, cb);else if (isBuf || validChunk(this, state, chunk, cb)) { + state.pendingcb++; + ret = writeOrBuffer(this, state, isBuf, chunk, encoding, cb); + } + + return ret; +}; + +Writable.prototype.cork = function () { + var state = this._writableState; + + state.corked++; +}; + +Writable.prototype.uncork = function () { + var state = this._writableState; + + if (state.corked) { + state.corked--; + + if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); + } +}; + +Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { + // node::ParseEncoding() requires lower case. + if (typeof encoding === 'string') encoding = encoding.toLowerCase(); + if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); + this._writableState.defaultEncoding = encoding; + return this; +}; + +function decodeChunk(state, chunk, encoding) { + if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { + chunk = Buffer.from(chunk, encoding); + } + return chunk; +} + +Object.defineProperty(Writable.prototype, 'writableHighWaterMark', { + // making it explicit this property is not enumerable + // because otherwise some prototype manipulation in + // userland will fail + enumerable: false, + get: function () { + return this._writableState.highWaterMark; + } +}); + +// if we're already writing something, then just put this +// in the queue, and wait our turn. Otherwise, call _write +// If we return false, then we need a drain event, so set that flag. +function writeOrBuffer(stream, state, isBuf, chunk, encoding, cb) { + if (!isBuf) { + var newChunk = decodeChunk(state, chunk, encoding); + if (chunk !== newChunk) { + isBuf = true; + encoding = 'buffer'; + chunk = newChunk; + } + } + var len = state.objectMode ? 1 : chunk.length; + + state.length += len; + + var ret = state.length < state.highWaterMark; + // we must ensure that previous needDrain will not be reset to false. + if (!ret) state.needDrain = true; + + if (state.writing || state.corked) { + var last = state.lastBufferedRequest; + state.lastBufferedRequest = { + chunk: chunk, + encoding: encoding, + isBuf: isBuf, + callback: cb, + next: null + }; + if (last) { + last.next = state.lastBufferedRequest; + } else { + state.bufferedRequest = state.lastBufferedRequest; + } + state.bufferedRequestCount += 1; + } else { + doWrite(stream, state, false, len, chunk, encoding, cb); + } + + return ret; +} + +function doWrite(stream, state, writev, len, chunk, encoding, cb) { + state.writelen = len; + state.writecb = cb; + state.writing = true; + state.sync = true; + if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); + state.sync = false; +} + +function onwriteError(stream, state, sync, er, cb) { + --state.pendingcb; + + if (sync) { + // defer the callback if we are being called synchronously + // to avoid piling up things on the stack + pna.nextTick(cb, er); + // this can emit finish, and it will always happen + // after error + pna.nextTick(finishMaybe, stream, state); + stream._writableState.errorEmitted = true; + stream.emit('error', er); + } else { + // the caller expect this to happen before if + // it is async + cb(er); + stream._writableState.errorEmitted = true; + stream.emit('error', er); + // this can emit finish, but finish must + // always follow error + finishMaybe(stream, state); + } +} + +function onwriteStateUpdate(state) { + state.writing = false; + state.writecb = null; + state.length -= state.writelen; + state.writelen = 0; +} + +function onwrite(stream, er) { + var state = stream._writableState; + var sync = state.sync; + var cb = state.writecb; + + onwriteStateUpdate(state); + + if (er) onwriteError(stream, state, sync, er, cb);else { + // Check if we're actually ready to finish, but don't emit yet + var finished = needFinish(state); + + if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { + clearBuffer(stream, state); + } + + if (sync) { + /*<replacement>*/ + asyncWrite(afterWrite, stream, state, finished, cb); + /*</replacement>*/ + } else { + afterWrite(stream, state, finished, cb); + } + } +} + +function afterWrite(stream, state, finished, cb) { + if (!finished) onwriteDrain(stream, state); + state.pendingcb--; + cb(); + finishMaybe(stream, state); +} + +// Must force callback to be called on nextTick, so that we don't +// emit 'drain' before the write() consumer gets the 'false' return +// value, and has a chance to attach a 'drain' listener. +function onwriteDrain(stream, state) { + if (state.length === 0 && state.needDrain) { + state.needDrain = false; + stream.emit('drain'); + } +} + +// if there's something in the buffer waiting, then process it +function clearBuffer(stream, state) { + state.bufferProcessing = true; + var entry = state.bufferedRequest; + + if (stream._writev && entry && entry.next) { + // Fast case, write everything using _writev() + var l = state.bufferedRequestCount; + var buffer = new Array(l); + var holder = state.corkedRequestsFree; + holder.entry = entry; + + var count = 0; + var allBuffers = true; + while (entry) { + buffer[count] = entry; + if (!entry.isBuf) allBuffers = false; + entry = entry.next; + count += 1; + } + buffer.allBuffers = allBuffers; + + doWrite(stream, state, true, state.length, buffer, '', holder.finish); + + // doWrite is almost always async, defer these to save a bit of time + // as the hot path ends with doWrite + state.pendingcb++; + state.lastBufferedRequest = null; + if (holder.next) { + state.corkedRequestsFree = holder.next; + holder.next = null; + } else { + state.corkedRequestsFree = new CorkedRequest(state); + } + state.bufferedRequestCount = 0; + } else { + // Slow case, write chunks one-by-one + while (entry) { + var chunk = entry.chunk; + var encoding = entry.encoding; + var cb = entry.callback; + var len = state.objectMode ? 1 : chunk.length; + + doWrite(stream, state, false, len, chunk, encoding, cb); + entry = entry.next; + state.bufferedRequestCount--; + // if we didn't call the onwrite immediately, then + // it means that we need to wait until it does. + // also, that means that the chunk and cb are currently + // being processed, so move the buffer counter past them. + if (state.writing) { + break; + } + } + + if (entry === null) state.lastBufferedRequest = null; + } + + state.bufferedRequest = entry; + state.bufferProcessing = false; +} + +Writable.prototype._write = function (chunk, encoding, cb) { + cb(new Error('_write() is not implemented')); +}; + +Writable.prototype._writev = null; + +Writable.prototype.end = function (chunk, encoding, cb) { + var state = this._writableState; + + if (typeof chunk === 'function') { + cb = chunk; + chunk = null; + encoding = null; + } else if (typeof encoding === 'function') { + cb = encoding; + encoding = null; + } + + if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); + + // .end() fully uncorks + if (state.corked) { + state.corked = 1; + this.uncork(); + } + + // ignore unnecessary end() calls. + if (!state.ending && !state.finished) endWritable(this, state, cb); +}; + +function needFinish(state) { + return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; +} +function callFinal(stream, state) { + stream._final(function (err) { + state.pendingcb--; + if (err) { + stream.emit('error', err); + } + state.prefinished = true; + stream.emit('prefinish'); + finishMaybe(stream, state); + }); +} +function prefinish(stream, state) { + if (!state.prefinished && !state.finalCalled) { + if (typeof stream._final === 'function') { + state.pendingcb++; + state.finalCalled = true; + pna.nextTick(callFinal, stream, state); + } else { + state.prefinished = true; + stream.emit('prefinish'); + } + } +} + +function finishMaybe(stream, state) { + var need = needFinish(state); + if (need) { + prefinish(stream, state); + if (state.pendingcb === 0) { + state.finished = true; + stream.emit('finish'); + } + } + return need; +} + +function endWritable(stream, state, cb) { + state.ending = true; + finishMaybe(stream, state); + if (cb) { + if (state.finished) pna.nextTick(cb);else stream.once('finish', cb); + } + state.ended = true; + stream.writable = false; +} + +function onCorkedFinish(corkReq, state, err) { + var entry = corkReq.entry; + corkReq.entry = null; + while (entry) { + var cb = entry.callback; + state.pendingcb--; + cb(err); + entry = entry.next; + } + if (state.corkedRequestsFree) { + state.corkedRequestsFree.next = corkReq; + } else { + state.corkedRequestsFree = corkReq; + } +} + +Object.defineProperty(Writable.prototype, 'destroyed', { + get: function () { + if (this._writableState === undefined) { + return false; + } + return this._writableState.destroyed; + }, + set: function (value) { + // we ignore the value if the stream + // has not been initialized yet + if (!this._writableState) { + return; + } + + // backward compatibility, the user is explicitly + // managing destroyed + this._writableState.destroyed = value; + } +}); + +Writable.prototype.destroy = destroyImpl.destroy; +Writable.prototype._undestroy = destroyImpl.undestroy; +Writable.prototype._destroy = function (err, cb) { + this.end(); + cb(err); +}; +}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {},require("timers").setImmediate) +},{"./_stream_duplex":71,"./internal/streams/destroy":77,"./internal/streams/stream":78,"_process":69,"core-util-is":44,"inherits":56,"process-nextick-args":68,"safe-buffer":83,"timers":86,"util-deprecate":87}],76:[function(require,module,exports){ +'use strict'; + +function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + +var Buffer = require('safe-buffer').Buffer; +var util = require('util'); + +function copyBuffer(src, target, offset) { + src.copy(target, offset); +} + +module.exports = function () { + function BufferList() { + _classCallCheck(this, BufferList); + + this.head = null; + this.tail = null; + this.length = 0; + } + + BufferList.prototype.push = function push(v) { + var entry = { data: v, next: null }; + if (this.length > 0) this.tail.next = entry;else this.head = entry; + this.tail = entry; + ++this.length; + }; + + BufferList.prototype.unshift = function unshift(v) { + var entry = { data: v, next: this.head }; + if (this.length === 0) this.tail = entry; + this.head = entry; + ++this.length; + }; + + BufferList.prototype.shift = function shift() { + if (this.length === 0) return; + var ret = this.head.data; + if (this.length === 1) this.head = this.tail = null;else this.head = this.head.next; + --this.length; + return ret; + }; + + BufferList.prototype.clear = function clear() { + this.head = this.tail = null; + this.length = 0; + }; + + BufferList.prototype.join = function join(s) { + if (this.length === 0) return ''; + var p = this.head; + var ret = '' + p.data; + while (p = p.next) { + ret += s + p.data; + }return ret; + }; + + BufferList.prototype.concat = function concat(n) { + if (this.length === 0) return Buffer.alloc(0); + if (this.length === 1) return this.head.data; + var ret = Buffer.allocUnsafe(n >>> 0); + var p = this.head; + var i = 0; + while (p) { + copyBuffer(p.data, ret, i); + i += p.data.length; + p = p.next; + } + return ret; + }; + + return BufferList; +}(); + +if (util && util.inspect && util.inspect.custom) { + module.exports.prototype[util.inspect.custom] = function () { + var obj = util.inspect({ length: this.length }); + return this.constructor.name + ' ' + obj; + }; +} +},{"safe-buffer":83,"util":40}],77:[function(require,module,exports){ +'use strict'; + +/*<replacement>*/ + +var pna = require('process-nextick-args'); +/*</replacement>*/ + +// undocumented cb() API, needed for core, not for public API +function destroy(err, cb) { + var _this = this; + + var readableDestroyed = this._readableState && this._readableState.destroyed; + var writableDestroyed = this._writableState && this._writableState.destroyed; + + if (readableDestroyed || writableDestroyed) { + if (cb) { + cb(err); + } else if (err && (!this._writableState || !this._writableState.errorEmitted)) { + pna.nextTick(emitErrorNT, this, err); + } + return this; + } + + // we set destroyed to true before firing error callbacks in order + // to make it re-entrance safe in case destroy() is called within callbacks + + if (this._readableState) { + this._readableState.destroyed = true; + } + + // if this is a duplex stream mark the writable part as destroyed as well + if (this._writableState) { + this._writableState.destroyed = true; + } + + this._destroy(err || null, function (err) { + if (!cb && err) { + pna.nextTick(emitErrorNT, _this, err); + if (_this._writableState) { + _this._writableState.errorEmitted = true; + } + } else if (cb) { + cb(err); + } + }); + + return this; +} + +function undestroy() { + if (this._readableState) { + this._readableState.destroyed = false; + this._readableState.reading = false; + this._readableState.ended = false; + this._readableState.endEmitted = false; + } + + if (this._writableState) { + this._writableState.destroyed = false; + this._writableState.ended = false; + this._writableState.ending = false; + this._writableState.finished = false; + this._writableState.errorEmitted = false; + } +} + +function emitErrorNT(self, err) { + self.emit('error', err); +} + +module.exports = { + destroy: destroy, + undestroy: undestroy +}; +},{"process-nextick-args":68}],78:[function(require,module,exports){ +module.exports = require('events').EventEmitter; + +},{"events":50}],79:[function(require,module,exports){ +module.exports = require('./readable').PassThrough + +},{"./readable":80}],80:[function(require,module,exports){ +exports = module.exports = require('./lib/_stream_readable.js'); +exports.Stream = exports; +exports.Readable = exports; +exports.Writable = require('./lib/_stream_writable.js'); +exports.Duplex = require('./lib/_stream_duplex.js'); +exports.Transform = require('./lib/_stream_transform.js'); +exports.PassThrough = require('./lib/_stream_passthrough.js'); + +},{"./lib/_stream_duplex.js":71,"./lib/_stream_passthrough.js":72,"./lib/_stream_readable.js":73,"./lib/_stream_transform.js":74,"./lib/_stream_writable.js":75}],81:[function(require,module,exports){ +module.exports = require('./readable').Transform + +},{"./readable":80}],82:[function(require,module,exports){ +module.exports = require('./lib/_stream_writable.js'); + +},{"./lib/_stream_writable.js":75}],83:[function(require,module,exports){ +/* eslint-disable node/no-deprecated-api */ +var buffer = require('buffer') +var Buffer = buffer.Buffer + +// alternative to using Object.keys for old browsers +function copyProps (src, dst) { + for (var key in src) { + dst[key] = src[key] + } +} +if (Buffer.from && Buffer.alloc && Buffer.allocUnsafe && Buffer.allocUnsafeSlow) { + module.exports = buffer +} else { + // Copy properties from require('buffer') + copyProps(buffer, exports) + exports.Buffer = SafeBuffer +} + +function SafeBuffer (arg, encodingOrOffset, length) { + return Buffer(arg, encodingOrOffset, length) +} + +// Copy static methods from Buffer +copyProps(Buffer, SafeBuffer) + +SafeBuffer.from = function (arg, encodingOrOffset, length) { + if (typeof arg === 'number') { + throw new TypeError('Argument must not be a number') + } + return Buffer(arg, encodingOrOffset, length) +} + +SafeBuffer.alloc = function (size, fill, encoding) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + var buf = Buffer(size) + if (fill !== undefined) { + if (typeof encoding === 'string') { + buf.fill(fill, encoding) + } else { + buf.fill(fill) + } + } else { + buf.fill(0) + } + return buf +} + +SafeBuffer.allocUnsafe = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return Buffer(size) +} + +SafeBuffer.allocUnsafeSlow = function (size) { + if (typeof size !== 'number') { + throw new TypeError('Argument must be a number') + } + return buffer.SlowBuffer(size) +} + +},{"buffer":43}],84:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -10471,1750 +17022,7 @@ return dest; }; -},{"events":50,"inherits":53,"readable-stream/duplex.js":61,"readable-stream/passthrough.js":67,"readable-stream/readable.js":68,"readable-stream/transform.js":69,"readable-stream/writable.js":70}],60:[function(require,module,exports){ -arguments[4][46][0].apply(exports,arguments) -},{"dup":46}],61:[function(require,module,exports){ -module.exports = require("./lib/_stream_duplex.js") - -},{"./lib/_stream_duplex.js":62}],62:[function(require,module,exports){ -// a duplex stream is just a stream that is both readable and writable. -// Since JS doesn't have multiple prototypal inheritance, this class -// prototypally inherits from Readable, and then parasitically from -// Writable. - -'use strict'; - -/*<replacement>*/ - -var objectKeys = Object.keys || function (obj) { - var keys = []; - for (var key in obj) { - keys.push(key); - }return keys; -}; -/*</replacement>*/ - -module.exports = Duplex; - -/*<replacement>*/ -var processNextTick = require('process-nextick-args'); -/*</replacement>*/ - -/*<replacement>*/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/*</replacement>*/ - -var Readable = require('./_stream_readable'); -var Writable = require('./_stream_writable'); - -util.inherits(Duplex, Readable); - -var keys = objectKeys(Writable.prototype); -for (var v = 0; v < keys.length; v++) { - var method = keys[v]; - if (!Duplex.prototype[method]) Duplex.prototype[method] = Writable.prototype[method]; -} - -function Duplex(options) { - if (!(this instanceof Duplex)) return new Duplex(options); - - Readable.call(this, options); - Writable.call(this, options); - - if (options && options.readable === false) this.readable = false; - - if (options && options.writable === false) this.writable = false; - - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) this.allowHalfOpen = false; - - this.once('end', onend); -} - -// the no-half-open enforcer -function onend() { - // if we allow half-open state, or if the writable side ended, - // then we're ok. - if (this.allowHalfOpen || this._writableState.ended) return; - - // no more data can be written. - // But allow more writes to happen in this tick. - processNextTick(onEndNT, this); -} - -function onEndNT(self) { - self.end(); -} - -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} -},{"./_stream_readable":64,"./_stream_writable":66,"core-util-is":47,"inherits":53,"process-nextick-args":57}],63:[function(require,module,exports){ -// a passthrough stream. -// basically just the most minimal sort of Transform stream. -// Every written chunk gets output as-is. - -'use strict'; - -module.exports = PassThrough; - -var Transform = require('./_stream_transform'); - -/*<replacement>*/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/*</replacement>*/ - -util.inherits(PassThrough, Transform); - -function PassThrough(options) { - if (!(this instanceof PassThrough)) return new PassThrough(options); - - Transform.call(this, options); -} - -PassThrough.prototype._transform = function (chunk, encoding, cb) { - cb(null, chunk); -}; -},{"./_stream_transform":65,"core-util-is":47,"inherits":53}],64:[function(require,module,exports){ -(function (process){ -'use strict'; - -module.exports = Readable; - -/*<replacement>*/ -var processNextTick = require('process-nextick-args'); -/*</replacement>*/ - -/*<replacement>*/ -var isArray = require('isarray'); -/*</replacement>*/ - -Readable.ReadableState = ReadableState; - -/*<replacement>*/ -var EE = require('events').EventEmitter; - -var EElistenerCount = function (emitter, type) { - return emitter.listeners(type).length; -}; -/*</replacement>*/ - -/*<replacement>*/ -var Stream; -(function () { - try { - Stream = require('st' + 'ream'); - } catch (_) {} finally { - if (!Stream) Stream = require('events').EventEmitter; - } -})(); -/*</replacement>*/ - -var Buffer = require('buffer').Buffer; -/*<replacement>*/ -var bufferShim = require('buffer-shims'); -/*</replacement>*/ - -/*<replacement>*/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/*</replacement>*/ - -/*<replacement>*/ -var debugUtil = require('util'); -var debug = void 0; -if (debugUtil && debugUtil.debuglog) { - debug = debugUtil.debuglog('stream'); -} else { - debug = function () {}; -} -/*</replacement>*/ - -var StringDecoder; - -util.inherits(Readable, Stream); - -var hasPrependListener = typeof EE.prototype.prependListener === 'function'; - -function prependListener(emitter, event, fn) { - if (hasPrependListener) return emitter.prependListener(event, fn); - - // This is a brutally ugly hack to make sure that our error handler - // is attached before any userland ones. NEVER DO THIS. This is here - // only because this code needs to continue to work with older versions - // of Node.js that do not include the prependListener() method. The goal - // is to eventually remove this hack. - if (!emitter._events || !emitter._events[event]) emitter.on(event, fn);else if (isArray(emitter._events[event])) emitter._events[event].unshift(fn);else emitter._events[event] = [fn, emitter._events[event]]; -} - -var Duplex; -function ReadableState(options, stream) { - Duplex = Duplex || require('./_stream_duplex'); - - options = options || {}; - - // object stream flag. Used to make read(n) ignore n and to - // make all the buffer merging and length checks go away - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.readableObjectMode; - - // the point at which it stops calling _read() to fill the buffer - // Note: 0 is a valid value, means "don't call _read preemptively ever" - var hwm = options.highWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; - - // cast to ints. - this.highWaterMark = ~ ~this.highWaterMark; - - this.buffer = []; - this.length = 0; - this.pipes = null; - this.pipesCount = 0; - this.flowing = null; - this.ended = false; - this.endEmitted = false; - this.reading = false; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // whenever we return null, then we set a flag to say - // that we're awaiting a 'readable' event emission. - this.needReadable = false; - this.emittedReadable = false; - this.readableListening = false; - this.resumeScheduled = false; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // when piping, we only care about 'readable' events that happen - // after read()ing all the bytes and not getting any pushback. - this.ranOut = false; - - // the number of writers that are awaiting a drain event in .pipe()s - this.awaitDrain = 0; - - // if true, a maybeReadMore has been scheduled - this.readingMore = false; - - this.decoder = null; - this.encoding = null; - if (options.encoding) { - if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; - this.decoder = new StringDecoder(options.encoding); - this.encoding = options.encoding; - } -} - -var Duplex; -function Readable(options) { - Duplex = Duplex || require('./_stream_duplex'); - - if (!(this instanceof Readable)) return new Readable(options); - - this._readableState = new ReadableState(options, this); - - // legacy - this.readable = true; - - if (options && typeof options.read === 'function') this._read = options.read; - - Stream.call(this); -} - -// Manually shove something into the read() buffer. -// This returns true if the highWaterMark has not been hit yet, -// similar to how Writable.write() returns true if you should -// write() some more. -Readable.prototype.push = function (chunk, encoding) { - var state = this._readableState; - - if (!state.objectMode && typeof chunk === 'string') { - encoding = encoding || state.defaultEncoding; - if (encoding !== state.encoding) { - chunk = bufferShim.from(chunk, encoding); - encoding = ''; - } - } - - return readableAddChunk(this, state, chunk, encoding, false); -}; - -// Unshift should *always* be something directly out of read() -Readable.prototype.unshift = function (chunk) { - var state = this._readableState; - return readableAddChunk(this, state, chunk, '', true); -}; - -Readable.prototype.isPaused = function () { - return this._readableState.flowing === false; -}; - -function readableAddChunk(stream, state, chunk, encoding, addToFront) { - var er = chunkInvalid(state, chunk); - if (er) { - stream.emit('error', er); - } else if (chunk === null) { - state.reading = false; - onEofChunk(stream, state); - } else if (state.objectMode || chunk && chunk.length > 0) { - if (state.ended && !addToFront) { - var e = new Error('stream.push() after EOF'); - stream.emit('error', e); - } else if (state.endEmitted && addToFront) { - var _e = new Error('stream.unshift() after end event'); - stream.emit('error', _e); - } else { - var skipAdd; - if (state.decoder && !addToFront && !encoding) { - chunk = state.decoder.write(chunk); - skipAdd = !state.objectMode && chunk.length === 0; - } - - if (!addToFront) state.reading = false; - - // Don't add to the buffer if we've decoded to an empty string chunk and - // we're not in object mode - if (!skipAdd) { - // if we want the data now, just emit it. - if (state.flowing && state.length === 0 && !state.sync) { - stream.emit('data', chunk); - stream.read(0); - } else { - // update the buffer info. - state.length += state.objectMode ? 1 : chunk.length; - if (addToFront) state.buffer.unshift(chunk);else state.buffer.push(chunk); - - if (state.needReadable) emitReadable(stream); - } - } - - maybeReadMore(stream, state); - } - } else if (!addToFront) { - state.reading = false; - } - - return needMoreData(state); -} - -// if it's past the high water mark, we can push in some more. -// Also, if we have no data yet, we can stand some -// more bytes. This is to work around cases where hwm=0, -// such as the repl. Also, if the push() triggered a -// readable event, and the user called read(largeNumber) such that -// needReadable was set, then we ought to push more, so that another -// 'readable' event will be triggered. -function needMoreData(state) { - return !state.ended && (state.needReadable || state.length < state.highWaterMark || state.length === 0); -} - -// backwards compatibility. -Readable.prototype.setEncoding = function (enc) { - if (!StringDecoder) StringDecoder = require('string_decoder/').StringDecoder; - this._readableState.decoder = new StringDecoder(enc); - this._readableState.encoding = enc; - return this; -}; - -// Don't raise the hwm > 8MB -var MAX_HWM = 0x800000; -function computeNewHighWaterMark(n) { - if (n >= MAX_HWM) { - n = MAX_HWM; - } else { - // Get the next highest power of 2 - n--; - n |= n >>> 1; - n |= n >>> 2; - n |= n >>> 4; - n |= n >>> 8; - n |= n >>> 16; - n++; - } - return n; -} - -function howMuchToRead(n, state) { - if (state.length === 0 && state.ended) return 0; - - if (state.objectMode) return n === 0 ? 0 : 1; - - if (n === null || isNaN(n)) { - // only flow one buffer at a time - if (state.flowing && state.buffer.length) return state.buffer[0].length;else return state.length; - } - - if (n <= 0) return 0; - - // If we're asking for more than the target buffer level, - // then raise the water mark. Bump up to the next highest - // power of 2, to prevent increasing it excessively in tiny - // amounts. - if (n > state.highWaterMark) state.highWaterMark = computeNewHighWaterMark(n); - - // don't have that much. return null, unless we've ended. - if (n > state.length) { - if (!state.ended) { - state.needReadable = true; - return 0; - } else { - return state.length; - } - } - - return n; -} - -// you can override either this method, or the async _read(n) below. -Readable.prototype.read = function (n) { - debug('read', n); - var state = this._readableState; - var nOrig = n; - - if (typeof n !== 'number' || n > 0) state.emittedReadable = false; - - // if we're doing read(0) to trigger a readable event, but we - // already have a bunch of data in the buffer, then just trigger - // the 'readable' event and move on. - if (n === 0 && state.needReadable && (state.length >= state.highWaterMark || state.ended)) { - debug('read: emitReadable', state.length, state.ended); - if (state.length === 0 && state.ended) endReadable(this);else emitReadable(this); - return null; - } - - n = howMuchToRead(n, state); - - // if we've ended, and we're now clear, then finish it up. - if (n === 0 && state.ended) { - if (state.length === 0) endReadable(this); - return null; - } - - // All the actual chunk generation logic needs to be - // *below* the call to _read. The reason is that in certain - // synthetic stream cases, such as passthrough streams, _read - // may be a completely synchronous operation which may change - // the state of the read buffer, providing enough data when - // before there was *not* enough. - // - // So, the steps are: - // 1. Figure out what the state of things will be after we do - // a read from the buffer. - // - // 2. If that resulting state will trigger a _read, then call _read. - // Note that this may be asynchronous, or synchronous. Yes, it is - // deeply ugly to write APIs this way, but that still doesn't mean - // that the Readable class should behave improperly, as streams are - // designed to be sync/async agnostic. - // Take note if the _read call is sync or async (ie, if the read call - // has returned yet), so that we know whether or not it's safe to emit - // 'readable' etc. - // - // 3. Actually pull the requested chunks out of the buffer and return. - - // if we need a readable event, then we need to do some reading. - var doRead = state.needReadable; - debug('need readable', doRead); - - // if we currently have less than the highWaterMark, then also read some - if (state.length === 0 || state.length - n < state.highWaterMark) { - doRead = true; - debug('length less than watermark', doRead); - } - - // however, if we've ended, then there's no point, and if we're already - // reading, then it's unnecessary. - if (state.ended || state.reading) { - doRead = false; - debug('reading or ended', doRead); - } - - if (doRead) { - debug('do read'); - state.reading = true; - state.sync = true; - // if the length is currently zero, then we *need* a readable event. - if (state.length === 0) state.needReadable = true; - // call internal read method - this._read(state.highWaterMark); - state.sync = false; - } - - // If _read pushed data synchronously, then `reading` will be false, - // and we need to re-evaluate how much data we can return to the user. - if (doRead && !state.reading) n = howMuchToRead(nOrig, state); - - var ret; - if (n > 0) ret = fromList(n, state);else ret = null; - - if (ret === null) { - state.needReadable = true; - n = 0; - } - - state.length -= n; - - // If we have nothing in the buffer, then we want to know - // as soon as we *do* get something into the buffer. - if (state.length === 0 && !state.ended) state.needReadable = true; - - // If we tried to read() past the EOF, then emit end on the next tick. - if (nOrig !== n && state.ended && state.length === 0) endReadable(this); - - if (ret !== null) this.emit('data', ret); - - return ret; -}; - -function chunkInvalid(state, chunk) { - var er = null; - if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== null && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - return er; -} - -function onEofChunk(stream, state) { - if (state.ended) return; - if (state.decoder) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) { - state.buffer.push(chunk); - state.length += state.objectMode ? 1 : chunk.length; - } - } - state.ended = true; - - // emit 'readable' now to make sure it gets picked up. - emitReadable(stream); -} - -// Don't emit readable right away in sync mode, because this can trigger -// another read() call => stack overflow. This way, it might trigger -// a nextTick recursion warning, but that's not so bad. -function emitReadable(stream) { - var state = stream._readableState; - state.needReadable = false; - if (!state.emittedReadable) { - debug('emitReadable', state.flowing); - state.emittedReadable = true; - if (state.sync) processNextTick(emitReadable_, stream);else emitReadable_(stream); - } -} - -function emitReadable_(stream) { - debug('emit readable'); - stream.emit('readable'); - flow(stream); -} - -// at this point, the user has presumably seen the 'readable' event, -// and called read() to consume some data. that may have triggered -// in turn another _read(n) call, in which case reading = true if -// it's in progress. -// However, if we're not ended, or reading, and the length < hwm, -// then go ahead and try to read some more preemptively. -function maybeReadMore(stream, state) { - if (!state.readingMore) { - state.readingMore = true; - processNextTick(maybeReadMore_, stream, state); - } -} - -function maybeReadMore_(stream, state) { - var len = state.length; - while (!state.reading && !state.flowing && !state.ended && state.length < state.highWaterMark) { - debug('maybeReadMore read 0'); - stream.read(0); - if (len === state.length) - // didn't get any data, stop spinning. - break;else len = state.length; - } - state.readingMore = false; -} - -// abstract method. to be overridden in specific implementation classes. -// call cb(er, data) where data is <= n in length. -// for virtual (non-string, non-buffer) streams, "length" is somewhat -// arbitrary, and perhaps not very meaningful. -Readable.prototype._read = function (n) { - this.emit('error', new Error('not implemented')); -}; - -Readable.prototype.pipe = function (dest, pipeOpts) { - var src = this; - var state = this._readableState; - - switch (state.pipesCount) { - case 0: - state.pipes = dest; - break; - case 1: - state.pipes = [state.pipes, dest]; - break; - default: - state.pipes.push(dest); - break; - } - state.pipesCount += 1; - debug('pipe count=%d opts=%j', state.pipesCount, pipeOpts); - - var doEnd = (!pipeOpts || pipeOpts.end !== false) && dest !== process.stdout && dest !== process.stderr; - - var endFn = doEnd ? onend : cleanup; - if (state.endEmitted) processNextTick(endFn);else src.once('end', endFn); - - dest.on('unpipe', onunpipe); - function onunpipe(readable) { - debug('onunpipe'); - if (readable === src) { - cleanup(); - } - } - - function onend() { - debug('onend'); - dest.end(); - } - - // when the dest drains, it reduces the awaitDrain counter - // on the source. This would be more elegant with a .once() - // handler in flow(), but adding and removing repeatedly is - // too slow. - var ondrain = pipeOnDrain(src); - dest.on('drain', ondrain); - - var cleanedUp = false; - function cleanup() { - debug('cleanup'); - // cleanup event handlers once the pipe is broken - dest.removeListener('close', onclose); - dest.removeListener('finish', onfinish); - dest.removeListener('drain', ondrain); - dest.removeListener('error', onerror); - dest.removeListener('unpipe', onunpipe); - src.removeListener('end', onend); - src.removeListener('end', cleanup); - src.removeListener('data', ondata); - - cleanedUp = true; - - // if the reader is waiting for a drain event from this - // specific writer, then it would cause it to never start - // flowing again. - // So, if this is awaiting a drain, then we just call it now. - // If we don't know, then assume that we are waiting for one. - if (state.awaitDrain && (!dest._writableState || dest._writableState.needDrain)) ondrain(); - } - - src.on('data', ondata); - function ondata(chunk) { - debug('ondata'); - var ret = dest.write(chunk); - if (false === ret) { - // If the user unpiped during `dest.write()`, it is possible - // to get stuck in a permanently paused state if that write - // also returned false. - // => Check whether `dest` is still a piping destination. - if ((state.pipesCount === 1 && state.pipes === dest || state.pipesCount > 1 && indexOf(state.pipes, dest) !== -1) && !cleanedUp) { - debug('false write response, pause', src._readableState.awaitDrain); - src._readableState.awaitDrain++; - } - src.pause(); - } - } - - // if the dest has an error, then stop piping into it. - // however, don't suppress the throwing behavior for this. - function onerror(er) { - debug('onerror', er); - unpipe(); - dest.removeListener('error', onerror); - if (EElistenerCount(dest, 'error') === 0) dest.emit('error', er); - } - - // Make sure our error handler is attached before userland ones. - prependListener(dest, 'error', onerror); - - // Both close and finish should trigger unpipe, but only once. - function onclose() { - dest.removeListener('finish', onfinish); - unpipe(); - } - dest.once('close', onclose); - function onfinish() { - debug('onfinish'); - dest.removeListener('close', onclose); - unpipe(); - } - dest.once('finish', onfinish); - - function unpipe() { - debug('unpipe'); - src.unpipe(dest); - } - - // tell the dest that it's being piped to - dest.emit('pipe', src); - - // start the flow if it hasn't been started already. - if (!state.flowing) { - debug('pipe resume'); - src.resume(); - } - - return dest; -}; - -function pipeOnDrain(src) { - return function () { - var state = src._readableState; - debug('pipeOnDrain', state.awaitDrain); - if (state.awaitDrain) state.awaitDrain--; - if (state.awaitDrain === 0 && EElistenerCount(src, 'data')) { - state.flowing = true; - flow(src); - } - }; -} - -Readable.prototype.unpipe = function (dest) { - var state = this._readableState; - - // if we're not piping anywhere, then do nothing. - if (state.pipesCount === 0) return this; - - // just one destination. most common case. - if (state.pipesCount === 1) { - // passed in one, but it's not the right one. - if (dest && dest !== state.pipes) return this; - - if (!dest) dest = state.pipes; - - // got a match. - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - if (dest) dest.emit('unpipe', this); - return this; - } - - // slow case. multiple pipe destinations. - - if (!dest) { - // remove all. - var dests = state.pipes; - var len = state.pipesCount; - state.pipes = null; - state.pipesCount = 0; - state.flowing = false; - - for (var _i = 0; _i < len; _i++) { - dests[_i].emit('unpipe', this); - }return this; - } - - // try to find the right one. - var i = indexOf(state.pipes, dest); - if (i === -1) return this; - - state.pipes.splice(i, 1); - state.pipesCount -= 1; - if (state.pipesCount === 1) state.pipes = state.pipes[0]; - - dest.emit('unpipe', this); - - return this; -}; - -// set up data events if they are asked for -// Ensure readable listeners eventually get something -Readable.prototype.on = function (ev, fn) { - var res = Stream.prototype.on.call(this, ev, fn); - - // If listening to data, and it has not explicitly been paused, - // then call resume to start the flow of data on the next tick. - if (ev === 'data' && false !== this._readableState.flowing) { - this.resume(); - } - - if (ev === 'readable' && !this._readableState.endEmitted) { - var state = this._readableState; - if (!state.readableListening) { - state.readableListening = true; - state.emittedReadable = false; - state.needReadable = true; - if (!state.reading) { - processNextTick(nReadingNextTick, this); - } else if (state.length) { - emitReadable(this, state); - } - } - } - - return res; -}; -Readable.prototype.addListener = Readable.prototype.on; - -function nReadingNextTick(self) { - debug('readable nexttick read 0'); - self.read(0); -} - -// pause() and resume() are remnants of the legacy readable stream API -// If the user uses them, then switch into old mode. -Readable.prototype.resume = function () { - var state = this._readableState; - if (!state.flowing) { - debug('resume'); - state.flowing = true; - resume(this, state); - } - return this; -}; - -function resume(stream, state) { - if (!state.resumeScheduled) { - state.resumeScheduled = true; - processNextTick(resume_, stream, state); - } -} - -function resume_(stream, state) { - if (!state.reading) { - debug('resume read 0'); - stream.read(0); - } - - state.resumeScheduled = false; - stream.emit('resume'); - flow(stream); - if (state.flowing && !state.reading) stream.read(0); -} - -Readable.prototype.pause = function () { - debug('call pause flowing=%j', this._readableState.flowing); - if (false !== this._readableState.flowing) { - debug('pause'); - this._readableState.flowing = false; - this.emit('pause'); - } - return this; -}; - -function flow(stream) { - var state = stream._readableState; - debug('flow', state.flowing); - if (state.flowing) { - do { - var chunk = stream.read(); - } while (null !== chunk && state.flowing); - } -} - -// wrap an old-style stream as the async data source. -// This is *not* part of the readable stream interface. -// It is an ugly unfortunate mess of history. -Readable.prototype.wrap = function (stream) { - var state = this._readableState; - var paused = false; - - var self = this; - stream.on('end', function () { - debug('wrapped end'); - if (state.decoder && !state.ended) { - var chunk = state.decoder.end(); - if (chunk && chunk.length) self.push(chunk); - } - - self.push(null); - }); - - stream.on('data', function (chunk) { - debug('wrapped data'); - if (state.decoder) chunk = state.decoder.write(chunk); - - // don't skip over falsy values in objectMode - if (state.objectMode && (chunk === null || chunk === undefined)) return;else if (!state.objectMode && (!chunk || !chunk.length)) return; - - var ret = self.push(chunk); - if (!ret) { - paused = true; - stream.pause(); - } - }); - - // proxy all the other methods. - // important when wrapping filters and duplexes. - for (var i in stream) { - if (this[i] === undefined && typeof stream[i] === 'function') { - this[i] = function (method) { - return function () { - return stream[method].apply(stream, arguments); - }; - }(i); - } - } - - // proxy certain important events. - var events = ['error', 'close', 'destroy', 'pause', 'resume']; - forEach(events, function (ev) { - stream.on(ev, self.emit.bind(self, ev)); - }); - - // when we try to consume some more bytes, simply unpause the - // underlying stream. - self._read = function (n) { - debug('wrapped _read', n); - if (paused) { - paused = false; - stream.resume(); - } - }; - - return self; -}; - -// exposed for testing purposes only. -Readable._fromList = fromList; - -// Pluck off n bytes from an array of buffers. -// Length is the combined lengths of all the buffers in the list. -function fromList(n, state) { - var list = state.buffer; - var length = state.length; - var stringMode = !!state.decoder; - var objectMode = !!state.objectMode; - var ret; - - // nothing in the list, definitely empty. - if (list.length === 0) return null; - - if (length === 0) ret = null;else if (objectMode) ret = list.shift();else if (!n || n >= length) { - // read it all, truncate the array. - if (stringMode) ret = list.join('');else if (list.length === 1) ret = list[0];else ret = Buffer.concat(list, length); - list.length = 0; - } else { - // read just some of it. - if (n < list[0].length) { - // just take a part of the first list item. - // slice is the same for buffers and strings. - var buf = list[0]; - ret = buf.slice(0, n); - list[0] = buf.slice(n); - } else if (n === list[0].length) { - // first list is a perfect match - ret = list.shift(); - } else { - // complex case. - // we have enough to cover it, but it spans past the first buffer. - if (stringMode) ret = '';else ret = bufferShim.allocUnsafe(n); - - var c = 0; - for (var i = 0, l = list.length; i < l && c < n; i++) { - var _buf = list[0]; - var cpy = Math.min(n - c, _buf.length); - - if (stringMode) ret += _buf.slice(0, cpy);else _buf.copy(ret, c, 0, cpy); - - if (cpy < _buf.length) list[0] = _buf.slice(cpy);else list.shift(); - - c += cpy; - } - } - } - - return ret; -} - -function endReadable(stream) { - var state = stream._readableState; - - // If we get here before consuming all the bytes, then that is a - // bug in node. Should never happen. - if (state.length > 0) throw new Error('"endReadable()" called on non-empty stream'); - - if (!state.endEmitted) { - state.ended = true; - processNextTick(endReadableNT, state, stream); - } -} - -function endReadableNT(state, stream) { - // Check that we didn't get one last unshift. - if (!state.endEmitted && state.length === 0) { - state.endEmitted = true; - stream.readable = false; - stream.emit('end'); - } -} - -function forEach(xs, f) { - for (var i = 0, l = xs.length; i < l; i++) { - f(xs[i], i); - } -} - -function indexOf(xs, x) { - for (var i = 0, l = xs.length; i < l; i++) { - if (xs[i] === x) return i; - } - return -1; -} -}).call(this,require('_process')) -},{"./_stream_duplex":62,"_process":58,"buffer":45,"buffer-shims":44,"core-util-is":47,"events":50,"inherits":53,"isarray":60,"process-nextick-args":57,"string_decoder/":71,"util":41}],65:[function(require,module,exports){ -// a transform stream is a readable/writable stream where you do -// something with the data. Sometimes it's called a "filter", -// but that's not a great name for it, since that implies a thing where -// some bits pass through, and others are simply ignored. (That would -// be a valid example of a transform, of course.) -// -// While the output is causally related to the input, it's not a -// necessarily symmetric or synchronous transformation. For example, -// a zlib stream might take multiple plain-text writes(), and then -// emit a single compressed chunk some time in the future. -// -// Here's how this works: -// -// The Transform stream has all the aspects of the readable and writable -// stream classes. When you write(chunk), that calls _write(chunk,cb) -// internally, and returns false if there's a lot of pending writes -// buffered up. When you call read(), that calls _read(n) until -// there's enough pending readable data buffered up. -// -// In a transform stream, the written data is placed in a buffer. When -// _read(n) is called, it transforms the queued up data, calling the -// buffered _write cb's as it consumes chunks. If consuming a single -// written chunk would result in multiple output chunks, then the first -// outputted bit calls the readcb, and subsequent chunks just go into -// the read buffer, and will cause it to emit 'readable' if necessary. -// -// This way, back-pressure is actually determined by the reading side, -// since _read has to be called to start processing a new chunk. However, -// a pathological inflate type of transform can cause excessive buffering -// here. For example, imagine a stream where every byte of input is -// interpreted as an integer from 0-255, and then results in that many -// bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in -// 1kb of data being output. In this case, you could write a very small -// amount of input, and end up with a very large amount of output. In -// such a pathological inflating mechanism, there'd be no way to tell -// the system to stop doing the transform. A single 4MB write could -// cause the system to run out of memory. -// -// However, even in such a pathological case, only a single written chunk -// would be consumed, and then the rest would wait (un-transformed) until -// the results of the previous transformed chunk were consumed. - -'use strict'; - -module.exports = Transform; - -var Duplex = require('./_stream_duplex'); - -/*<replacement>*/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/*</replacement>*/ - -util.inherits(Transform, Duplex); - -function TransformState(stream) { - this.afterTransform = function (er, data) { - return afterTransform(stream, er, data); - }; - - this.needTransform = false; - this.transforming = false; - this.writecb = null; - this.writechunk = null; - this.writeencoding = null; -} - -function afterTransform(stream, er, data) { - var ts = stream._transformState; - ts.transforming = false; - - var cb = ts.writecb; - - if (!cb) return stream.emit('error', new Error('no writecb in Transform class')); - - ts.writechunk = null; - ts.writecb = null; - - if (data !== null && data !== undefined) stream.push(data); - - cb(er); - - var rs = stream._readableState; - rs.reading = false; - if (rs.needReadable || rs.length < rs.highWaterMark) { - stream._read(rs.highWaterMark); - } -} - -function Transform(options) { - if (!(this instanceof Transform)) return new Transform(options); - - Duplex.call(this, options); - - this._transformState = new TransformState(this); - - // when the writable side finishes, then flush out anything remaining. - var stream = this; - - // start out asking for a readable event once data is transformed. - this._readableState.needReadable = true; - - // we have implemented the _read method, and done the other things - // that Readable wants before the first _read call, so unset the - // sync guard flag. - this._readableState.sync = false; - - if (options) { - if (typeof options.transform === 'function') this._transform = options.transform; - - if (typeof options.flush === 'function') this._flush = options.flush; - } - - this.once('prefinish', function () { - if (typeof this._flush === 'function') this._flush(function (er) { - done(stream, er); - });else done(stream); - }); -} - -Transform.prototype.push = function (chunk, encoding) { - this._transformState.needTransform = false; - return Duplex.prototype.push.call(this, chunk, encoding); -}; - -// This is the part where you do stuff! -// override this function in implementation classes. -// 'chunk' is an input chunk. -// -// Call `push(newChunk)` to pass along transformed output -// to the readable side. You may call 'push' zero or more times. -// -// Call `cb(err)` when you are done with this chunk. If you pass -// an error, then that'll put the hurt on the whole operation. If you -// never call cb(), then you'll never get another chunk. -Transform.prototype._transform = function (chunk, encoding, cb) { - throw new Error('Not implemented'); -}; - -Transform.prototype._write = function (chunk, encoding, cb) { - var ts = this._transformState; - ts.writecb = cb; - ts.writechunk = chunk; - ts.writeencoding = encoding; - if (!ts.transforming) { - var rs = this._readableState; - if (ts.needTransform || rs.needReadable || rs.length < rs.highWaterMark) this._read(rs.highWaterMark); - } -}; - -// Doesn't matter what the args are here. -// _transform does all the work. -// That we got here means that the readable side wants more data. -Transform.prototype._read = function (n) { - var ts = this._transformState; - - if (ts.writechunk !== null && ts.writecb && !ts.transforming) { - ts.transforming = true; - this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); - } else { - // mark that we need a transform, so that any data that comes in - // will get processed, now that we've asked for it. - ts.needTransform = true; - } -}; - -function done(stream, er) { - if (er) return stream.emit('error', er); - - // if there's nothing in the write buffer, then that means - // that nothing more will ever be provided - var ws = stream._writableState; - var ts = stream._transformState; - - if (ws.length) throw new Error('Calling transform done when ws.length != 0'); - - if (ts.transforming) throw new Error('Calling transform done when still transforming'); - - return stream.push(null); -} -},{"./_stream_duplex":62,"core-util-is":47,"inherits":53}],66:[function(require,module,exports){ -(function (process){ -// A bit simpler than readable streams. -// Implement an async ._write(chunk, encoding, cb), and it'll handle all -// the drain event emission and buffering. - -'use strict'; - -module.exports = Writable; - -/*<replacement>*/ -var processNextTick = require('process-nextick-args'); -/*</replacement>*/ - -/*<replacement>*/ -var asyncWrite = !process.browser && ['v0.10', 'v0.9.'].indexOf(process.version.slice(0, 5)) > -1 ? setImmediate : processNextTick; -/*</replacement>*/ - -Writable.WritableState = WritableState; - -/*<replacement>*/ -var util = require('core-util-is'); -util.inherits = require('inherits'); -/*</replacement>*/ - -/*<replacement>*/ -var internalUtil = { - deprecate: require('util-deprecate') -}; -/*</replacement>*/ - -/*<replacement>*/ -var Stream; -(function () { - try { - Stream = require('st' + 'ream'); - } catch (_) {} finally { - if (!Stream) Stream = require('events').EventEmitter; - } -})(); -/*</replacement>*/ - -var Buffer = require('buffer').Buffer; -/*<replacement>*/ -var bufferShim = require('buffer-shims'); -/*</replacement>*/ - -util.inherits(Writable, Stream); - -function nop() {} - -function WriteReq(chunk, encoding, cb) { - this.chunk = chunk; - this.encoding = encoding; - this.callback = cb; - this.next = null; -} - -var Duplex; -function WritableState(options, stream) { - Duplex = Duplex || require('./_stream_duplex'); - - options = options || {}; - - // object stream flag to indicate whether or not this stream - // contains buffers or objects. - this.objectMode = !!options.objectMode; - - if (stream instanceof Duplex) this.objectMode = this.objectMode || !!options.writableObjectMode; - - // the point at which write() starts returning false - // Note: 0 is a valid value, means that we always return false if - // the entire buffer is not flushed immediately on write() - var hwm = options.highWaterMark; - var defaultHwm = this.objectMode ? 16 : 16 * 1024; - this.highWaterMark = hwm || hwm === 0 ? hwm : defaultHwm; - - // cast to ints. - this.highWaterMark = ~ ~this.highWaterMark; - - this.needDrain = false; - // at the start of calling end() - this.ending = false; - // when end() has been called, and returned - this.ended = false; - // when 'finish' is emitted - this.finished = false; - - // should we decode strings into buffers before passing to _write? - // this is here so that some node-core streams can optimize string - // handling at a lower level. - var noDecode = options.decodeStrings === false; - this.decodeStrings = !noDecode; - - // Crypto is kind of old and crusty. Historically, its default string - // encoding is 'binary' so we have to make this configurable. - // Everything else in the universe uses 'utf8', though. - this.defaultEncoding = options.defaultEncoding || 'utf8'; - - // not an actual buffer we keep track of, but a measurement - // of how much we're waiting to get pushed to some underlying - // socket or file. - this.length = 0; - - // a flag to see when we're in the middle of a write. - this.writing = false; - - // when true all writes will be buffered until .uncork() call - this.corked = 0; - - // a flag to be able to tell if the onwrite cb is called immediately, - // or on a later tick. We set this to true at first, because any - // actions that shouldn't happen until "later" should generally also - // not happen before the first write call. - this.sync = true; - - // a flag to know if we're processing previously buffered items, which - // may call the _write() callback in the same tick, so that we don't - // end up in an overlapped onwrite situation. - this.bufferProcessing = false; - - // the callback that's passed to _write(chunk,cb) - this.onwrite = function (er) { - onwrite(stream, er); - }; - - // the callback that the user supplies to write(chunk,encoding,cb) - this.writecb = null; - - // the amount that is being written when _write is called. - this.writelen = 0; - - this.bufferedRequest = null; - this.lastBufferedRequest = null; - - // number of pending user-supplied write callbacks - // this must be 0 before 'finish' can be emitted - this.pendingcb = 0; - - // emit prefinish if the only thing we're waiting for is _write cbs - // This is relevant for synchronous Transform streams - this.prefinished = false; - - // True if the error was already emitted and should not be thrown again - this.errorEmitted = false; - - // count buffered requests - this.bufferedRequestCount = 0; - - // allocate the first CorkedRequest, there is always - // one allocated and free to use, and we maintain at most two - this.corkedRequestsFree = new CorkedRequest(this); -} - -WritableState.prototype.getBuffer = function writableStateGetBuffer() { - var current = this.bufferedRequest; - var out = []; - while (current) { - out.push(current); - current = current.next; - } - return out; -}; - -(function () { - try { - Object.defineProperty(WritableState.prototype, 'buffer', { - get: internalUtil.deprecate(function () { - return this.getBuffer(); - }, '_writableState.buffer is deprecated. Use _writableState.getBuffer ' + 'instead.') - }); - } catch (_) {} -})(); - -var Duplex; -function Writable(options) { - Duplex = Duplex || require('./_stream_duplex'); - - // Writable ctor is applied to Duplexes, though they're not - // instanceof Writable, they're instanceof Readable. - if (!(this instanceof Writable) && !(this instanceof Duplex)) return new Writable(options); - - this._writableState = new WritableState(options, this); - - // legacy. - this.writable = true; - - if (options) { - if (typeof options.write === 'function') this._write = options.write; - - if (typeof options.writev === 'function') this._writev = options.writev; - } - - Stream.call(this); -} - -// Otherwise people can pipe Writable streams, which is just wrong. -Writable.prototype.pipe = function () { - this.emit('error', new Error('Cannot pipe, not readable')); -}; - -function writeAfterEnd(stream, cb) { - var er = new Error('write after end'); - // TODO: defer error events consistently everywhere, not just the cb - stream.emit('error', er); - processNextTick(cb, er); -} - -// If we get something that is not a buffer, string, null, or undefined, -// and we're not in objectMode, then that's an error. -// Otherwise stream chunks are all considered to be of length=1, and the -// watermarks determine how many objects to keep in the buffer, rather than -// how many bytes or characters. -function validChunk(stream, state, chunk, cb) { - var valid = true; - var er = false; - // Always throw error if a null is written - // if we are not in object mode then throw - // if it is not a buffer, string, or undefined. - if (chunk === null) { - er = new TypeError('May not write null values to stream'); - } else if (!Buffer.isBuffer(chunk) && typeof chunk !== 'string' && chunk !== undefined && !state.objectMode) { - er = new TypeError('Invalid non-string/buffer chunk'); - } - if (er) { - stream.emit('error', er); - processNextTick(cb, er); - valid = false; - } - return valid; -} - -Writable.prototype.write = function (chunk, encoding, cb) { - var state = this._writableState; - var ret = false; - - if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } - - if (Buffer.isBuffer(chunk)) encoding = 'buffer';else if (!encoding) encoding = state.defaultEncoding; - - if (typeof cb !== 'function') cb = nop; - - if (state.ended) writeAfterEnd(this, cb);else if (validChunk(this, state, chunk, cb)) { - state.pendingcb++; - ret = writeOrBuffer(this, state, chunk, encoding, cb); - } - - return ret; -}; - -Writable.prototype.cork = function () { - var state = this._writableState; - - state.corked++; -}; - -Writable.prototype.uncork = function () { - var state = this._writableState; - - if (state.corked) { - state.corked--; - - if (!state.writing && !state.corked && !state.finished && !state.bufferProcessing && state.bufferedRequest) clearBuffer(this, state); - } -}; - -Writable.prototype.setDefaultEncoding = function setDefaultEncoding(encoding) { - // node::ParseEncoding() requires lower case. - if (typeof encoding === 'string') encoding = encoding.toLowerCase(); - if (!(['hex', 'utf8', 'utf-8', 'ascii', 'binary', 'base64', 'ucs2', 'ucs-2', 'utf16le', 'utf-16le', 'raw'].indexOf((encoding + '').toLowerCase()) > -1)) throw new TypeError('Unknown encoding: ' + encoding); - this._writableState.defaultEncoding = encoding; - return this; -}; - -function decodeChunk(state, chunk, encoding) { - if (!state.objectMode && state.decodeStrings !== false && typeof chunk === 'string') { - chunk = bufferShim.from(chunk, encoding); - } - return chunk; -} - -// if we're already writing something, then just put this -// in the queue, and wait our turn. Otherwise, call _write -// If we return false, then we need a drain event, so set that flag. -function writeOrBuffer(stream, state, chunk, encoding, cb) { - chunk = decodeChunk(state, chunk, encoding); - - if (Buffer.isBuffer(chunk)) encoding = 'buffer'; - var len = state.objectMode ? 1 : chunk.length; - - state.length += len; - - var ret = state.length < state.highWaterMark; - // we must ensure that previous needDrain will not be reset to false. - if (!ret) state.needDrain = true; - - if (state.writing || state.corked) { - var last = state.lastBufferedRequest; - state.lastBufferedRequest = new WriteReq(chunk, encoding, cb); - if (last) { - last.next = state.lastBufferedRequest; - } else { - state.bufferedRequest = state.lastBufferedRequest; - } - state.bufferedRequestCount += 1; - } else { - doWrite(stream, state, false, len, chunk, encoding, cb); - } - - return ret; -} - -function doWrite(stream, state, writev, len, chunk, encoding, cb) { - state.writelen = len; - state.writecb = cb; - state.writing = true; - state.sync = true; - if (writev) stream._writev(chunk, state.onwrite);else stream._write(chunk, encoding, state.onwrite); - state.sync = false; -} - -function onwriteError(stream, state, sync, er, cb) { - --state.pendingcb; - if (sync) processNextTick(cb, er);else cb(er); - - stream._writableState.errorEmitted = true; - stream.emit('error', er); -} - -function onwriteStateUpdate(state) { - state.writing = false; - state.writecb = null; - state.length -= state.writelen; - state.writelen = 0; -} - -function onwrite(stream, er) { - var state = stream._writableState; - var sync = state.sync; - var cb = state.writecb; - - onwriteStateUpdate(state); - - if (er) onwriteError(stream, state, sync, er, cb);else { - // Check if we're actually ready to finish, but don't emit yet - var finished = needFinish(state); - - if (!finished && !state.corked && !state.bufferProcessing && state.bufferedRequest) { - clearBuffer(stream, state); - } - - if (sync) { - /*<replacement>*/ - asyncWrite(afterWrite, stream, state, finished, cb); - /*</replacement>*/ - } else { - afterWrite(stream, state, finished, cb); - } - } -} - -function afterWrite(stream, state, finished, cb) { - if (!finished) onwriteDrain(stream, state); - state.pendingcb--; - cb(); - finishMaybe(stream, state); -} - -// Must force callback to be called on nextTick, so that we don't -// emit 'drain' before the write() consumer gets the 'false' return -// value, and has a chance to attach a 'drain' listener. -function onwriteDrain(stream, state) { - if (state.length === 0 && state.needDrain) { - state.needDrain = false; - stream.emit('drain'); - } -} - -// if there's something in the buffer waiting, then process it -function clearBuffer(stream, state) { - state.bufferProcessing = true; - var entry = state.bufferedRequest; - - if (stream._writev && entry && entry.next) { - // Fast case, write everything using _writev() - var l = state.bufferedRequestCount; - var buffer = new Array(l); - var holder = state.corkedRequestsFree; - holder.entry = entry; - - var count = 0; - while (entry) { - buffer[count] = entry; - entry = entry.next; - count += 1; - } - - doWrite(stream, state, true, state.length, buffer, '', holder.finish); - - // doWrite is almost always async, defer these to save a bit of time - // as the hot path ends with doWrite - state.pendingcb++; - state.lastBufferedRequest = null; - if (holder.next) { - state.corkedRequestsFree = holder.next; - holder.next = null; - } else { - state.corkedRequestsFree = new CorkedRequest(state); - } - } else { - // Slow case, write chunks one-by-one - while (entry) { - var chunk = entry.chunk; - var encoding = entry.encoding; - var cb = entry.callback; - var len = state.objectMode ? 1 : chunk.length; - - doWrite(stream, state, false, len, chunk, encoding, cb); - entry = entry.next; - // if we didn't call the onwrite immediately, then - // it means that we need to wait until it does. - // also, that means that the chunk and cb are currently - // being processed, so move the buffer counter past them. - if (state.writing) { - break; - } - } - - if (entry === null) state.lastBufferedRequest = null; - } - - state.bufferedRequestCount = 0; - state.bufferedRequest = entry; - state.bufferProcessing = false; -} - -Writable.prototype._write = function (chunk, encoding, cb) { - cb(new Error('not implemented')); -}; - -Writable.prototype._writev = null; - -Writable.prototype.end = function (chunk, encoding, cb) { - var state = this._writableState; - - if (typeof chunk === 'function') { - cb = chunk; - chunk = null; - encoding = null; - } else if (typeof encoding === 'function') { - cb = encoding; - encoding = null; - } - - if (chunk !== null && chunk !== undefined) this.write(chunk, encoding); - - // .end() fully uncorks - if (state.corked) { - state.corked = 1; - this.uncork(); - } - - // ignore unnecessary end() calls. - if (!state.ending && !state.finished) endWritable(this, state, cb); -}; - -function needFinish(state) { - return state.ending && state.length === 0 && state.bufferedRequest === null && !state.finished && !state.writing; -} - -function prefinish(stream, state) { - if (!state.prefinished) { - state.prefinished = true; - stream.emit('prefinish'); - } -} - -function finishMaybe(stream, state) { - var need = needFinish(state); - if (need) { - if (state.pendingcb === 0) { - prefinish(stream, state); - state.finished = true; - stream.emit('finish'); - } else { - prefinish(stream, state); - } - } - return need; -} - -function endWritable(stream, state, cb) { - state.ending = true; - finishMaybe(stream, state); - if (cb) { - if (state.finished) processNextTick(cb);else stream.once('finish', cb); - } - state.ended = true; - stream.writable = false; -} - -// It seems a linked list but it is not -// there will be only 2 of these for each stream -function CorkedRequest(state) { - var _this = this; - - this.next = null; - this.entry = null; - - this.finish = function (err) { - var entry = _this.entry; - _this.entry = null; - while (entry) { - var cb = entry.callback; - state.pendingcb--; - cb(err); - entry = entry.next; - } - if (state.corkedRequestsFree) { - state.corkedRequestsFree.next = _this; - } else { - state.corkedRequestsFree = _this; - } - }; -} -}).call(this,require('_process')) -},{"./_stream_duplex":62,"_process":58,"buffer":45,"buffer-shims":44,"core-util-is":47,"events":50,"inherits":53,"process-nextick-args":57,"util-deprecate":73}],67:[function(require,module,exports){ -module.exports = require("./lib/_stream_passthrough.js") - -},{"./lib/_stream_passthrough.js":63}],68:[function(require,module,exports){ -(function (process){ -var Stream = (function (){ - try { - return require('st' + 'ream'); // hack to fix a circular dependency issue when used with browserify - } catch(_){} -}()); -exports = module.exports = require('./lib/_stream_readable.js'); -exports.Stream = Stream || exports; -exports.Readable = exports; -exports.Writable = require('./lib/_stream_writable.js'); -exports.Duplex = require('./lib/_stream_duplex.js'); -exports.Transform = require('./lib/_stream_transform.js'); -exports.PassThrough = require('./lib/_stream_passthrough.js'); - -if (!process.browser && process.env.READABLE_STREAM === 'disable' && Stream) { - module.exports = Stream; -} - -}).call(this,require('_process')) -},{"./lib/_stream_duplex.js":62,"./lib/_stream_passthrough.js":63,"./lib/_stream_readable.js":64,"./lib/_stream_transform.js":65,"./lib/_stream_writable.js":66,"_process":58}],69:[function(require,module,exports){ -module.exports = require("./lib/_stream_transform.js") - -},{"./lib/_stream_transform.js":65}],70:[function(require,module,exports){ -module.exports = require("./lib/_stream_writable.js") - -},{"./lib/_stream_writable.js":66}],71:[function(require,module,exports){ +},{"events":50,"inherits":56,"readable-stream/duplex.js":70,"readable-stream/passthrough.js":79,"readable-stream/readable.js":80,"readable-stream/transform.js":81,"readable-stream/writable.js":82}],85:[function(require,module,exports){ // Copyright Joyent, Inc. and other Node contributors. // // Permission is hereby granted, free of charge, to any person obtaining a @@ -12236,249 +17044,361 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. -var Buffer = require('buffer').Buffer; +'use strict'; -var isBufferEncoding = Buffer.isEncoding - || function(encoding) { - switch (encoding && encoding.toLowerCase()) { - case 'hex': case 'utf8': case 'utf-8': case 'ascii': case 'binary': case 'base64': case 'ucs2': case 'ucs-2': case 'utf16le': case 'utf-16le': case 'raw': return true; - default: return false; - } - } +/*<replacement>*/ +var Buffer = require('safe-buffer').Buffer; +/*</replacement>*/ -function assertEncoding(encoding) { - if (encoding && !isBufferEncoding(encoding)) { - throw new Error('Unknown encoding: ' + encoding); +var isEncoding = Buffer.isEncoding || function (encoding) { + encoding = '' + encoding; + switch (encoding && encoding.toLowerCase()) { + case 'hex':case 'utf8':case 'utf-8':case 'ascii':case 'binary':case 'base64':case 'ucs2':case 'ucs-2':case 'utf16le':case 'utf-16le':case 'raw': + return true; + default: + return false; } +}; + +function _normalizeEncoding(enc) { + if (!enc) return 'utf8'; + var retried; + while (true) { + switch (enc) { + case 'utf8': + case 'utf-8': + return 'utf8'; + case 'ucs2': + case 'ucs-2': + case 'utf16le': + case 'utf-16le': + return 'utf16le'; + case 'latin1': + case 'binary': + return 'latin1'; + case 'base64': + case 'ascii': + case 'hex': + return enc; + default: + if (retried) return; // undefined + enc = ('' + enc).toLowerCase(); + retried = true; + } + } +}; + +// Do not cache `Buffer.isEncoding` when checking encoding names as some +// modules monkey-patch it to support additional encodings +function normalizeEncoding(enc) { + var nenc = _normalizeEncoding(enc); + if (typeof nenc !== 'string' && (Buffer.isEncoding === isEncoding || !isEncoding(enc))) throw new Error('Unknown encoding: ' + enc); + return nenc || enc; } // StringDecoder provides an interface for efficiently splitting a series of // buffers into a series of JS strings without breaking apart multi-byte -// characters. CESU-8 is handled as part of the UTF-8 encoding. -// -// @TODO Handling all encodings inside a single object makes it very difficult -// to reason about this code, so it should be split up in the future. -// @TODO There should be a utf8-strict encoding that rejects invalid UTF-8 code -// points as used by CESU-8. -var StringDecoder = exports.StringDecoder = function(encoding) { - this.encoding = (encoding || 'utf8').toLowerCase().replace(/[-_]/, ''); - assertEncoding(encoding); +// characters. +exports.StringDecoder = StringDecoder; +function StringDecoder(encoding) { + this.encoding = normalizeEncoding(encoding); + var nb; switch (this.encoding) { - case 'utf8': - // CESU-8 represents each of Surrogate Pair by 3-bytes - this.surrogateSize = 3; - break; - case 'ucs2': case 'utf16le': - // UTF-16 represents each of Surrogate Pair by 2-bytes - this.surrogateSize = 2; - this.detectIncompleteChar = utf16DetectIncompleteChar; + this.text = utf16Text; + this.end = utf16End; + nb = 4; + break; + case 'utf8': + this.fillLast = utf8FillLast; + nb = 4; break; case 'base64': - // Base-64 stores 3 bytes in 4 chars, and pads the remainder. - this.surrogateSize = 3; - this.detectIncompleteChar = base64DetectIncompleteChar; + this.text = base64Text; + this.end = base64End; + nb = 3; break; default: - this.write = passThroughWrite; + this.write = simpleWrite; + this.end = simpleEnd; return; } + this.lastNeed = 0; + this.lastTotal = 0; + this.lastChar = Buffer.allocUnsafe(nb); +} - // Enough space to store all bytes of a single character. UTF-8 needs 4 - // bytes, but CESU-8 may require up to 6 (3 bytes per surrogate). - this.charBuffer = new Buffer(6); - // Number of bytes received for the current incomplete multi-byte character. - this.charReceived = 0; - // Number of bytes expected for the current incomplete multi-byte character. - this.charLength = 0; +StringDecoder.prototype.write = function (buf) { + if (buf.length === 0) return ''; + var r; + var i; + if (this.lastNeed) { + r = this.fillLast(buf); + if (r === undefined) return ''; + i = this.lastNeed; + this.lastNeed = 0; + } else { + i = 0; + } + if (i < buf.length) return r ? r + this.text(buf, i) : this.text(buf, i); + return r || ''; }; +StringDecoder.prototype.end = utf8End; -// write decodes the given buffer and returns it as JS string that is -// guaranteed to not contain any partial multi-byte characters. Any partial -// character found at the end of the buffer is buffered up, and will be -// returned when calling write again with the remaining bytes. -// -// Note: Converting a Buffer containing an orphan surrogate to a String -// currently works, but converting a String to a Buffer (via `new Buffer`, or -// Buffer#write) will replace incomplete surrogates with the unicode -// replacement character. See https://codereview.chromium.org/121173009/ . -StringDecoder.prototype.write = function(buffer) { - var charStr = ''; - // if our last write ended with an incomplete multibyte character - while (this.charLength) { - // determine how many remaining bytes this buffer has to offer for this char - var available = (buffer.length >= this.charLength - this.charReceived) ? - this.charLength - this.charReceived : - buffer.length; +// Returns only complete characters in a Buffer +StringDecoder.prototype.text = utf8Text; - // add the new bytes to the char buffer - buffer.copy(this.charBuffer, this.charReceived, 0, available); - this.charReceived += available; - - if (this.charReceived < this.charLength) { - // still not enough chars in this buffer? wait for more ... - return ''; - } - - // remove bytes belonging to the current character from the buffer - buffer = buffer.slice(available, buffer.length); - - // get the character that was split - charStr = this.charBuffer.slice(0, this.charLength).toString(this.encoding); - - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - var charCode = charStr.charCodeAt(charStr.length - 1); - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - this.charLength += this.surrogateSize; - charStr = ''; - continue; - } - this.charReceived = this.charLength = 0; - - // if there are no more bytes in this buffer, just emit our char - if (buffer.length === 0) { - return charStr; - } - break; +// Attempts to complete a partial non-UTF-8 character using bytes from a Buffer +StringDecoder.prototype.fillLast = function (buf) { + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); } - - // determine and set charLength / charReceived - this.detectIncompleteChar(buffer); - - var end = buffer.length; - if (this.charLength) { - // buffer the incomplete character bytes we got - buffer.copy(this.charBuffer, 0, buffer.length - this.charReceived, end); - end -= this.charReceived; - } - - charStr += buffer.toString(this.encoding, 0, end); - - var end = charStr.length - 1; - var charCode = charStr.charCodeAt(end); - // CESU-8: lead surrogate (D800-DBFF) is also the incomplete character - if (charCode >= 0xD800 && charCode <= 0xDBFF) { - var size = this.surrogateSize; - this.charLength += size; - this.charReceived += size; - this.charBuffer.copy(this.charBuffer, size, 0, size); - buffer.copy(this.charBuffer, 0, 0, size); - return charStr.substring(0, end); - } - - // or just emit the charStr - return charStr; + buf.copy(this.lastChar, this.lastTotal - this.lastNeed, 0, buf.length); + this.lastNeed -= buf.length; }; -// detectIncompleteChar determines if there is an incomplete UTF-8 character at -// the end of the given buffer. If so, it sets this.charLength to the byte -// length that character, and sets this.charReceived to the number of bytes -// that are available for this character. -StringDecoder.prototype.detectIncompleteChar = function(buffer) { - // determine how many bytes we have to check at the end of this buffer - var i = (buffer.length >= 3) ? 3 : buffer.length; +// Checks the type of a UTF-8 byte, whether it's ASCII, a leading byte, or a +// continuation byte. If an invalid byte is detected, -2 is returned. +function utf8CheckByte(byte) { + if (byte <= 0x7F) return 0;else if (byte >> 5 === 0x06) return 2;else if (byte >> 4 === 0x0E) return 3;else if (byte >> 3 === 0x1E) return 4; + return byte >> 6 === 0x02 ? -1 : -2; +} - // Figure out if one of the last i bytes of our buffer announces an - // incomplete char. - for (; i > 0; i--) { - var c = buffer[buffer.length - i]; - - // See http://en.wikipedia.org/wiki/UTF-8#Description - - // 110XXXXX - if (i == 1 && c >> 5 == 0x06) { - this.charLength = 2; - break; +// Checks at most 3 bytes at the end of a Buffer in order to detect an +// incomplete multi-byte UTF-8 character. The total number of bytes (2, 3, or 4) +// needed to complete the UTF-8 character (if applicable) are returned. +function utf8CheckIncomplete(self, buf, i) { + var j = buf.length - 1; + if (j < i) return 0; + var nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 1; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) self.lastNeed = nb - 2; + return nb; + } + if (--j < i || nb === -2) return 0; + nb = utf8CheckByte(buf[j]); + if (nb >= 0) { + if (nb > 0) { + if (nb === 2) nb = 0;else self.lastNeed = nb - 3; } + return nb; + } + return 0; +} - // 1110XXXX - if (i <= 2 && c >> 4 == 0x0E) { - this.charLength = 3; - break; +// Validates as many continuation bytes for a multi-byte UTF-8 character as +// needed or are available. If we see a non-continuation byte where we expect +// one, we "replace" the validated continuation bytes we've seen so far with +// a single UTF-8 replacement character ('\ufffd'), to match v8's UTF-8 decoding +// behavior. The continuation byte check is included three times in the case +// where all of the continuation bytes for a character exist in the same buffer. +// It is also done this way as a slight performance increase instead of using a +// loop. +function utf8CheckExtraBytes(self, buf, p) { + if ((buf[0] & 0xC0) !== 0x80) { + self.lastNeed = 0; + return '\ufffd'; + } + if (self.lastNeed > 1 && buf.length > 1) { + if ((buf[1] & 0xC0) !== 0x80) { + self.lastNeed = 1; + return '\ufffd'; } - - // 11110XXX - if (i <= 3 && c >> 3 == 0x1E) { - this.charLength = 4; - break; + if (self.lastNeed > 2 && buf.length > 2) { + if ((buf[2] & 0xC0) !== 0x80) { + self.lastNeed = 2; + return '\ufffd'; + } } } - this.charReceived = i; -}; +} -StringDecoder.prototype.end = function(buffer) { - var res = ''; - if (buffer && buffer.length) - res = this.write(buffer); - - if (this.charReceived) { - var cr = this.charReceived; - var buf = this.charBuffer; - var enc = this.encoding; - res += buf.slice(0, cr).toString(enc); +// Attempts to complete a multi-byte UTF-8 character using bytes from a Buffer. +function utf8FillLast(buf) { + var p = this.lastTotal - this.lastNeed; + var r = utf8CheckExtraBytes(this, buf, p); + if (r !== undefined) return r; + if (this.lastNeed <= buf.length) { + buf.copy(this.lastChar, p, 0, this.lastNeed); + return this.lastChar.toString(this.encoding, 0, this.lastTotal); } + buf.copy(this.lastChar, p, 0, buf.length); + this.lastNeed -= buf.length; +} - return res; +// Returns all complete UTF-8 characters in a Buffer. If the Buffer ended on a +// partial character, the character's bytes are buffered until the required +// number of bytes are available. +function utf8Text(buf, i) { + var total = utf8CheckIncomplete(this, buf, i); + if (!this.lastNeed) return buf.toString('utf8', i); + this.lastTotal = total; + var end = buf.length - (total - this.lastNeed); + buf.copy(this.lastChar, 0, end); + return buf.toString('utf8', i, end); +} + +// For UTF-8, a replacement character is added when ending on a partial +// character. +function utf8End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + '\ufffd'; + return r; +} + +// UTF-16LE typically needs two bytes per character, but even if we have an even +// number of bytes available, we need to check if we end on a leading/high +// surrogate. In that case, we need to wait for the next two bytes in order to +// decode the last character properly. +function utf16Text(buf, i) { + if ((buf.length - i) % 2 === 0) { + var r = buf.toString('utf16le', i); + if (r) { + var c = r.charCodeAt(r.length - 1); + if (c >= 0xD800 && c <= 0xDBFF) { + this.lastNeed = 2; + this.lastTotal = 4; + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + return r.slice(0, -1); + } + } + return r; + } + this.lastNeed = 1; + this.lastTotal = 2; + this.lastChar[0] = buf[buf.length - 1]; + return buf.toString('utf16le', i, buf.length - 1); +} + +// For UTF-16LE we do not explicitly append special replacement characters if we +// end on a partial character, we simply let v8 handle that. +function utf16End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) { + var end = this.lastTotal - this.lastNeed; + return r + this.lastChar.toString('utf16le', 0, end); + } + return r; +} + +function base64Text(buf, i) { + var n = (buf.length - i) % 3; + if (n === 0) return buf.toString('base64', i); + this.lastNeed = 3 - n; + this.lastTotal = 3; + if (n === 1) { + this.lastChar[0] = buf[buf.length - 1]; + } else { + this.lastChar[0] = buf[buf.length - 2]; + this.lastChar[1] = buf[buf.length - 1]; + } + return buf.toString('base64', i, buf.length - n); +} + +function base64End(buf) { + var r = buf && buf.length ? this.write(buf) : ''; + if (this.lastNeed) return r + this.lastChar.toString('base64', 0, 3 - this.lastNeed); + return r; +} + +// Pass bytes on through for single-byte encodings (e.g. ascii, latin1, hex) +function simpleWrite(buf) { + return buf.toString(this.encoding); +} + +function simpleEnd(buf) { + return buf && buf.length ? this.write(buf) : ''; +} +},{"safe-buffer":83}],86:[function(require,module,exports){ +(function (setImmediate,clearImmediate){ +var nextTick = require('process/browser.js').nextTick; +var apply = Function.prototype.apply; +var slice = Array.prototype.slice; +var immediateIds = {}; +var nextImmediateId = 0; + +// DOM APIs, for completeness + +exports.setTimeout = function() { + return new Timeout(apply.call(setTimeout, window, arguments), clearTimeout); +}; +exports.setInterval = function() { + return new Timeout(apply.call(setInterval, window, arguments), clearInterval); +}; +exports.clearTimeout = +exports.clearInterval = function(timeout) { timeout.close(); }; + +function Timeout(id, clearFn) { + this._id = id; + this._clearFn = clearFn; +} +Timeout.prototype.unref = Timeout.prototype.ref = function() {}; +Timeout.prototype.close = function() { + this._clearFn.call(window, this._id); }; -function passThroughWrite(buffer) { - return buffer.toString(this.encoding); -} +// Does not start the time, just sets up the members needed. +exports.enroll = function(item, msecs) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = msecs; +}; -function utf16DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 2; - this.charLength = this.charReceived ? 2 : 0; -} +exports.unenroll = function(item) { + clearTimeout(item._idleTimeoutId); + item._idleTimeout = -1; +}; -function base64DetectIncompleteChar(buffer) { - this.charReceived = buffer.length % 3; - this.charLength = this.charReceived ? 3 : 0; -} +exports._unrefActive = exports.active = function(item) { + clearTimeout(item._idleTimeoutId); -},{"buffer":45}],72:[function(require,module,exports){ + var msecs = item._idleTimeout; + if (msecs >= 0) { + item._idleTimeoutId = setTimeout(function onTimeout() { + if (item._onTimeout) + item._onTimeout(); + }, msecs); + } +}; -/** - * Expose `toIsoString`. - */ +// That's not how node.js implements it but the exposed api is the same. +exports.setImmediate = typeof setImmediate === "function" ? setImmediate : function(fn) { + var id = nextImmediateId++; + var args = arguments.length < 2 ? false : slice.call(arguments, 1); -module.exports = toIsoString; + immediateIds[id] = true; + nextTick(function onNextTick() { + if (immediateIds[id]) { + // fn.call() is faster so we optimize for the common use-case + // @see http://jsperf.com/call-apply-segu + if (args) { + fn.apply(null, args); + } else { + fn.call(null); + } + // Prevent ids from leaking + exports.clearImmediate(id); + } + }); -/** - * Turn a `date` into an ISO string. - * - * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString - * - * @param {Date} date - * @return {String} - */ + return id; +}; -function toIsoString (date) { - return date.getUTCFullYear() - + '-' + pad(date.getUTCMonth() + 1) - + '-' + pad(date.getUTCDate()) - + 'T' + pad(date.getUTCHours()) - + ':' + pad(date.getUTCMinutes()) - + ':' + pad(date.getUTCSeconds()) - + '.' + String((date.getUTCMilliseconds()/1000).toFixed(3)).slice(2, 5) - + 'Z'; -} - - -/** - * Pad a `number` with a ten's place zero. - * - * @param {Number} number - * @return {String} - */ - -function pad (number) { - var n = number.toString(); - return n.length === 1 ? '0' + n : n; -} -},{}],73:[function(require,module,exports){ +exports.clearImmediate = typeof clearImmediate === "function" ? clearImmediate : function(id) { + delete immediateIds[id]; +}; +}).call(this,require("timers").setImmediate,require("timers").clearImmediate) +},{"process/browser.js":69,"timers":86}],87:[function(require,module,exports){ (function (global){ /** @@ -12549,14 +17469,14 @@ } }).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{}],74:[function(require,module,exports){ +},{}],88:[function(require,module,exports){ module.exports = function isBuffer(arg) { return arg && typeof arg === 'object' && typeof arg.copy === 'function' && typeof arg.fill === 'function' && typeof arg.readUInt8 === 'function'; } -},{}],75:[function(require,module,exports){ +},{}],89:[function(require,module,exports){ (function (process,global){ // Copyright Joyent, Inc. and other Node contributors. // @@ -13146,4 +18066,11 @@ } }).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./support/isBuffer":74,"_process":58,"inherits":53}]},{},[1]); +},{"./support/isBuffer":88,"_process":69,"inherits":56}],90:[function(require,module,exports){ +module.exports={ + "name": "mocha", + "version": "6.1.4", + "homepage": "https://mochajs.org/", + "notifyLogo": "https://ibin.co/4QuRuGjXvl36.png" +} +},{}]},{},[1]);
diff --git a/third_party/polymer/v1_0/bower.json b/third_party/polymer/v1_0/bower.json index 427434b..eb44683d 100644 --- a/third_party/polymer/v1_0/bower.json +++ b/third_party/polymer/v1_0/bower.json
@@ -33,7 +33,6 @@ "neon-animation": "PolymerElements/neon-animation#2.1.0", "paper-behaviors": "PolymerElements/paper-behaviors#2.1.0", "paper-button": "PolymerElements/paper-button#2.0.0", - "paper-fab": "PolymerElements/paper-fab#2.0.0", "paper-icon-button": "PolymerElements/paper-icon-button#2.1.0", "paper-input": "PolymerElements/paper-input#2.2.2", "paper-progress": "PolymerElements/paper-progress#2.0.1",
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/BUILD.gn b/third_party/polymer/v1_0/components-chromium/paper-fab/BUILD.gn deleted file mode 100644 index 5642052..0000000 --- a/third_party/polymer/v1_0/components-chromium/paper-fab/BUILD.gn +++ /dev/null
@@ -1,14 +0,0 @@ -# Copyright 2019 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. -# -# NOTE: Created with generate_gn.py, please do not edit. - -import("//third_party/closure_compiler/compile_js.gni") - -js_library("paper-fab-extracted") { - deps = [ - "../iron-icon:iron-icon-extracted", - "../paper-behaviors:paper-button-behavior-extracted", - ] -}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/bower.json b/third_party/polymer/v1_0/components-chromium/paper-fab/bower.json deleted file mode 100644 index dc912a29..0000000 --- a/third_party/polymer/v1_0/components-chromium/paper-fab/bower.json +++ /dev/null
@@ -1,62 +0,0 @@ -{ - "name": "paper-fab", - "version": "2.0.0", - "description": "A material design floating action button", - "authors": [ - "The Polymer Authors" - ], - "keywords": [ - "web-components", - "polymer", - "button" - ], - "main": "paper-fab.html", - "ignore": [], - "private": true, - "repository": { - "type": "git", - "url": "git://github.com/PolymerElements/paper-fab.git" - }, - "license": "http://polymer.github.io/LICENSE.txt", - "homepage": "https://github.com/PolymerElements/paper-fab", - "dependencies": { - "iron-flex-layout": "PolymerElements/iron-flex-layout#1 - 2", - "iron-icon": "PolymerElements/iron-icon#1 - 2", - "paper-behaviors": "PolymerElements/paper-behaviors#1 - 2", - "paper-styles": "PolymerElements/paper-styles#1 - 2", - "polymer": "Polymer/polymer#1.9 - 2" - }, - "devDependencies": { - "iron-component-page": "PolymerElements/iron-component-page#1 - 2", - "iron-demo-helpers": "PolymerElements/iron-demo-helpers#1 - 2", - "iron-icons": "PolymerElements/iron-icons#1 - 2", - "paper-styles": "PolymerElements/paper-styles#1 - 2", - "web-component-tester": "^6.0.0", - "webcomponentsjs": "webcomponents/webcomponentsjs#^1.0.0" - }, - "variants": { - "1.x": { - "dependencies": { - "iron-flex-layout": "PolymerElements/iron-flex-layout#^1.0.0", - "iron-icon": "PolymerElements/iron-icon#^1.0.0", - "paper-behaviors": "PolymerElements/paper-behaviors#^1.0.0", - "paper-styles": "PolymerElements/paper-styles#^1.0.0", - "polymer": "Polymer/polymer#^1.9" - }, - "devDependencies": { - "iron-component-page": "PolymerElements/iron-component-page#^1.0.0", - "iron-demo-helpers": "PolymerElements/iron-demo-helpers#^1.0.0", - "iron-icons": "PolymerElements/iron-icons#^1.0.0", - "paper-styles": "PolymerElements/paper-styles#^1.0.0", - "web-component-tester": "^4.0.0", - "webcomponentsjs": "webcomponents/webcomponentsjs#^0.7.0" - }, - "resolutions": { - "webcomponentsjs": "^0.7" - } - } - }, - "resolutions": { - "webcomponentsjs": "^1.0.0" - } -}
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab-extracted.js b/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab-extracted.js deleted file mode 100644 index 2121d0d..0000000 --- a/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab-extracted.js +++ /dev/null
@@ -1,54 +0,0 @@ -Polymer({ - is: 'paper-fab', - - behaviors: [ - Polymer.PaperButtonBehavior - ], - - properties: { - /** - * The URL of an image for the icon. If the src property is specified, - * the icon property should not be. - */ - src: { - type: String, - value: '' - }, - - /** - * Specifies the icon name or index in the set of icons available in - * the icon's icon set. If the icon property is specified, - * the src property should not be. - */ - icon: { - type: String, - value: '' - }, - - /** - * Set this to true to style this is a "mini" FAB. - */ - mini: { - type: Boolean, - value: false, - reflectToAttribute: true - }, - - /** - * The label displayed in the badge. The label is centered, and ideally - * should have very few characters. - */ - label: { - type: String, - observer: '_labelChanged' - } - }, - - _labelChanged: function() { - this.setAttribute('aria-label', this.label); - }, - - _computeIsIconFab: function(icon, src) { - return (icon.length > 0) || (src.length > 0); - } - }); \ No newline at end of file
diff --git a/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html b/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html deleted file mode 100644 index 403fae57..0000000 --- a/third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html +++ /dev/null
@@ -1,147 +0,0 @@ -<!-- -@license -Copyright (c) 2015 The Polymer Project Authors. All rights reserved. -This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt -The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt -The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt -Code distributed by Google as part of the polymer project is also -subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt ---><html><head><link rel="import" href="../polymer/polymer.html"> -<link rel="import" href="../iron-flex-layout/iron-flex-layout.html"> -<link rel="import" href="../iron-icon/iron-icon.html"> -<link rel="import" href="../paper-behaviors/paper-button-behavior.html"> -<link rel="import" href="../paper-styles/element-styles/paper-material-styles.html"> -<link rel="import" href="../paper-styles/color.html"> -<link rel="import" href="../paper-styles/default-theme.html"> - -<!-- -Material design: [Floating Action Button](https://www.google.com/design/spec/components/buttons-floating-action-button.html) - -`paper-fab` is a floating action button. It contains an image placed in the center and -comes in two sizes: regular size and a smaller size by applying the attribute `mini`. When -the user touches the button, a ripple effect emanates from the center of the button. - -You may import `iron-icons` to use with this element, or provide a URL to a custom icon. -See `iron-iconset` for more information about how to use a custom icon set. - -Example: - - <link href="path/to/iron-icons/iron-icons.html" rel="import"> - - <paper-fab icon="add"></paper-fab> - <paper-fab mini icon="favorite"></paper-fab> - <paper-fab src="star.png"></paper-fab> - - -### Styling - -The following custom properties and mixins are available for styling: - -Custom property | Description | Default -----------------|-------------|---------- -`--paper-fab-background` | The background color of the button | `--accent-color` -`--paper-fab-keyboard-focus-background` | The background color of the button when focused | `--paper-pink-900` -`--paper-fab-disabled-background` | The background color of the button when it's disabled | `--paper-grey-300` -`--paper-fab-disabled-text` | The text color of the button when it's disabled | `--paper-grey-500` -`--paper-fab` | Mixin applied to the button | `{}` -`--paper-fab-mini` | Mixin applied to a mini button | `{}` -`--paper-fab-disabled` | Mixin applied to a disabled button | `{}` -`--paper-fab-iron-icon` | Mixin applied to the iron-icon within the button | `{}` -`--paper-fab-label` | Mixin applied to the label within the button | `{}` - -@group Paper Elements -@demo demo/index.html ---> - -</head><body><dom-module id="paper-fab"> - <template strip-whitespace=""> - <style include="paper-material-styles"> - :host { - @apply --layout-vertical; - @apply --layout-center-center; - - background: var(--paper-fab-background, var(--accent-color)); - border-radius: 50%; - box-sizing: border-box; - color: var(--text-primary-color); - cursor: pointer; - height: 56px; - min-width: 0; - outline: none; - padding: 16px; - position: relative; - user-select: none; - width: 56px; - z-index: 0; - - /* NOTE: Both values are needed, since some phones require the value `transparent`. */ - -webkit-tap-highlight-color: rgba(0,0,0,0); - -webkit-tap-highlight-color: transparent; - - @apply --paper-fab; - } - - [hidden] { - display: none !important; - } - - :host([mini]) { - width: 40px; - height: 40px; - padding: 8px; - - @apply --paper-fab-mini; - } - - :host([disabled]) { - color: var(--paper-fab-disabled-text, var(--paper-grey-500)); - background: var(--paper-fab-disabled-background, var(--paper-grey-300)); - - @apply --paper-fab-disabled; - } - - iron-icon { - @apply --paper-fab-iron-icon; - } - - span { - width: 100%; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - text-align: center; - - @apply --paper-fab-label; - } - - :host(.keyboard-focus) { - background: var(--paper-fab-keyboard-focus-background, var(--paper-pink-900)); - } - - :host([elevation="1"]) { - @apply --paper-material-elevation-1; - } - - :host([elevation="2"]) { - @apply --paper-material-elevation-2; - } - - :host([elevation="3"]) { - @apply --paper-material-elevation-3; - } - - :host([elevation="4"]) { - @apply --paper-material-elevation-4; - } - - :host([elevation="5"]) { - @apply --paper-material-elevation-5; - } - </style> - - <iron-icon id="icon" hidden$="{{!_computeIsIconFab(icon, src)}}" src="[[src]]" icon="[[icon]]"></iron-icon> - <span hidden$="{{_computeIsIconFab(icon, src)}}">{{label}}</span> - </template> - - </dom-module> -<script src="paper-fab-extracted.js"></script></body></html> \ No newline at end of file
diff --git a/third_party/polymer/v1_0/components_summary.txt b/third_party/polymer/v1_0/components_summary.txt index 5b8af37c..74c3728 100644 --- a/third_party/polymer/v1_0/components_summary.txt +++ b/third_party/polymer/v1_0/components_summary.txt
@@ -184,12 +184,6 @@ Revision: b37655b85e1c3364ce9f5ca0470ddf1071cca3aa Tree link: https://github.com/PolymerElements/paper-button/tree/v2.0.0 -Name: paper-fab -Repository: https://github.com/PolymerElements/paper-fab.git -Tree: v2.0.0 -Revision: d1dcd747d807200516444ef15f215d0aaa526816 -Tree link: https://github.com/PolymerElements/paper-fab/tree/v2.0.0 - Name: paper-icon-button Repository: https://github.com/PolymerElements/paper-icon-button.git Tree: v2.1.0
diff --git a/third_party/polymer/v1_0/rsync_exclude.txt b/third_party/polymer/v1_0/rsync_exclude.txt index 41e6369..027599f 100644 --- a/third_party/polymer/v1_0/rsync_exclude.txt +++ b/third_party/polymer/v1_0/rsync_exclude.txt
@@ -28,6 +28,10 @@ */site/ */templates/ +# html-imports +html-imports/src/* +html-imports/gulpfile.js + # html-imports-v0 html-imports-v0/src/* html-imports-v0/gulpfile.js
diff --git a/third_party/webxr_test_pages/webxr-samples/360-photos.html b/third_party/webxr_test_pages/webxr-samples/360-photos.html index b5b987f..f428a151 100644 --- a/third_party/webxr_test_pages/webxr-samples/360-photos.html +++ b/third_party/webxr_test_pages/webxr-samples/360-photos.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/fallback-rendering.html b/third_party/webxr_test_pages/webxr-samples/fallback-rendering.html index 3019f07..1e65b7d 100644 --- a/third_party/webxr_test_pages/webxr-samples/fallback-rendering.html +++ b/third_party/webxr_test_pages/webxr-samples/fallback-rendering.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/framebuffer-scaling.html b/third_party/webxr_test_pages/webxr-samples/framebuffer-scaling.html index 2e5dab5..baa2658 100644 --- a/third_party/webxr_test_pages/webxr-samples/framebuffer-scaling.html +++ b/third_party/webxr_test_pages/webxr-samples/framebuffer-scaling.html
@@ -35,6 +35,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/input-selection.html b/third_party/webxr_test_pages/webxr-samples/input-selection.html index b022ad9..04251b2 100644 --- a/third_party/webxr_test_pages/webxr-samples/input-selection.html +++ b/third_party/webxr_test_pages/webxr-samples/input-selection.html
@@ -33,9 +33,11 @@ <link href='css/common.css' rel='stylesheet'></link> + <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/input-tracking.html b/third_party/webxr_test_pages/webxr-samples/input-tracking.html index 76e0ed5..97dd2cb 100644 --- a/third_party/webxr_test_pages/webxr-samples/input-tracking.html +++ b/third_party/webxr_test_pages/webxr-samples/input-tracking.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js b/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js index 55ebbf6..8477ab8 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js +++ b/third_party/webxr_test_pages/webxr-samples/js/cottontail/src/scenes/scene.js
@@ -24,6 +24,8 @@ import {Node} from '../core/node.js'; import {vec3, quat} from '../math/gl-matrix.js'; +import '/js/xrray-polyfill.js'; + export class WebXRView extends RenderView { constructor(view, pose, layer) { super(
diff --git a/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js b/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js index 875b412..0ef2fe18 100644 --- a/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js +++ b/third_party/webxr_test_pages/webxr-samples/js/webxr-polyfill.js
@@ -34,7 +34,7 @@ /** * @license - * webvr-polyfill-dpdb + * webvr-polyfill-dpdb * Copyright (c) 2017 Google * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -1276,37 +1276,6 @@ } var DOMPointReadOnly$1 = domPointROExport; -var XRRay = -function XRRay() { - var origin = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : new DOMPointReadOnly$1(0, 0, 0, 1); - var direction = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : new DOMPointReadOnly$1(0, 0, -1, 0); - var matrix = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : new Float32Array(16); - classCallCheck(this, XRRay); - if (!(origin instanceof DOMPointReadOnly$1)) { - throw new Error('origin must be a DOMPointReadOnly'); - } - if (!(direction instanceof DOMPointReadOnly$1)) { - throw new Error('direction must be a DOMPointReadOnly'); - } - if (!(matrix instanceof Float32Array)) { - throw new Error('matrix must be a Float32Array'); - } - Object.defineProperties(this, { - origin: { - value: origin, - writable: false - }, - direction: { - value: direction, - writable: false - }, - matrix: { - value: matrix, - writable: false - } - }); -}; - var PRIVATE$13 = Symbol('@@webxr-polyfill/XRInputPose'); var XRInputPose = function () { function XRInputPose(inputSourceImpl, hasGripMatrix) { @@ -1484,7 +1453,6 @@ XRStageBoundsPoint: XRStageBoundsPoint, XRInputPose: XRInputPose, XRInputSource: XRInputSource, - XRRay: XRRay }; var extendContextCompatibleXRDevice = function extendContextCompatibleXRDevice(Context) {
diff --git a/third_party/webxr_test_pages/webxr-samples/js/xrray-module.js b/third_party/webxr_test_pages/webxr-samples/js/xrray-module.js new file mode 100644 index 0000000..ea5b134 --- /dev/null +++ b/third_party/webxr_test_pages/webxr-samples/js/xrray-module.js
@@ -0,0 +1,181 @@ +// Copyright 2018 The Immersive Web Community Group +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +// |matrix| - Float32Array representing 4x4 matrix (column major) +// |point| - DOMPointReadOnly +const transformByMatrix = function(matrix, point){ + return new DOMPointReadOnly({ + x : matrix[0] * point.x + matrix[4] * point.y + matrix[8] * point.z + matrix[12] * point.w, + y : matrix[1] * point.x + matrix[5] * point.y + matrix[9] * point.z + matrix[13] * point.w, + z : matrix[2] * point.x + matrix[6] * point.y + matrix[10] * point.z + matrix[14] * point.w, + w : matrix[3] * point.x + matrix[7] * point.y + matrix[11] * point.z + matrix[15] * point.w, + }); +}; + +// |lhs|, |rhs| - Float32Arrays representing 4x4 matrices (column major) +// returns Float32Array representing 4x4 matrix (column major) +const multiply = function(lhs, rhs) { + let result = new Float32Array([ + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0, + 0, 0, 0, 0 + ]); + + for(let col = 0; col < 4; ++col) { + for(let row = 0; row < 4; ++row) { + for(let k = 0; k < 4; ++k) { + result[col * 4 + row] += rhs[col][k] * lhs[k][row]; + } + } + } + + return result; +}; + +// |point| - DOMPointReadOnly +const normalizeLength = function(point){ + let l = Math.sqrt(point.x * point.x + point.y * point.y + point.z * point.z); + return new DOMPointReadOnly(point.x / l, point.y / l, point.z / l, point.w); +}; + +// |lhs|, |rhs| - 3-element float arrays +// returns 3-element float array +const dot = function(lhs, rhs) { + return lhs[0] * rhs[0] + lhs[1] * rhs[1] + lhs[2] * rhs[2]; +}; + +// |lhs|, |rhs| - 3-element float arrays +// returns 3-element float array +const cross = function(lhs, rhs){ + return [ + lhs[1] * rhs[2] - lhs[2] * rhs[1], + lhs[2] * rhs[0] - lhs[0] * rhs[2], + lhs[0] * rhs[1] - lhs[1] * rhs[0], + ]; +}; + +// |matrix| - Float32Array representing 4x4 matrix (column major) +// |axis| - DOMPointReadOnly representing axis, must be normalized +// |angle| - float, angle in radians +const rotate = function(matrix, axis, angle) { + const sin_angle = Math.sin(angle); + const cos_angle = Math.cos(angle); + const one_minus_cos_angle = 1 - cos_angle; + + const rotateMatrix = new Float32Array([ + // first column + cos_angle + axis.x * axis.x * one_minus_cos_angle, + axis.y * axis.x * one_minus_cos_angle + axis.z * sin_angle, + axis.z * axis.x * one_minus_cos_angle - axis.y * sin_angle, + 0, + // second column + axis.x * axis.y * one_minus_cos_angle - axis.z * sin_angle, + cos_angle + axis.y * axis.y * one_minus_cos_angle, + axis.z * axis.y * one_minus_cos_angle + x * sin_angle, + 0, + // third column + axis.x * axis.z * one_minus_cos_angle + axis.y * sin_angle, + axis.y * axis.z * one_minus_cos_angle - axis.x * sin_angle, + cos_angle + axis.z * axis.z * one_minus_cos_angle, + 0, + // fourth column + 0, + 0, + 0, + 1 + ]); + + return multiply(matrix, rotateMatrix); +}; + +export class XRRay { + constructor() { + + if (arguments.length > 0 && arguments[0] instanceof XRRigidTransform) { + if(arguments.length != 1) + throw new Error("Invalid number of arguments!"); + + this.origin_ = transformByMatrix( + arguments[0].matrix, new DOMPointReadOnly(0, 0, 0, 1)); + this.direction_ = normalizeLength( + transformByMatrix( + arguments[0].matrix, new DOMPointReadOnly(0, 0, -1, 0))); + this.matrix_ = arguments[0].matrix; + } else { + if(arguments.length > 2) + throw new Error("Too many arguments!"); + + this.origin_ = (arguments.length > 0 && arguments[0] !== undefined) + ? arguments[0] + : new DOMPointReadOnly(0, 0, 0, 1); + this.direction_ = (arguments.length > 1 && arguments[1] !== undefined) + ? arguments[1] + : new DOMPointReadOnly(0, 0, -1, 0); + + // Compute the matrix from origin & direction. + this.matrix_ = new Float32Array([ + 1, 0, 0, 0, + 0, 1, 0, 0, + 0, 0, 1, 0, + this.origin_.x, this.origin_.y, this.origin_.z, 1 + ]); + + const initial_ray_direction = [0, 0, -1]; + const desired_ray_direction = [direction.x, direction.y, direction.z]; + + const cos_angle = dot(initial_ray_direction, desired_ray_direction); + + if (cos_angle > 0.9999) { + // Vectors are co-linear or almost co-linear & face the same direction, + // no rotation is needed. + } else if (cos_angle < -0.9999) { + // Vectors are co-linear or almost co-linear & face the opposite + // direction, rotation by 180 degrees is needed & can be around any vector + // perpendicular to (0,0,-1) so let's rotate by (1, 0, 0). + const axis = new DOMPointReadOnly(1, 0, 0, 0); + cos_angle = -1; + + this.matrix_ = rotate(this.matrix_, axis, Math.acos(angle)); + } else { + // Rotation needed - create it from axis-angle. + const cross_initial_desired = cross(initialRayDirection, desiredRayDirection); + const axis = normalizeLength(new DOMPointReadOnly( + cross_initial_desired[0], cross_initial_desired[1], cross_initial_desired[2], 0)); + + this.matrix_ = rotate(this.matrix_, axis, Math.acos(angle)); + } + } + + if (!(this.origin_ instanceof DOMPointReadOnly)) { + throw new Error('origin must be a DOMPointReadOnly'); + } + if (!(this.direction_ instanceof DOMPointReadOnly)) { + throw new Error('direction must be a DOMPointReadOnly'); + } + if (!(this.matrix_ instanceof Float32Array)) { + throw new Error('matrix must be a Float32Array'); + } + } + + get origin() { return this.origin_; } + get direction() { return this.direction_; } + get matrix() { return this.matrix_; } +}
diff --git a/third_party/webxr_test_pages/webxr-samples/js/xrray-polyfill.js b/third_party/webxr_test_pages/webxr-samples/js/xrray-polyfill.js new file mode 100644 index 0000000..4ddeaf60 --- /dev/null +++ b/third_party/webxr_test_pages/webxr-samples/js/xrray-polyfill.js
@@ -0,0 +1,31 @@ +// Copyright 2018 The Immersive Web Community Group +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of +// this software and associated documentation files (the "Software"), to deal in +// the Software without restriction, including without limitation the rights to +// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +// the Software, and to permit persons to whom the Software is furnished to do so, +// subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +import {XRRay} from './xrray-module.js'; + +(function(global) { + + if(typeof global.XRRay !== 'function') { + console.debug("XRRay not present, polyfilling."); + global.XRRay = XRRay; + } else { + console.debug("XRRay is present"); + } +}(window));
diff --git a/third_party/webxr_test_pages/webxr-samples/magic-window.html b/third_party/webxr_test_pages/webxr-samples/magic-window.html index 017a6dfc..1f3c0957 100644 --- a/third_party/webxr_test_pages/webxr-samples/magic-window.html +++ b/third_party/webxr_test_pages/webxr-samples/magic-window.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/mirroring.html b/third_party/webxr_test_pages/webxr-samples/mirroring.html index 718d97e2..c0d7fe625 100644 --- a/third_party/webxr_test_pages/webxr-samples/mirroring.html +++ b/third_party/webxr_test_pages/webxr-samples/mirroring.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/module-tester.html b/third_party/webxr_test_pages/webxr-samples/module-tester.html index 76100da..2c3c8936 100644 --- a/third_party/webxr_test_pages/webxr-samples/module-tester.html +++ b/third_party/webxr_test_pages/webxr-samples/module-tester.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <style> @@ -124,7 +125,7 @@ boxNodes.push(node); boxBuilder.clear(); } - + /*addBox(0, 0, -1.0); addBox(-0.7, 0, -1.0); addBox(0.7, 0, -1.0);
diff --git a/third_party/webxr_test_pages/webxr-samples/positional-audio.html b/third_party/webxr_test_pages/webxr-samples/positional-audio.html index 06b533e..32795211 100644 --- a/third_party/webxr_test_pages/webxr-samples/positional-audio.html +++ b/third_party/webxr_test_pages/webxr-samples/positional-audio.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src="https://cdn.jsdelivr.net/npm/resonance-audio/build/resonance-audio.min.js"></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html index 51afc5f..b957241 100644 --- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html +++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar-hit-test.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='../js/xrray-polyfill.js' type='module'></script> <script src='../js/webxr-polyfill.js'></script> <script src='../js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html index a746e53a..1ce0e80 100644 --- a/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html +++ b/third_party/webxr_test_pages/webxr-samples/proposals/phone-ar.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='../js/xrray-polyfill.js' type='module'></script> <script src='../js/webxr-polyfill.js'></script> <script src='../js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/reduced-bind-rendering.html b/third_party/webxr_test_pages/webxr-samples/reduced-bind-rendering.html index 8c4b624..e2bc4e1d5 100644 --- a/third_party/webxr_test_pages/webxr-samples/reduced-bind-rendering.html +++ b/third_party/webxr_test_pages/webxr-samples/reduced-bind-rendering.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/room-scale.html b/third_party/webxr_test_pages/webxr-samples/room-scale.html index adacde5d..dbb6fad 100644 --- a/third_party/webxr_test_pages/webxr-samples/room-scale.html +++ b/third_party/webxr_test_pages/webxr-samples/room-scale.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script> @@ -155,7 +156,7 @@ // floor-relative space and will always be supported for // immersive sessions. It will not, however, provide boundaries // and generally expects the user to stand in one place. - // If the device doesn't have a way of determining the floor + // If the device doesn't have a way of determining the floor // level (for example, with a 3DoF device) then it will return // an emulated floor-level space, where the view is translated // up by a static height so that the scene still renders in
diff --git a/third_party/webxr_test_pages/webxr-samples/spectator-mode.html b/third_party/webxr_test_pages/webxr-samples/spectator-mode.html index a6231098..9b6397e 100644 --- a/third_party/webxr_test_pages/webxr-samples/spectator-mode.html +++ b/third_party/webxr_test_pages/webxr-samples/spectator-mode.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/stereo-video.html b/third_party/webxr_test_pages/webxr-samples/stereo-video.html index 1f3a731..d3d88c8 100644 --- a/third_party/webxr_test_pages/webxr-samples/stereo-video.html +++ b/third_party/webxr_test_pages/webxr-samples/stereo-video.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/tests/cube-sea.html b/third_party/webxr_test_pages/webxr-samples/tests/cube-sea.html index 0c5f3789..6b174e7 100644 --- a/third_party/webxr_test_pages/webxr-samples/tests/cube-sea.html +++ b/third_party/webxr_test_pages/webxr-samples/tests/cube-sea.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='../js/xrray-polyfill.js' type='module'></script> <script src='../js/webxr-polyfill.js'></script> <script src='../js/third-party/dat.gui/dat.gui.min.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/tests/offscreen-canvas.html b/third_party/webxr_test_pages/webxr-samples/tests/offscreen-canvas.html index 7dca22d..fd7d943 100644 --- a/third_party/webxr_test_pages/webxr-samples/tests/offscreen-canvas.html +++ b/third_party/webxr_test_pages/webxr-samples/tests/offscreen-canvas.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='../js/xrray-polyfill.js' type='module'></script> <script src='../js/webxr-polyfill.js'></script> <script src='../js/third-party/dat.gui/dat.gui.min.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/tests/permission-request.html b/third_party/webxr_test_pages/webxr-samples/tests/permission-request.html index e24fc2c..b382fb8 100644 --- a/third_party/webxr_test_pages/webxr-samples/tests/permission-request.html +++ b/third_party/webxr_test_pages/webxr-samples/tests/permission-request.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='../js/xrray-polyfill.js' type='module'></script> <script src='../js/webxr-polyfill.js'></script> <script src='../js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/tests/pointer-painter.html b/third_party/webxr_test_pages/webxr-samples/tests/pointer-painter.html index eb326dc..213dd0c 100644 --- a/third_party/webxr_test_pages/webxr-samples/tests/pointer-painter.html +++ b/third_party/webxr_test_pages/webxr-samples/tests/pointer-painter.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='../js/xrray-polyfill.js' type='module'></script> <script src='../js/webxr-polyfill.js'></script> <script src='../js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/tests/sponza.html b/third_party/webxr_test_pages/webxr-samples/tests/sponza.html index 168773b..0409ab3 100644 --- a/third_party/webxr_test_pages/webxr-samples/tests/sponza.html +++ b/third_party/webxr_test_pages/webxr-samples/tests/sponza.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='../js/xrray-polyfill.js' type='module'></script> <script src='../js/webxr-polyfill.js'></script> <script src='../js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/viewport-scaling.html b/third_party/webxr_test_pages/webxr-samples/viewport-scaling.html index dd021ac..b6d0941 100644 --- a/third_party/webxr_test_pages/webxr-samples/viewport-scaling.html +++ b/third_party/webxr_test_pages/webxr-samples/viewport-scaling.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/third_party/webxr_test_pages/webxr-samples/xr-presentation.html b/third_party/webxr_test_pages/webxr-samples/xr-presentation.html index 5ee75b5..4f9bc999 100644 --- a/third_party/webxr_test_pages/webxr-samples/xr-presentation.html +++ b/third_party/webxr_test_pages/webxr-samples/xr-presentation.html
@@ -36,6 +36,7 @@ <!--The polyfill is not needed for browser that have native API support, but is linked by these samples for wider compatibility.--> <!--script src='https://cdn.jsdelivr.net/npm/webxr-polyfill@latest/build/webxr-polyfill.js'></script--> + <script src='js/xrray-polyfill.js' type='module'></script> <script src='js/webxr-polyfill.js'></script> <script src='js/webxr-button.js'></script>
diff --git a/tools/android/roll/android_deps/build.gradle b/tools/android/roll/android_deps/build.gradle index c3dc08ea..3861c7a 100644 --- a/tools/android/roll/android_deps/build.gradle +++ b/tools/android/roll/android_deps/build.gradle
@@ -63,11 +63,11 @@ compile "com.android.support:multidex:1.0.0" - compile "javax.inject:javax.inject:1" + buildCompile "javax.inject:javax.inject:1" // Dagger def daggerVersion = '2.17' - compile "com.google.dagger:dagger:${daggerVersion}" + buildCompile "com.google.dagger:dagger:${daggerVersion}" annotationProcessor "com.google.dagger:dagger-compiler:${daggerVersion}" // JavaPoet
diff --git a/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy b/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy index 21a6ae2..e820dc9 100644 --- a/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy +++ b/tools/android/roll/android_deps/buildSrc/src/main/groovy/BuildConfigGenerator.groovy
@@ -357,8 +357,8 @@ licenseString = dependency.licenseName } - def securityCritical = dependency.supportsAndroid && !dependency.testOnly - def licenseFile = securityCritical? "LICENSE" : "NOT_SHIPPED" + def securityCritical = dependency.supportsAndroid && dependency.isShipped + def licenseFile = dependency.isShipped? "LICENSE" : "NOT_SHIPPED" return """\ Name: ${dependency.displayName}
diff --git a/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy b/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy index f639b45..fdc6ae3a 100644 --- a/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy +++ b/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumDepGraph.groovy
@@ -62,11 +62,13 @@ void collectDependencies() { def compileConfig = project.configurations.getByName('compile').resolvedConfiguration + def buildCompileConfig = project.configurations.getByName('buildCompile').resolvedConfiguration def annotationProcessorConfig = project.configurations.getByName('annotationProcessor').resolvedConfiguration def testCompileConfig = project.configurations.getByName('testCompile').resolvedConfiguration List<String> topLevelIds = [] Set<ResolvedConfiguration> deps = [] deps += compileConfig.firstLevelModuleDependencies + deps += buildCompileConfig.firstLevelModuleDependencies deps += annotationProcessorConfig.firstLevelModuleDependencies deps += testCompileConfig.firstLevelModuleDependencies @@ -82,6 +84,16 @@ assert dep != null : "No dependency collected for artifact ${artifact.name}" dep.supportsAndroid = true dep.testOnly = true + dep.isShipped = false + } + + buildCompileConfig.resolvedArtifacts.each { artifact -> + def id = makeModuleId(artifact) + def dep = dependencies.get(id) + assert dep != null : "No dependency collected for artifact ${artifact.name}" + dep.supportsAndroid = true + dep.testOnly = false + dep.isShipped = false } compileConfig.resolvedArtifacts.each { artifact -> @@ -90,6 +102,7 @@ assert dep != null : "No dependency collected for artifact ${artifact.name}" dep.supportsAndroid = true dep.testOnly = false + dep.isShipped = true } } @@ -248,7 +261,7 @@ String group, name, version, extension, displayName, description, url String licenseName, licenseUrl, licensePath String fileName - boolean supportsAndroid, visible, exclude, testOnly + boolean supportsAndroid, visible, exclude, testOnly, isShipped boolean licenseAndroidCompatible ComponentIdentifier componentId List<String> children
diff --git a/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumPlugin.groovy b/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumPlugin.groovy index 69f5b4d..374f3c3 100644 --- a/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumPlugin.groovy +++ b/tools/android/roll/android_deps/buildSrc/src/main/groovy/ChromiumPlugin.groovy
@@ -20,6 +20,9 @@ /** Libraries that are for testing only. */ testCompile + /** Libraries that are only used during build. These support android. */ + buildCompile + /** * Marks that the dependency will only be used during building, as an annotation * processor. It will not be usable in the APK, and not marked as supporting android.
diff --git a/tools/mb/mb_config.pyl b/tools/mb/mb_config.pyl index a14aaca..4ba5d5ac 100644 --- a/tools/mb/mb_config.pyl +++ b/tools/mb/mb_config.pyl
@@ -328,11 +328,16 @@ 'Chromium Mac Goma RBE Staging (clobber)': 'release_bot', 'Chromium Mac Goma RBE Staging': 'release_bot', 'Chromium Mac Goma RBE Staging (dbg)': 'debug_bot', + 'Chromium Mac Goma RBE Prod': 'release_bot', # Same as CrWinGomaStaging. 'Chromium Win Goma RBE ToT': 'release_bot_x86_minimal_symbols', 'Chromium Win Goma RBE Staging': 'release_bot_x86_minimal_symbols', 'Chromium Win Goma RBE Staging (clobber)': 'release_bot_x86_minimal_symbols', + 'Chromium Win Goma RBE Prod': 'release_bot_x86_minimal_symbols', + 'Chromium Win Goma RBE Prod (clobber)': 'release_bot_x86_minimal_symbols', + 'Chromium Win Goma RBE Prod (dbg)': 'debug_bot_x86_minimal_symbols', + 'Chromium Win Goma RBE Prod (dbg) (clobber)': 'debug_bot_x86_minimal_symbols', 'Chromium Android ARM 32-bit Goma RBE ToT': 'android_release_bot_minimal_symbols', 'Chromium Android ARM 32-bit Goma RBE ToT (ATS)': 'android_release_bot_minimal_symbols',
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml index 7c038c93..10dfa0a 100644 --- a/tools/metrics/histograms/enums.xml +++ b/tools/metrics/histograms/enums.xml
@@ -14091,6 +14091,29 @@ <int value="362" label="configprofile"/> <int value="363" label="internetconnect"/> <int value="364" label="networkconnect"/> + <int value="365" label="bmp"/> + <int value="366" label="css"/> + <int value="367" label="ehtml"/> + <int value="368" label="flac"/> + <int value="369" label="ico"/> + <int value="370" label="jfif"/> + <int value="371" label="m4a"/> + <int value="372" label="m4v"/> + <int value="373" label="mpeg"/> + <int value="374" label="mpg"/> + <int value="375" label="oga"/> + <int value="376" label="ogg"/> + <int value="377" label="ogm"/> + <int value="378" label="ogv"/> + <int value="379" label="opus"/> + <int value="380" label="pjp"/> + <int value="381" label="pjpeg"/> + <int value="382" label="svgz"/> + <int value="383" label="text"/> + <int value="384" label="tiff"/> + <int value="385" label="weba"/> + <int value="386" label="webm"/> + <int value="387" label="xbm"/> </enum> <enum name="DownloadItem.DangerType"> @@ -41782,6 +41805,20 @@ The attempt resulted in a retriable loading failure. We encountered an error page (e.g. 404 page). </int> + <int value="21" label="Loading deferred (retriable, auto-fetch exclusive)"> + Background loading of the page was deferred because its URL matches the one + on the active tab URL. The attempt will be retried later. + </int> + <int value="22" label="Page has certificate error"> + The loaded page has a HTTPS certificate error. The request was aborted. + </int> + <int value="23" label="Page is blocked by SafeBrowsing"> + The loaded page is blocked by SafeBrowsing. The request was aborted. + </int> + <int value="24" label="Page is an interstitial or error page"> + The loaded page is a Chrome interstitial or an error page. The request was + aborted. + </int> </enum> <enum name="OfflinePagesBackgroundSavePageResult"> @@ -41991,17 +42028,17 @@ Certain pages like file URL or NTP will not be saved because they're already available offline. </int> - <int value="8" label="Security certificate error"> - Save operation failed because the page resulted in a security certificate - error. + <int value="8" label="Deprecated: Security certificate error"> + Deprecated: Save operation failed because the page resulted in a security + certificate error. </int> - <int value="9" label="Error page detected"> - Save operation failed because an error page (i.e. offline dino page) was - detected. + <int value="9" label="Deprecated: Error page detected"> + Deprecated: Save operation failed because an error page (i.e. offline dino + page) was detected. </int> - <int value="10" label="Interstitial page detected"> - Save operation failed because an interstitial page (i.e. page warning of - expired certificates or improper dev signatures) was detected. + <int value="10" label="Deprecated: Interstitial page detected"> + Deprecated: Save operation failed because an interstitial page (i.e. page + warning of expired certificates or improper dev signatures) was detected. </int> <int value="11" label="Digest calculation failure"> Failed to compute the digest of an archive file. @@ -49913,6 +49950,29 @@ <int value="362" label="CONFIGPROFILE"/> <int value="363" label="INTERNETCONNECT"/> <int value="364" label="NETWORKCONNECT"/> + <int value="365" label="BMP"/> + <int value="366" label="CSS"/> + <int value="367" label="EHTML"/> + <int value="368" label="FLAC"/> + <int value="369" label="ICO"/> + <int value="370" label="JFIF"/> + <int value="371" label="M4A"/> + <int value="372" label="M4V"/> + <int value="373" label="MPEG"/> + <int value="374" label="MPG"/> + <int value="375" label="OGA"/> + <int value="376" label="OGG"/> + <int value="377" label="OGM"/> + <int value="378" label="OGV"/> + <int value="379" label="OPUS"/> + <int value="380" label="PJP"/> + <int value="381" label="PJPEG"/> + <int value="382" label="SVGZ"/> + <int value="383" label="TEXT"/> + <int value="384" label="TIFF"/> + <int value="385" label="WEBA"/> + <int value="386" label="WEBM"/> + <int value="387" label="XBM"/> </enum> <enum name="SBClientDownloadIsSignedBinary">
diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index 390b4e59..f1a347e 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml
@@ -133162,6 +133162,16 @@ </summary> </histogram> +<histogram name="UpgradeDetector.TimeBeforeUpgrade" units="ms" + expires_after="M80"> + <owner>ksspiers@chromium.org</owner> + <owner>nrpeter@chromium.org</owner> + <summary> + Measures the time elapsed from an update being visible to the browser and + the browser being restarted or quit. + </summary> +</histogram> + <histogram name="Uptime.ChromeExecToLoginPromptVisibleAfterLogout" units="ms" expires_after="M77"> <owner>hajimehoshi@chromium.org</owner> @@ -142426,6 +142436,18 @@ </summary> </histogram> +<histogram name="WebShare.Unverified" enum="SBClientDownloadExtensions" + expires_after="M82"> + <owner>ericwilligers@chromium.org</owner> + <owner>hartmanng@chromium.org</owner> + <owner>hzjian@chromium.org</owner> + <owner>yfriedman@chromium.org</owner> + <summary> + File types included in navigator.share() requests, where file content and + source URLs were not verified with Safe Browsing. + </summary> +</histogram> + <histogram name="WebsiteSettings.Action" enum="WebsiteSettingsAction"> <owner>estark@chromium.org</owner> <summary>
diff --git a/tools/perf/benchmarks/system_health_smoke_test.py b/tools/perf/benchmarks/system_health_smoke_test.py index 599940a..574f883a 100644 --- a/tools/perf/benchmarks/system_health_smoke_test.py +++ b/tools/perf/benchmarks/system_health_smoke_test.py
@@ -137,6 +137,26 @@ # crbug.com/937006 'system_health.memory_mobile/browse:news:toi', + + # The following tests are disabled because they are disabled on the perf + # waterfall (using tools/perf/expectations.config) on one platform or another. + # They may run fine on the CQ, but it isn't worth the bot time to run them. + # [ + # crbug.com/799106 + 'system_health.memory_desktop/browse:media:flickr_infinite_scroll' + # crbug.com/836407 + 'system_health.memory_desktop/browse:tools:maps' + # crbug.com/924330 + 'system_health.memory_desktop/browse:media:pinterest:2018' + # crbug.com/899887 + 'system_health.memory_desktop/browse:social:facebook_infinite_scroll:2018' + # crbug.com/649392 + 'system_health.memory_desktop/play:media:google_play_music' + # crbug.com/934885 + 'system_health.memory_desktop/load_accessibility:media:wikipedia:2018' + # crbug.com/942952 + 'system_health.memory_desktop/browse:news:hackernews:2018' + # ] })
diff --git a/ui/base/ime/dummy_text_input_client.cc b/ui/base/ime/dummy_text_input_client.cc index b6ac286..da3fc28 100644 --- a/ui/base/ime/dummy_text_input_client.cc +++ b/ui/base/ime/dummy_text_input_client.cc
@@ -146,9 +146,11 @@ } #if defined(OS_WIN) || defined(OS_CHROMEOS) -void DummyTextInputClient::SetCompositionFromExistingText( +bool DummyTextInputClient::SetCompositionFromExistingText( const gfx::Range& range, - const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {} + const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { + return false; +} #endif #if defined(OS_WIN)
diff --git a/ui/base/ime/dummy_text_input_client.h b/ui/base/ime/dummy_text_input_client.h index f97f4ca..0d9f5053 100644 --- a/ui/base/ime/dummy_text_input_client.h +++ b/ui/base/ime/dummy_text_input_client.h
@@ -57,7 +57,7 @@ bool ShouldDoLearning() override; #if defined(OS_WIN) || defined(OS_CHROMEOS) - void SetCompositionFromExistingText( + bool SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override; #endif
diff --git a/ui/base/ime/text_input_client.h b/ui/base/ime/text_input_client.h index cd01ff38..a1e54e1 100644 --- a/ui/base/ime/text_input_client.h +++ b/ui/base/ime/text_input_client.h
@@ -207,8 +207,8 @@ #if defined(OS_WIN) || defined(OS_CHROMEOS) // Start composition over a given UTF-16 code range from existing text. This // should only be used for composition scenario when IME wants to start - // composition on existing text. - virtual void SetCompositionFromExistingText( + // composition on existing text. Returns whether the operation was successful. + virtual bool SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) = 0; #endif
diff --git a/ui/base/ime/win/tsf_text_store_unittest.cc b/ui/base/ime/win/tsf_text_store_unittest.cc index 8ff63ee..9ca7ac2 100644 --- a/ui/base/ime/win/tsf_text_store_unittest.cc +++ b/ui/base/ime/win/tsf_text_store_unittest.cc
@@ -67,7 +67,7 @@ MOCK_METHOD1(SetTextEditCommandForNextKeyEvent, void(TextEditCommand)); MOCK_CONST_METHOD0(GetClientSourceForMetrics, ukm::SourceId()); MOCK_METHOD2(SetCompositionFromExistingText, - void(const gfx::Range&, const std::vector<ui::ImeTextSpan>&)); + bool(const gfx::Range&, const std::vector<ui::ImeTextSpan>&)); MOCK_METHOD3(SetActiveCompositionForAccessibility, void(const gfx::Range&, const base::string16&, bool)); };
diff --git a/ui/views/controls/button/label_button.cc b/ui/views/controls/button/label_button.cc index 25427f9..e558a17a 100644 --- a/ui/views/controls/button/label_button.cc +++ b/ui/views/controls/button/label_button.cc
@@ -22,7 +22,6 @@ #include "ui/views/animation/ink_drop.h" #include "ui/views/background.h" #include "ui/views/controls/button/label_button_border.h" -#include "ui/views/controls/button/label_button_label.h" #include "ui/views/layout/layout_provider.h" #include "ui/views/painter.h" #include "ui/views/style/platform_style.h" @@ -175,44 +174,60 @@ InvalidateLayout(); } +std::unique_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const { + if (style_ != Button::STYLE_TEXTBUTTON) + return std::make_unique<LabelButtonAssetBorder>(style_); + std::unique_ptr<LabelButtonBorder> border = + std::make_unique<LabelButtonBorder>(); + border->set_insets( + views::LabelButtonAssetBorder::GetDefaultInsetsForStyle(style_)); + return border; +} + +void LabelButton::SetBorder(std::unique_ptr<Border> border) { + border_is_themed_border_ = false; + View::SetBorder(std::move(border)); + ResetCachedPreferredSize(); +} + gfx::Size LabelButton::CalculatePreferredSize() const { - if (cached_preferred_size_valid_) - return cached_preferred_size_; + // Cache the computed size, as recomputing it is an expensive operation. + if (!cached_preferred_size_valid_) { + // Use a temporary label copy for sizing to avoid calculation side-effects. + Label label(GetText(), {label_->font_list()}); + label.SetLineHeight(label_->line_height()); + label.SetShadows(label_->shadows()); - // Use a temporary label copy for sizing to avoid calculation side-effects. - Label label(GetText(), {label_->font_list()}); - label.SetLineHeight(label_->line_height()); - label.SetShadows(label_->shadows()); + if (style_ == STYLE_BUTTON) { + // Some text appears wider when rendered normally than when rendered bold. + // Accommodate the widest, as buttons may show bold and shouldn't resize. + const int current_width = label.GetPreferredSize().width(); + label.SetFontList(cached_default_button_font_list_); + if (label.GetPreferredSize().width() < current_width) + label.SetFontList(label_->font_list()); + } - if (style_ == STYLE_BUTTON) { - // Some text appears wider when rendered normally than when rendered bold. - // Accommodate the widest, as buttons may show bold and shouldn't resize. - const int current_width = label.GetPreferredSize().width(); - label.SetFontList(cached_default_button_font_list_); - if (label.GetPreferredSize().width() < current_width) - label.SetFontList(label_->font_list()); + // Calculate the required size. + const gfx::Size preferred_label_size = label.GetPreferredSize(); + gfx::Size size = GetUnclampedSizeWithoutLabel(); + size.Enlarge(preferred_label_size.width(), 0); + + // Increase the height of the label (with insets) if larger. + size.set_height(std::max( + preferred_label_size.height() + GetInsets().height(), size.height())); + + size.SetToMax(min_size_); + + // Clamp size to max size (if valid). + if (max_size_.width() > 0) + size.set_width(std::min(max_size_.width(), size.width())); + if (max_size_.height() > 0) + size.set_height(std::min(max_size_.height(), size.height())); + + cached_preferred_size_valid_ = true; + cached_preferred_size_ = size; } - // Calculate the required size. - const gfx::Size preferred_label_size = label.GetPreferredSize(); - gfx::Size size = GetUnclampedSizeWithoutLabel(); - size.Enlarge(preferred_label_size.width(), 0); - - // Increase the height of the label (with insets) if larger. - size.set_height(std::max(preferred_label_size.height() + GetInsets().height(), - size.height())); - - size.SetToMax(min_size_); - - // Clamp size to max size (if valid). - if (max_size_.width() > 0) - size.set_width(std::min(max_size_.width(), size.width())); - if (max_size_.height() > 0) - size.set_height(std::min(max_size_.height(), size.height())); - - // Cache this computed size, as recomputing it is an expensive operation. - cached_preferred_size_valid_ = true; - cached_preferred_size_ = size; return cached_preferred_size_; } @@ -312,53 +327,6 @@ image_->EnableCanvasFlippingForRTLUI(flip); } -std::unique_ptr<LabelButtonBorder> LabelButton::CreateDefaultBorder() const { - if (style_ != Button::STYLE_TEXTBUTTON) - return std::make_unique<LabelButtonAssetBorder>(style_); - std::unique_ptr<LabelButtonBorder> border = - std::make_unique<LabelButtonBorder>(); - border->set_insets(views::LabelButtonAssetBorder::GetDefaultInsetsForStyle( - style_)); - return border; -} - -void LabelButton::SetBorder(std::unique_ptr<Border> border) { - border_is_themed_border_ = false; - View::SetBorder(std::move(border)); - ResetCachedPreferredSize(); -} - -Label* LabelButton::label() const { - return label_; -} - -gfx::Rect LabelButton::GetChildAreaBounds() { - return GetLocalBounds(); -} - -void LabelButton::OnFocus() { - Button::OnFocus(); - // Typically the border renders differently when focused. - SchedulePaint(); -} - -void LabelButton::OnBlur() { - Button::OnBlur(); - // Typically the border renders differently when focused. - SchedulePaint(); -} - -void LabelButton::OnThemeChanged() { - ResetColorsFromNativeTheme(); - UpdateThemedBorder(); - ResetLabelEnabledColor(); - // Invalidate the layout to pickup the new insets from the border. - InvalidateLayout(); - // The entire button has to be repainted here, since the native theme can - // define the tint for the entire background/border/focus ring. - SchedulePaint(); -} - void LabelButton::GetAccessibleNodeData(ui::AXNodeData* node_data) { if (is_default()) node_data->AddState(ax::mojom::State::kDefault); @@ -378,14 +346,64 @@ image()->DestroyLayer(); } -void LabelButton::StateChanged(ButtonState old_state) { - const gfx::Size previous_image_size(image_->GetPreferredSize()); - UpdateImage(); - ResetLabelEnabledColor(); - label_->SetEnabled(state() != STATE_DISABLED); - if (image_->GetPreferredSize() != previous_image_size) - InvalidateLayout(); - Button::StateChanged(old_state); +ui::NativeTheme::Part LabelButton::GetThemePart() const { + return ui::NativeTheme::kPushButton; +} + +gfx::Rect LabelButton::GetThemePaintRect() const { + return GetLocalBounds(); +} + +ui::NativeTheme::State LabelButton::GetThemeState( + ui::NativeTheme::ExtraParams* params) const { + GetExtraParams(params); + switch (state()) { + case STATE_NORMAL: + return ui::NativeTheme::kNormal; + case STATE_HOVERED: + return ui::NativeTheme::kHovered; + case STATE_PRESSED: + return ui::NativeTheme::kPressed; + case STATE_DISABLED: + return ui::NativeTheme::kDisabled; + case STATE_COUNT: + NOTREACHED() << "Unknown state: " << state(); + } + return ui::NativeTheme::kNormal; +} + +const gfx::Animation* LabelButton::GetThemeAnimation() const { + return &hover_animation(); +} + +ui::NativeTheme::State LabelButton::GetBackgroundThemeState( + ui::NativeTheme::ExtraParams* params) const { + GetExtraParams(params); + return ui::NativeTheme::kNormal; +} + +ui::NativeTheme::State LabelButton::GetForegroundThemeState( + ui::NativeTheme::ExtraParams* params) const { + GetExtraParams(params); + return ui::NativeTheme::kHovered; +} + +void LabelButton::UpdateImage() { + image_->SetImage(GetImage(GetVisualState())); + ResetCachedPreferredSize(); +} + +void LabelButton::UpdateThemedBorder() { + // Don't override borders set by others. + if (!border_is_themed_border_) + return; + + SetBorder(PlatformStyle::CreateThemedLabelButtonBorder(this)); + border_is_themed_border_ = true; +} + +gfx::Rect LabelButton::GetChildAreaBounds() { + return GetLocalBounds(); } void LabelButton::GetExtraParams(ui::NativeTheme::ExtraParams* params) const { @@ -457,65 +475,47 @@ ResetLabelEnabledColor(); } -void LabelButton::UpdateImage() { - image_->SetImage(GetImage(GetVisualState())); - ResetCachedPreferredSize(); -} - -void LabelButton::UpdateThemedBorder() { - // Don't override borders set by others. - if (!border_is_themed_border_) - return; - - SetBorder(PlatformStyle::CreateThemedLabelButtonBorder(this)); - border_is_themed_border_ = true; -} - -void LabelButton::SetTextInternal(const base::string16& text) { - SetAccessibleName(text); - label_->SetText(text); -} - void LabelButton::ChildPreferredSizeChanged(View* child) { ResetCachedPreferredSize(); PreferredSizeChanged(); } -ui::NativeTheme::Part LabelButton::GetThemePart() const { - return ui::NativeTheme::kPushButton; +void LabelButton::OnFocus() { + Button::OnFocus(); + // Typically the border renders differently when focused. + SchedulePaint(); } -gfx::Rect LabelButton::GetThemePaintRect() const { - return GetLocalBounds(); +void LabelButton::OnBlur() { + Button::OnBlur(); + // Typically the border renders differently when focused. + SchedulePaint(); } -ui::NativeTheme::State LabelButton::GetThemeState( - ui::NativeTheme::ExtraParams* params) const { - GetExtraParams(params); - switch (state()) { - case STATE_NORMAL: return ui::NativeTheme::kNormal; - case STATE_HOVERED: return ui::NativeTheme::kHovered; - case STATE_PRESSED: return ui::NativeTheme::kPressed; - case STATE_DISABLED: return ui::NativeTheme::kDisabled; - case STATE_COUNT: NOTREACHED() << "Unknown state: " << state(); - } - return ui::NativeTheme::kNormal; +void LabelButton::OnThemeChanged() { + ResetColorsFromNativeTheme(); + UpdateThemedBorder(); + ResetLabelEnabledColor(); + // Invalidate the layout to pickup the new insets from the border. + InvalidateLayout(); + // The entire button has to be repainted here, since the native theme can + // define the tint for the entire background/border/focus ring. + SchedulePaint(); } -const gfx::Animation* LabelButton::GetThemeAnimation() const { - return &hover_animation(); +void LabelButton::StateChanged(ButtonState old_state) { + const gfx::Size previous_image_size(image_->GetPreferredSize()); + UpdateImage(); + ResetLabelEnabledColor(); + label_->SetEnabled(state() != STATE_DISABLED); + if (image_->GetPreferredSize() != previous_image_size) + InvalidateLayout(); + Button::StateChanged(old_state); } -ui::NativeTheme::State LabelButton::GetBackgroundThemeState( - ui::NativeTheme::ExtraParams* params) const { - GetExtraParams(params); - return ui::NativeTheme::kNormal; -} - -ui::NativeTheme::State LabelButton::GetForegroundThemeState( - ui::NativeTheme::ExtraParams* params) const { - GetExtraParams(params); - return ui::NativeTheme::kHovered; +void LabelButton::SetTextInternal(const base::string16& text) { + SetAccessibleName(text); + label_->SetText(text); } void LabelButton::ResetCachedPreferredSize() {
diff --git a/ui/views/controls/button/label_button.h b/ui/views/controls/button/label_button.h index 4dc555db..82e9eb9 100644 --- a/ui/views/controls/button/label_button.h +++ b/ui/views/controls/button/label_button.h
@@ -14,6 +14,7 @@ #include "third_party/skia/include/core/SkColor.h" #include "ui/gfx/image/image_skia.h" #include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/label_button_label.h" #include "ui/views/controls/image_view.h" #include "ui/views/controls/label.h" #include "ui/views/native_theme_delegate.h" @@ -23,7 +24,6 @@ class InkDropContainerView; class LabelButtonBorder; -class LabelButtonLabel; // LabelButton is a button with text and an icon, it's not focusable by default. class VIEWS_EXPORT LabelButton : public Button, public NativeThemeDelegate { @@ -89,7 +89,7 @@ // subclasses. virtual std::unique_ptr<LabelButtonBorder> CreateDefaultBorder() const; - // View: + // Button: void SetBorder(std::unique_ptr<Border> border) override; gfx::Size CalculatePreferredSize() const override; int GetHeightForWidth(int w) const override; @@ -100,9 +100,20 @@ void AddLayerBeneathView(ui::Layer* new_layer) override; void RemoveLayerBeneathView(ui::Layer* old_layer) override; + // NativeThemeDelegate: + ui::NativeTheme::Part GetThemePart() const override; + gfx::Rect GetThemePaintRect() const override; + ui::NativeTheme::State GetThemeState( + ui::NativeTheme::ExtraParams* params) const override; + const gfx::Animation* GetThemeAnimation() const override; + ui::NativeTheme::State GetBackgroundThemeState( + ui::NativeTheme::ExtraParams* params) const override; + ui::NativeTheme::State GetForegroundThemeState( + ui::NativeTheme::ExtraParams* params) const override; + protected: ImageView* image() const { return image_; } - Label* label() const; + Label* label() const { return label_; } InkDropContainerView* ink_drop_container() const { return ink_drop_container_; } @@ -111,18 +122,24 @@ return explicitly_set_colors_[STATE_NORMAL]; } + const std::array<bool, STATE_COUNT>& explicitly_set_colors() const { + return explicitly_set_colors_; + } + void set_explicitly_set_colors(const std::array<bool, STATE_COUNT>& colors) { + explicitly_set_colors_ = colors; + } + + // Updates the image view to contain the appropriate button state image. + void UpdateImage(); + + // Updates the border as per the NativeTheme, unless a different border was + // set with SetBorder. + void UpdateThemedBorder(); + // Returns the available area for the label and image. Subclasses can change // these bounds if they need room to do manual painting. virtual gfx::Rect GetChildAreaBounds(); - // View: - void OnFocus() override; - void OnBlur() override; - void OnThemeChanged() override; - - // Button: - void StateChanged(ButtonState old_state) override; - // Fills |params| with information about the button. virtual void GetExtraParams(ui::NativeTheme::ExtraParams* params) const; @@ -133,39 +150,16 @@ // |is_default()|. virtual void UpdateStyleToIndicateDefaultStatus(); - // Updates the image view to contain the appropriate button state image. - void UpdateImage(); - - // Updates the border as per the NativeTheme, unless a different border was - // set with SetBorder. - void UpdateThemedBorder(); - - // NativeThemeDelegate: - gfx::Rect GetThemePaintRect() const override; - - const std::array<bool, STATE_COUNT>& explicitly_set_colors() const { - return explicitly_set_colors_; - } - void set_explicitly_set_colors(const std::array<bool, STATE_COUNT>& colors) { - explicitly_set_colors_ = colors; - } + // Button: + void ChildPreferredSizeChanged(View* child) override; + void OnFocus() override; + void OnBlur() override; + void OnThemeChanged() override; + void StateChanged(ButtonState old_state) override; private: void SetTextInternal(const base::string16& text); - // View: - void ChildPreferredSizeChanged(View* child) override; - - // NativeThemeDelegate: - ui::NativeTheme::Part GetThemePart() const override; - ui::NativeTheme::State GetThemeState( - ui::NativeTheme::ExtraParams* params) const override; - const gfx::Animation* GetThemeAnimation() const override; - ui::NativeTheme::State GetBackgroundThemeState( - ui::NativeTheme::ExtraParams* params) const override; - ui::NativeTheme::State GetForegroundThemeState( - ui::NativeTheme::ExtraParams* params) const override; - // Resets |cached_preferred_size_| and marks |cached_preferred_size_valid_| // as false. void ResetCachedPreferredSize();
diff --git a/ui/views/controls/prefix_selector.cc b/ui/views/controls/prefix_selector.cc index 05999a9a..b859d93 100644 --- a/ui/views/controls/prefix_selector.cc +++ b/ui/views/controls/prefix_selector.cc
@@ -169,9 +169,13 @@ } #if defined(OS_WIN) || defined(OS_CHROMEOS) -void PrefixSelector::SetCompositionFromExistingText( +bool PrefixSelector::SetCompositionFromExistingText( const gfx::Range& range, - const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {} + const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { + // TODO(https://crbug.com/952757): Implement this method. + NOTIMPLEMENTED_LOG_ONCE(); + return false; +} #endif #if defined(OS_WIN)
diff --git a/ui/views/controls/prefix_selector.h b/ui/views/controls/prefix_selector.h index ffa961a..84a9657 100644 --- a/ui/views/controls/prefix_selector.h +++ b/ui/views/controls/prefix_selector.h
@@ -77,7 +77,7 @@ bool ShouldDoLearning() override; #if defined(OS_WIN) || defined(OS_CHROMEOS) - void SetCompositionFromExistingText( + bool SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override; #endif
diff --git a/ui/views/controls/textfield/textfield.cc b/ui/views/controls/textfield/textfield.cc index ee2e06a..01fd1a54 100644 --- a/ui/views/controls/textfield/textfield.cc +++ b/ui/views/controls/textfield/textfield.cc
@@ -1752,9 +1752,12 @@ #if defined(OS_WIN) || defined(OS_CHROMEOS) // TODO(https://crbug.com/952355): Implement this method to support Korean IME reconversion feature // on native text fields (e.g. find bar). -void Textfield::SetCompositionFromExistingText( +bool Textfield::SetCompositionFromExistingText( const gfx::Range& range, - const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) {} + const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) { + NOTIMPLEMENTED_LOG_ONCE(); + return false; +} #endif #if defined(OS_WIN)
diff --git a/ui/views/controls/textfield/textfield.h b/ui/views/controls/textfield/textfield.h index 55a54d1a..0a88abf 100644 --- a/ui/views/controls/textfield/textfield.h +++ b/ui/views/controls/textfield/textfield.h
@@ -373,7 +373,7 @@ bool ShouldDoLearning() override; #if defined(OS_WIN) || defined(OS_CHROMEOS) - void SetCompositionFromExistingText( + bool SetCompositionFromExistingText( const gfx::Range& range, const std::vector<ui::ImeTextSpan>& ui_ime_text_spans) override; #endif
diff --git a/ui/webui/resources/polymer_resources.grdp b/ui/webui/resources/polymer_resources.grdp index a62b52d1..df840c4c 100644 --- a/ui/webui/resources/polymer_resources.grdp +++ b/ui/webui/resources/polymer_resources.grdp
@@ -428,14 +428,6 @@ file="../../../third_party/polymer/v1_0/components-chromium/paper-button/paper-button.html" type="chrome_html" compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_FAB_PAPER_FAB_EXTRACTED_JS" - file="../../../third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab-extracted.js" - type="chrome_html" - compress="gzip" /> - <structure name="IDR_POLYMER_1_0_PAPER_FAB_PAPER_FAB_HTML" - file="../../../third_party/polymer/v1_0/components-chromium/paper-fab/paper-fab.html" - type="chrome_html" - compress="gzip" /> <structure name="IDR_POLYMER_1_0_PAPER_ICON_BUTTON_PAPER_ICON_BUTTON_EXTRACTED_JS" file="../../../third_party/polymer/v1_0/components-chromium/paper-icon-button/paper-icon-button-extracted.js" type="chrome_html"